@keyring-dev/fastify
v0.1.1
Published
Fastify plugin for Keyring. Decorates request.keyring from an onRequest hook, before body parsing.
Readme
@keyring-dev/fastify
Fastify 5 plugin for Keyring. MIT.
import Fastify from 'fastify';
import { keyringPlugin } from '@keyring-dev/fastify';
const app = Fastify();
await app.register(keyringPlugin, {
resources: { orders: { live: liveOrders, test: testOrders } },
});
app.get('/v1/orders', async (request) => ({
tenant: request.keyring?.tenantId,
env: request.keyring?.env,
orders: request.keyring?.orders,
}));request.keyring is KeyringContext | null — decorateRequest puts the field
on every request, and the hook fills it only for a request it verified — so the
?. above is what the shipped type requires, not defensive style. A route
configured skip: true leaves it null, and so does a refused request.
This block is compiled as a TypeScript consumer would, against the published
dist/, and that check pins the property's exact type. @keyring-dev/express
spells req.keyring identically; it is one row of @keyring-dev/sdk's
cross-language contract table, not a per-adapter choice.
Here the promise is unconditional, and in Express it is not. decorateRequest
runs at request creation, so request.keyring is null before any hook — this
one included — has run, and an onRequest hook registered ahead of the plugin
still sees the property. Nothing decorates an Express request, so
@keyring-dev/express can only assign, and there the guarantee starts at the
middleware: a request that never reached it has no property at all. The type is
the same in both; the point at which it becomes true is not. Whichever adapter
you are porting, read the property with ?. rather than === null.
secretKey, projectId and baseUrl come from KEYRING_SECRET_KEY,
KEYRING_PROJECT_ID and KEYRING_BASE_URL; none of the three has a default.
Pass instance to share one Keyring across several plugin registrations.
Hooks, and why these ones
- Verification hooks
onRequest— deliberately before body parsing. Verification must not wait for a body, and an unauthenticated caller must not get the JSON parser to run on a 5 MB payload before anyone has looked at their key. The plugin's own test suite asserts the parser is never invoked on a denied request. - Idempotency will hook
preHandler— the opposite case, because it has to hash a body it therefore has to wait for. That is not in this package yet. onResponseandonRequestAbortemit the usage event, so a caller that hangs up mid-request still appears in the vendor's request log.
Wrapped in fastify-plugin, so request.keyring is visible to the routes you
register rather than to an encapsulated child context nobody can reach. Register
it before your own onRequest authentication if Keyring owns the route, after
it if your session does.
Everything the plugin does is in @keyring-dev/sdk; read its README.
