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
| Call | What 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.