Keyring

Plain SDK

Any Node HTTP server, with the four SDK calls an adapter makes.

An adapter is a translation of four calls: handle decides, limit charges the counters, eventFor and record report. The server below is executed against the real @keyring/sdk by the docs' test suite, and it is a fair sketch of what every adapter does inside.

const keyring = new Keyring({
  resources: { orders: { live: liveOrders, test: testOrders } },
  routes: { 'GET /healthz': { skip: true } },
}).start();
async function serve(
  request: IncomingMessage,
  response: ServerResponse,
): Promise<void> {
  const startedAt = process.hrtime.bigint();
  const facts = {
    method: request.method ?? 'GET',
    path: request.url ?? '/',
    token: bearer(request),
  };
  const outcome = keyring.handle(facts);
  const record = (status: number, reason?: string | null) => {
    const event = keyring.eventFor(
      facts,
      outcome,
      status,
      Number(process.hrtime.bigint() - startedAt) / 1e6,
      reason,
    );
    if (event !== null) keyring.record(event);
  };

  if (outcome.decision.outcome === 'deny') {
    const { status, code, message } = outcome.decision;
    record(status);
    send(response, status, { error: { code, message } });
    return;
  }

  const limited = await keyring.limit(outcome);
  if (!limited.allowed) {
    const status = limited.status ?? 429;
    record(status, limited.reason);
    send(
      response,
      status,
      { error: { code: 'rate_limited', message: 'Too many requests.' } },
      limited.headers,
    );
    return;
  }

  const context = outcome.context;
  response.once('finish', () => record(response.statusCode));
  if (facts.path === '/healthz') {
    send(response, 200, { ok: true });
    return;
  }
  send(
    response,
    200,
    {
      tenant: context?.tenantId,
      env: context?.env,
      degraded: context?.degraded,
      orders: context?.orders,
    },
    limited.headers,
  );
}

The calls

CallWhat it does
handle(facts, override?)Synchronous. Parses the bearer token, looks the key up in the local policy set, applies the route rule and the onUnavailable mode, and answers deny with a status or allow with a context. No await anywhere.
limit(outcome)One round trip to the counter store for a verified key with limits; the answer carries the headers to set.
eventFor(facts, outcome, status, ms)Builds the usage event, or null on a skipped route.
record(event)Puts it in the ring buffer. The shipper does the rest.
runInRequest(context, fn)Runs fn inside the request's environment scope so currentEnv() works in code far from the request.
close()Flushes telemetry and the disk snapshot, stops the poller.

handle's second argument replaces the routes table's answer for this call, which is how @keyring/next and @keyring/nest carry a per-route rule without a path string.

What start() does

start() hydrates the policy store from the disk snapshot if one is recent, takes the first snapshot from the control plane, and begins polling every 5 seconds. It also installs SIGTERM and SIGINT handlers that call close() unless handleSignals: false. Every option, with its default, is on the KeyringOptions reference.

On this page