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

@12-apps/wiring

v1.17.0

Published

The package-to-host wiring contract: a producer half for packages (capability manifests — HTTP routes, job blueprints, MCP tools with annotations, permissions, notification blueprints, mailers, Prisma partials, web surfaces) and a consumer half for hosts

Readme

@12-apps/wiring

The package-to-host wiring contract. A producer half for packages — declare what you provide and what you require, per capability — and a consumer half for hosts — adopt the declarations, bind each one against shared ports, and get one ordered, conflict-checked, reported aggregate back.

Zero dependencies. Every capability shape is a structural twin of a seam a package in this repo already ships, so adopting the contract is declaring what already exists, not rewriting it.

The problem

Every @12-apps/* package already follows the same implicit plugin shape — createApi*(config) → { routes }, createWeb*(config) → { page, … }, a ./hono adapter, a Prisma partial, sometimes ./mcp or job blueprints. But the shape lives in TypeScript conventions and per-package ADOPTING.md files, so:

  • every host rediscovers each package's contract by reading it;
  • the origin host wires ~24 packages through hand-written surface files, route files, nav files, icon files, badge files and policy tables;
  • shapes that must stay identical across packages (JobBlueprint vs PaymentsJobBlueprint) are kept identical by convention, with no compile check anywhere;
  • a version bump that adds a capability arrives silently: report-builder 5.x shipped three working-copy endpoints its own client calls, and the origin host never mounted them — the editor's autosave 404s and nothing is red;
  • packages that should notify or mail cannot say so: there is no notify port at all, and the only email port lives inside another package's server entry.

The model

        PRODUCER (the package)                CONSUMER (the host)
  ┌──────────────────────────────┐      ┌────────────────────────────────┐
  │ <pkg>/manifest               │      │ createWiringHost({name, kind,  │
  │   defineManifest({           │      │                   ports})      │
  │     name, contract: 1,       │      │                                │
  │     permissions, mcp,        │──────▶ .adoptServer({manifest,        │
  │     notifications, db, e2e,  │      │    server, bindings})          │
  │     server: ['http','jobs'], │      │ .adoptWeb({manifest, web,      │
  │     web: ['surface','areas'] │      │    bindings})                  │
  │   })                         │      │                                │
  │ <pkg>/manifest/server        │      │ .assemble() ──▶ routes, jobs,  │
  │   defineServerManifest(...)  │      │    mailers, surfaces,          │
  │ <pkg>/manifest/web           │      │    permissions, notifications, │
  │   defineWebManifest(...)     │      │    mcpEndpoints, db, areas,    │
  └──────────────────────────────┘      │    report                      │
                                        └────────────────────────────────┘

Separate manifests per runtime because bundles are physics: the shared manifest is data every runtime can hold; the server manifest carries the createApi* factory and job blueprints; the web manifest carries the createWeb* factory; a package with React Native screens adds a native manifest (see React Native hosts). The shared manifest inventories the runtime manifests, and that inventory is the integrity mechanism: the producer refuses a runtime manifest that drifts from it, and a host that adopts a manifest without answering an inventoried capability gets a red assemble() naming the package and the capability.

Every declared capability must be bound or declined with a written reason. Declining is legitimate — a harness with no worker declines jobs — but silence is not: assemble() throws while anything is unanswered. That is what turns "the bump shipped a capability the host never wired" from a silent 404 into a build failure.

Capabilities

| kind | producer declares | consumer binds with | aggregate | |---|---|---|---| | http | create(config) → { routes } — the existing createApi* factory | { mountPath, config } | routes, specificity-ordered, conflict-checked | | jobs | namespace + dep-free blueprints (twin of @12-apps/jobs' JobBlueprint) | { deps } | jobs — JobDefinition twins; jobs.map(defineJob) and done | | email | createMailer(port) → mailer (the createAuthMailer pattern) | { port? } (defaults to the host port) | mailers[pkg] | | mcp | WireMcpTool[] — McpEndpoint plus annotations | collected; host-built vocabulary tools join via mcpEndpoints | mcpEndpoints, uniqueness-checked | | permissions | an rbac-shaped contribution (source, ids, permissions, labels) | collected | permissions — feed composePermissions | | notifications | blueprints: type, suggested category, generate | collected | notifications — feed the notifications mount | | db | the Prisma partial + migrations paths | collected | db — feed the sync tooling | | surface | create(config) → surface — the existing createWeb* factory | { config } | surfaces[pkg], built once (the memoisation rule, held in one place) | | surface (native) | the same create(config) → surface, returning React Native component types, in <pkg>/manifest/native | { config } on a native host | surfaces[pkg], built once | | areas | route/nav/gate suggestions per host area | collected | areas — project nav from data | | e2e | the journeys' entry subpath | collected | in the report |

React Native hosts

A React Native app is a third host kind. A package that ships screens for one adds a fourth manifest, <pkg>/manifest/native, declared with defineNativeManifest and inventoried as native: ["surface"] in the shared manifest. Its surface has the web surface's shape — one config object in, component types out — but returns React Native components, because a native bundle can import neither react-dom nor a web component library, and a web bundle must never import React Native.

// package: <pkg>/manifest/native — a plain value; wiring stays a type-only edge
import type { AnyNativeManifest } from "@12-apps/wiring";
export const threadsNativeManifest = {
  name: "@12-apps/threads",
  surface: { create: createNativeThreads },
} as const satisfies AnyNativeManifest;

// package: its own test suite runs the producer's assertions
expect(defineNativeManifest(threadsManifest, threadsNativeManifest)).toBe(threadsNativeManifest);

// host: the React Native app
const host = createWiringHost({ name: "field-app", kind: "native", ports: { loggerFor } });
const { surface } = host.adoptNative({
  manifest: threadsManifest,
  native: threadsNativeManifest,
  bindings: { surface: { config: { fetch, copy } } },
});
host.assemble();

surface is ONE capability with two possible runtimes, so the vocabulary every package answers for does not grow: the conformance gate checks only that a native: inventory has its ./manifest/native subpath, and that the subpath does not outlive the inventory (assertExportsMirror checks the same in the package's own suite). A native host has no areas (its navigation is its own; a native manifest carrying areas is refused), reports the server and web halves out-of-scope with the runtime named on each entry, and answers env vars declared with scope: "native". Like a web host, it still collects the shared data capabilities (permissions, notifications, MCP, db) into its aggregate; it simply has nothing to feed them to.

Ports (@12-apps/wiring/ports)

What a host provides once, for every package to require: EmailPort (the EmailDriver shape, verbatim), NotifyPort (new — emit a typed notification event; never throws), LoggerPort, JobsEnqueuePort (never throws), ClockPort. Memory reference implementations ship for tests.

What stays host-owned

The contract deliberately moves no decision that is host vocabulary today: every user-facing sentence (pt-BR copy arrives as config, exactly as report-builder 4.0 inverted it), guards and actor resolution, plan gates, nav placement/labels/icons, MCP operation ids and summaries for vocabulary-driven tools, the RBAC catalog assembly, and the database itself. The contract makes each of those a named, typed, refusable argument instead of a convention.

Example

See src/__tests__/fixture-package.ts for a complete producer, and src/__tests__/consumer.test.ts for both host kinds. The short version:

// host (API server)
import { createWiringHost } from "@12-apps/wiring/consumer";
import { defineJob } from "@12-apps/jobs";

const host = createWiringHost({ name: "web", kind: "server", ports: { email } });
host.adoptServer({
  manifest: notesManifest,
  server: notesServerManifest,
  bindings: {
    http: { mountPath: "/api/admin/:tenantSlug", config: { store } },
    jobs: { deps: { store, ran } },
    email: {},
  },
});
const wired = host.assemble();          // throws while anything is unanswered
wired.jobs.map((job) => defineJob(job)); // every adopted package's jobs, one line
console.log(renderWiringReport(wired.report));

Hosts that must keep one route file per endpoint (coverage gates read guards out of route files) still adopt: they mount by hand and pin unclaimedRoutes(wired.routes, claimedKeys) to [] in a unit test, which is the test that would have caught the working-copy 404.

Status

Released: the package is in release-packages.txt (first — it has no dependencies) and @12-apps/report-builder is the first producer, adopted by the consumer harness. The RFC and the per-package adaptation report live in docs/wiring/.