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

@haneinfo/definition-registry

v0.2.9

Published

Stores, validates and publishes mechanism definitions (kind + schemaVersion + metadata + spec), with generic MCP design tools and repo definition sync.

Readme

@haneinfo/definition-registry

Stores, validates and publishes mechanism definitions (kind + schemaVersion + metadata + spec) for every generic mechanism, with generic MCP design tools and a boot-time sync of backend/definitions/**. Agents: read agent-guide.md.

Install

  1. Add the plugin to haneinfo.plugins.json and run haneinfo build:

    { "plugin": "@haneinfo/definition-registry", "instanceId": "default", "enabled": true, "configRef": "definitionRegistry" }
  2. Register it in the App's plugin list (definitionRegistry() from @haneinfo/definition-registry/plugin) and add its Prisma fragment through haneinfo build; create a migration for Definition, DefinitionVersion and DefinitionWriteReceipt.

  3. Optional config at definitionRegistry:

    | Key | Default | Meaning | | --- | --- | --- | | scopeNamespace | MCP_TOOL_PREFIX | MCP scopes <ns>:definition:read\|write | | appName | the namespace | appName on audit records | | definitionsDir | <cwd>/definitions | Repo definitions directory | | syncRepoDefinitionsOnBoot | true | Publish new/changed repo definitions on bootstrap | | diffMaxChanges | 5000 | Changes one definition diff returns (1–50,000) | | diffValueMaxChars | 2000 | Characters of one displayed diff value (1–100,000) |

  4. Register the MCP tools into the registry the App exposes: definitionMcpTools.registerInto(registry).

  5. Add one test so pnpm verify runs the semantic checks:

    import { verifyRepoDefinitions } from '@haneinfo/definition-registry/testing';
    expect(verifyRepoDefinitions(path.join(__dirname, '../definitions'), kinds)).toEqual([]);

HTTP API (people only)

InteractiveAuthGuard; machine credentials are refused.

| Route | Purpose | | --- | --- | | POST /definitions { definition } | Create a runtime draft, or start a draft of a published runtime definition; 201 with DraftWriteResult | | PATCH /definitions/:kind/:code/draft { expectedVersion, operations } | Apply 1–200 RFC 6902 operations using revision CAS; 200 with DraftWriteResult | | POST /definitions/validate { definition } or { kind, code } | Validate unsaved content or the stored draft (published content if no draft); 200 with { valid, diagnostics }, without saving | | GET /definitions/kinds | Installed kinds | | GET /definitions?kind=&source= | Definitions the user may read: { definitions, truncated }, at most 1,000 in (kind, code) order | | GET /definitions/:kind/:code | Draft and latest published version, for review and diff | | GET /definitions/:kind/:code/diff?from=&to= | Difference between two published versions or a version and draft | | POST /definitions/publish { refs: [{ kind, code, expectedVersion? }] } | Publish drafts together; expectedVersion is the revision the person reviewed, and a draft changed since is refused with VERSION_CONFLICT | | POST /definitions/:kind/:code/discard-draft { expectedVersion } | Drop a draft |

Draft writes require <kind>:definition:write; validation requires <kind>:definition:read. DraftWriteResult contains { kind, code, revision, created, valid, diagnostics }. Invalid specs are saved as drafts with valid: false and diagnostics; the envelope, installed kind and schema version must still be accepted. HTTP results and diagnostic messages are plain values, without $userContent. Human writes and draft attribution use isAiOperation: false.

HTTP writes do not use MCP requestId receipts. A repeated create returns DRAFT_EXISTS (409) with details.revision; a stale patch returns VERSION_CONFLICT (409) with details.currentRevision. Read the definition again before retrying. Existing errors retain their statuses: FORBIDDEN 403, DEFINITION_NOT_FOUND 404, REPO_DEFINITION_READ_ONLY 409, INVALID_PATCH / IMMUTABLE_FIELD 422, UNKNOWN_KIND / Zod INVALID_INPUT 400. REPO definitions remain read-only and kind / metadata.code cannot change. Input schemas and limits are shared with the corresponding MCP tools.

The registry imposes no definition size limit. Configure the host's JSON body limit for its own kinds (Express defaults to 100kb); editor autosaves must fit that limit. Validation never changes the stored revision. After editing, review the latest draft and send its revision as expectedVersion when publishing.

Review UI

@haneinfo/definition-registry/frontend ships presentational components for the admin page the manifest declares (/dashboard/definitions, i18n namespace definitionRegistry):

  • DefinitionsTable — rows from GET /definitions; agent-made drafts are flagged.
  • DefinitionReview — draft next to the latest published version, the changed JSON Pointer paths, and publish / discard buttons. The App passes server actions that call the HTTP API above; publishAction(kind, code, expectedVersion) receives the revision on screen and must send it, so an agent edit made after the review cannot be published unseen. A blocked publish returns diagnostics to display: behind @haneinfo/common's GlobalExceptionFilter the response carries details.definitions (each blocked definition's { kind, code, reason } with the code and path of every diagnostic, no messages); map them to { ref: { kind, code }, code, path }.

DefinitionReview titles its sections with h3, so the host page supplies the h1 and an h2 (for example the definition name) above it. Its bounded JSON blocks are labelled, keyboard-focusable regions so keyboard users can scroll them.

For mechanism packages

Inject DEFINITION_REGISTRY (DefinitionRegistryPort from @haneinfo/plugin-api), call registerKind() in onModuleInit, and read published definitions with getPublished(), getPublishedVersion() and resolveBundle() (pin the bundle when an instance starts; it re-reads until two passes agree, so it never mixes versions published together, and fails with VERSION_CONFLICT after five passes while the set keeps being published). Registry failures are DefinitionRegistryError, a MechanismError subclass, so a mechanism's own error mapping turns them into their HTTP status (DEFINITION_NOT_FOUND is 404). Declare requires: ["haneinfo.definition-registry"] in the manifest. Test with createTestDefinitionRegistry() and checkDefinitionKindContract() from ./testing.

Draft data preparation (202610-8b3e)

Draft implementation; the decision remains draft. Contract 1.18.0 adds optional PrepareDataOptions (requireRequired?: boolean) to DefinitionKindRegistration.prepareData and DefinitionRegistryPort.prepareData. Omission retains full validation. StateMachineInstanceView optionally exposes fieldRevisions with removed-field tombstones; older providers can omit it. No new capability, MCP write tool or runtime port method is added. MechanismError.toJSON retains details.currentRevision, bounded conflicts and retryAfterSeconds without a new error envelope. Upgrade the registry forwarder and Form consumer together with state-machine; their manifests require 1.18.0.

Definition version diff (draft 202610-d9a5)

Draft implementation; the decision remains draft. GET /definitions/:kind/:code/diff?from=&to= compares two sides of one definition: from and to are published version numbers (DefinitionVersion.content) or draft (the current draft). Both are required; nothing else is accepted in the query. The response is { from, to, summary, changes, truncated } in the @haneinfo/diff format.

  • Same read rule as GET /definitions/:kind/:code: <kind>:definition:read (or ADMIN / ALLOW_ALL / READ_ALL) is checked before anything is loaded, so a refused caller gets FORBIDDEN and learns nothing about the content. REPO definitions compare like runtime ones.
  • DEFINITION_NOT_FOUND (404) for an unknown code, DEFINITION_VERSION_NOT_FOUND (404, details.version) for a missing version or a missing draft, DIFF_INPUT_TOO_LARGE / DIFF_TOO_DEEP (422) when a side exceeds 1 MB or 32 levels.
  • Key rules (DEFINITION_DIFF_KEYS): Form fields, layout children and subform columns pair by stable id, falling back to key ([id=...] segments); StateMachine states and transitions by key, falling back to code or name. Other kinds use the library defaults (id, key, code, name, else position).
  • diffMaxChanges and diffValueMaxChars bound the output; there are no secrets.
  • MCP: get_definition_diff (<ns>:definition:read, user-bound) returns the same result with every string in changes (path segments and values) wrapped as $userContent. It changes nothing; there is still no revert.