npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ynode/versionify

v1.5.2

Published

Fastify 5 plugin that exposes application name and version via a RESTful endpoint with content negotiation, cache control, and structured metadata.

Readme

@ynode/versionify

Copyright (c) 2026 Michael Welter [email protected]

npm version License: MIT

A simple and lightweight Fastify plugin to expose your application's name and version from package.json.

It automatically handles content negotiation to respond with JSON, HTML, or plain text based on the client's Accept header. Version responses include weak ETags by default and honor If-None-Match with 304 Not Modified.

Supported media ranges include exact types and standard wildcards: application/json and application/* return JSON, text/html returns HTML, text/plain returns plain text, text/* returns the first supported text response, and */* falls back to JSON.

For each representation, the most-specific matching media range determines its quality. An explicit q=0 exclusion therefore takes precedence over a broader wildcard.

Fastify automatically exposes a matching HEAD endpoint for the plugin's GET route. It returns the negotiated status and headers without a response body.

Node.js support

This package requires Node.js 20.19.0 or newer. CI exercises the exact 20.19.0, 22.13.0, and 24.0.0 boundaries. Node.js 20 remains tested only to preserve the current major-version contract even though upstream support has ended; use Node.js 22 or 24 for supported production deployments. A newly released Node.js major is not considered supported until it is added to CI, even when the open engines range admits it.

Installation

Install the package and its required peer dependency, fastify.

npm install @ynode/versionify fastify

Options

You can pass an options object as the second argument to register.

| Option | Type | Default | Description | | :-- | :-- | :-- | :-- | | prefix | string | undefined | Optional Fastify route prefix beginning with /. | | path | string | "/version" | The URL path to expose the version endpoint. Must begin with /. | | pkg | object | undefined | A package.json object. If not provided, the plugin will automatically load package.json from your project root. | | rootDir | string | process.cwd() | Directory whose package.json is loaded when pkg is not provided. | | cacheMaxAge | number | 3600 | Cache-Control max-age in seconds. Set to 0 to disable. | | metadata | object | undefined | Additional static key-value pairs included in the JSON response. Keys name, version, and build are reserved and will be ignored; build metadata belongs in the dedicated build option. | | build | object | undefined | Additional build metadata nested under build in the JSON response. Valid Dates become ISO strings, invalid Dates become null, and BigInts become strings. | | etag | boolean | true | Emit weak ETags and honor If-None-Match conditional requests. | | requireIdentity | boolean | false | Reject registration unless the resolved package name and version are non-empty strings. | | routeOptions | object | undefined | Allowlisted Fastify schema, config, logLevel, onRequest, preValidation, and preHandler settings for the version route. |

Basic Usage

import versionify from "@ynode/versionify";

// Register the plugin with default options
await fastify.register(versionify, { prefix: "/~" });

Example with Options

import versionify from "@ynode/versionify";

// Register with a custom path
await fastify.register(versionify, {
    path: "/info",
});

Now the endpoint will be available at http://localhost:3000/info.

For deployments where fallback identity would hide a packaging error, enable strict identity validation:

await fastify.register(versionify, {
    requireIdentity: true,
});

With requireIdentity: true, package loading or JSON parsing failures reject registration with ERR_VERSIONIFY_IDENTITY_LOAD, and missing, empty, or whitespace-only name or version values are rejected. The default remains compatible: an unreadable project package falls back to unknown and 0.0.0.

Route-level authentication and documentation can be attached without wrapping the plugin:

await fastify.register(versionify, {
    routeOptions: {
        schema: {
            tags: ["operations"],
            summary: "Application version",
        },
        config: { permission: "version:read" },
        logLevel: "warn",
        onRequest: async (request, reply) => {
            if (!request.user?.permissions.includes("version:read")) {
                await reply.code(403).send({ error: "Forbidden" });
            }
        },
    },
});

The route surface is explicitly limited to schema, config, logLevel, onRequest, preValidation, and preHandler; each hook accepts one function or an array of functions. Unknown options fail registration. method, url, and handler are reserved so the plugin always owns its GET/automatic HEAD contract, negotiated response, and endpoint path.

Example with Metadata and Cache Control

import process from "node:process";
import versionify from "@ynode/versionify";

await fastify.register(versionify, {
    metadata: { environment: "production", nodeVersion: process.version },
    build: { commit: process.env.GIT_SHA, time: process.env.BUILD_TIME },
    cacheMaxAge: 7200,
});

The JSON response will include all metadata fields alongside name and version:

{
    "name": "my-app",
    "version": "2.1.0",
    "environment": "production",
    "nodeVersion": "v22.0.0",
    "build": {
        "commit": "abc123",
        "time": "2026-07-21T12:34:56.000Z"
    }
}

Clients can reuse the response ETag in If-None-Match; when the version payload has not changed, the endpoint returns 304 Not Modified.

License

This project is licensed under the MIT License.