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

@nighthq/manifest

v0.2.0

Published

The substrate under a plugin seam: opaque versioned ids, declared parameter schemas, and one walker that gates values in both directions.

Readme

@nighthq/manifest

The substrate under a plugin seam: an opaque versioned id, a declared schema, and one walker that holds a value to it.

npm install @nighthq/manifest
import { parseManifestId, validateParams, type ParamSpec } from '@nighthq/manifest';

const params: Record<string, ParamSpec> = {
  hue: { kind: 'enum', values: ['shorter', 'longer'], optional: true },
  steps: { kind: 'number', min: 1, integer: true }
};

parseManifestId('ng.oklch/1'); // { name: 'ng.oklch', version: 1 }
parseManifestId('ng.oklch'); // throws — a manifest id carries its version

validateParams(params, { steps: 3, hue: 'shorter' }); // []
validateParams(params, { steps: 0, wobble: true });
// [ 'param "steps" is 0, below its minimum 1',
//   'param "wobble" is not declared by the schema' ]

That is the whole package: a name nobody parses meaning out of, a schema that says what may be supplied with it, and errors in both directions — a value that does not fit the schema, and a value the schema never declared.

Why it is its own package

Every plugin seam re-invents these three pieces, and re-inventing them is how two systems end up disagreeing about what "1" means. This is the version that @nighthq/icons runs on both sides of its own seam: the tier registry declares each tier's fields in this vocabulary, the operation registries (transition samplers, exporters) declare their parameters in it, and one walker gates every value at every application site.

It knows nothing about icons, and it imports nothing — not a framework, not the DOM, not a runtime dependency. Its own lib is ["ES2022"].

The vocabulary

| kind | declares | notable | | --------- | ----------------------- | ------------------------------------------------------ | | number | min, max, integer | bounds are inclusive | | string | nonEmpty, pattern | pattern is a RegExp | | boolean | — | | | enum | values | an empty values is a schema error, not a value error | | array | of, minItems | recursive | | record | of | open keys, one value shape | | object | fields | CLOSED — an undeclared key is an error | | tuple | items | fixed length, per-position shapes | | unknown | nothing | see below |

Every kind takes optional and a describe string.

unknown is a confession, not an escape hatch

A schema owns the SHAPE of a value and never its LAWS. Some fields are all law — a reference that must resolve, a closure that must hold, a literal that must match a token's default — and no shape check says anything true about them. Declaring such a field unknown records exactly that: this field is present, and its rules live in code elsewhere.

The alternative is worse than useless: a plausible-looking shape declaration that passes while the actual rule goes unchecked reads, to every reader and every gate, as though the field were verified.

Both directions, always

validateParamSpecs checks the SCHEMA (an enum with no values, an array with no element shape); validateValue and validateParams check a VALUE against it. The pair matters: checking only that supplied values fit misses the failure that actually happens — a manifest grows a parameter and a caller keeps passing the old set, or a caller passes a key the manifest never declared and it is silently ignored.

Both return string[] — empty is a pass. Nothing here throws except parseManifestId, which has nothing to return when an id is malformed.

Ids are opaque and versioned

name/version: lowercase dotted name, positive integer version, ng.lerp/1. The consumer of an id never parses meaning out of it — a registry is the only resolver, which is what lets a third party register acme.thing/2 without the host package changing, and what makes an unregistered id a refusal rather than a fallback.