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

@rubriclab/rubrot-api

v0.2.1

Published

The fleet's API contract layer: structured errors, zod request parsing, pagination, and fail-closed authenticated route wrappers

Readme

@rubriclab/rubrot-api

The fleet's API contract layer, folded together from the metal /api/v1 _lib (structured errors, zod parsing, pagination — its error shape is THE standard) and vault's api-handler (fail-closed authenticated wrappers, generalized to an injected authenticator). Ships as TypeScript source; peer dep is zod only. No framework imports — handlers take a plain Request, so Next 16 route files export them directly.

The contract

Every failure body is { error: { code, message } } with a stable ApiErrorCode (AUTH_MISSING, AUTH_INVALID, SCOPE_MISSING, BAD_REQUEST, INVALID_JSON, NOT_FOUND, UPSTREAM_CONTRACT, UPSTREAM_ERROR, INTERNAL). Every response built here — success or failure — carries cache-control: no-store.

jsonError(code, message, status)       structured failure, explicit code (the primitive)
apiError(message, status, code?)       structured failure, code defaulted by status
codeForStatus(status)                  the default status → ApiErrorCode map
apiJson(data, status?)                 non-cached JSON success
apiText(body, status?)                 non-cached text/plain (dotenv projections)
parseRequestJson(request, contract)    JSON + zod in one step → data | ready 400
zodMessage(error)                      first issue, offending field named
parsePagination(request)               ?limit=&offset= via strict contract → data | ready 400
pageItems / pageLimitOnlyItems         { items, pagination } envelope (exact / count-free total)
limitForOffset(query)                  SQL LIMIT with the next-page sentinel row

Status → code

codeForStatus(status) is the one default map — the glue vault (codeForStatus) and rubrot (authErrorCode) each hand-rolled, reconciled:

| status | code | | ------ | --------------- | | 400 | BAD_REQUEST | | 401 | AUTH_INVALID | | 403 | SCOPE_MISSING | | 404 | NOT_FOUND | | else | INTERNAL |

apiError(message, status, code?) builds a failure from a status alone (code defaults via codeForStatus) or takes an explicit code to override — it is vault's apiError and rubrot's caughtApiError folded into one, with jsonError as the explicit-code primitive underneath.

AUTH_MISSING is never produced by the default map — a 401 defaults to AUTH_INVALID (a presented credential was bad). "No credential at all" is a distinction only the caller can draw, so it is consumer-emitted: pass code: "AUTH_MISSING" (on an AuthFailure, or straight to apiError) where the app decides a request carried no credentials. INTERNAL is the fail-closed floor for any unmapped status.

Authenticated routes

withAuth(authenticate, handler) collapses what every route must get right — the auth gate, no-store, and fail-closed errors (a thrown handler logs and returns a clean structured 500, never a leak) — into one place. The authenticator is injected: header in, { ok, identity } | { ok: false, status, error, code? } out. On failure the wrapper builds the response via apiError — a set code wins, otherwise it defaults through codeForStatus (see the table above).

// lib/api.ts — bind once per app
import { createApiAuth } from "@rubriclab/rubrot-api";
export const api = createApiAuth({
  read: (authorization) => authenticateBearer(/* app's engine */),
  write: (authorization) => authenticateBearer(/* required: "write"/"operate" */),
});

// app/api/v1/machines/[id]/route.ts
export const GET = api.withRead<{ id: string }>(async (request, identity, ctx) => {
  const { id } = await ctx.params;
  return apiJson(await getMachine(id));
});

What "read" vs "write" means (ranked floor, orthogonal capability) is the authenticator's business — pair with @rubriclab/rubrot-tokens.