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

@wtfalch/contracts

v0.1.0

Published

The shared wire contract for the estate's -service packages: one ServiceError code set, the code-to-HTTP-status map, the error JSON body, one SDK error class, and the shared header names. Pure TypeScript, no runtime dependencies.

Readme

@wtfalch/contracts

The shared wire contract for every estate -service package: one error type, one error envelope on the wire, and the request conventions every service follows. Pure TypeScript, no runtime dependencies.

Install

pnpm add @wtfalch/contracts

The closed code set

import { SERVICE_ERROR_CODES, STATUS_BY_CODE, isServiceErrorCode } from '@wtfalch/contracts';

SERVICE_ERROR_CODES is the nine codes a service may answer, in the HTTP status STATUS_BY_CODE maps each one to:

| code | status | |---|---| | invalid_request | 400 | | unauthorized | 401 | | forbidden | 403 | | not_found | 404 | | conflict | 409 | | over_budget | 402 | | not_configured | 503 | | rate_limited | 429 | | unavailable | 503 |

unauthorized is in the set deliberately: it is a no-credential 401, distinct from a rejected-credential forbidden 403. isServiceErrorCode narrows an unknown wire value (e.g. a service's raw JSON body) to this set.

Service side: throw a ServiceError

import { ServiceError, serviceErrorResponse } from '@wtfalch/contracts';

export async function handler(request: Request): Promise<Response> {
  try {
    if (!hasAccess) throw new ServiceError('forbidden', 'Access denied');
    return Response.json(await doWork());
  } catch (error) {
    if (error instanceof ServiceError) return serviceErrorResponse(error);
    throw error; // the host's own 500 path decides what an unexpected error looks like
  }
}

ServiceError's third constructor argument, retryAfterSeconds, only means anything for rate_limited -- serviceErrorResponse sends it as the Retry-After header and omits the header for every other code.

serviceErrorResponse builds the whole failure Response (status, the { error: { code, message } } body, and Retry-After when applicable) using the global Fetch API, so it works unmodified in a Cloudflare Worker or a Next.js route handler. If you only need the body -- for example inside a framework that builds its own Response -- serviceErrorBody returns just that { error: { code, message } } object.

Client side: catch a ServiceApiError

import { ServiceApiError, serviceApiErrorFrom } from '@wtfalch/contracts';

const response = await fetch(url, init);
if (!response.ok) {
  throw serviceApiErrorFrom(response.status, await response.json(), response.headers.get('retry-after'));
}
try {
  await callService();
} catch (error) {
  if (error instanceof ServiceApiError && error.code === 'rate_limited') {
    await sleep((error.retryAfterSeconds ?? 1) * 1000);
  }
}

error.code is the closed ServiceErrorCode union, not a bare string, so a caller can narrow on it directly instead of re-deriving a coarser table from error.status. A code the wire sends that this package does not recognise -- an unmigrated service's own vocabulary -- becomes unavailable, never a made-up string outside the closed set.

serviceApiErrorFrom is the one place that parsing happens: build a ServiceApiError yourself only if your transport already has its own error.code/error.message extraction to keep.

Shared headers

import { ORGANISATION_HEADER, RETRY_AFTER_HEADER } from '@wtfalch/contracts';

ORGANISATION_HEADER (x-organisation-id) is the org a caller is acting as, verified by the service against the caller's credential. RETRY_AFTER_HEADER (retry-after) is what serviceErrorResponse sets for rate_limited.

Idempotency keys are not a header in this estate: every service that has one takes it as a request-body field (idempotencyKey), enforced by a database unique constraint, so this package does not name a header for it.

Out of scope

A service's own request and response schemas stay in that service's own SDK. This package is the failure shape and the codes, not the success shape.

Each consumer's own divergent codes -- integrations' connection_unavailable and idempotency_conflict, activity's separate vocabulary with no retryAfterSeconds -- are that consumer's own migration onto this set, not something this package adapts for them.