/** * Fastify Framework Adapter * * Adapts NAuth to work with Fastify with proper AsyncLocalStorage support. * * **Context Management:** * - First hook (clientInfo) initializes AsyncLocalStorage context * - Context is stored on request object for subsequent hooks * - Each hook restores context using ContextStorage.enterStore() * - Route handlers MUST use wrapRouteHandler() for context access * * **Why Context Restoration is Needed:** * Unlike Express where middleware runs in a continuous call stack, * Fastify hooks run independently. Each hook invocation loses the * AsyncLocalStorage context, so we store it on the request and restore it. */ import { NAuthAdapter, NAuthMiddlewareHandler, NAuthResponseInterceptorHandler, NAuthRouteHandler, MiddlewareOptions, RawHttpHandler, RawMountPredicate } from '../platform/interfaces'; /** * Fastify Adapter Implementation * * Provides NAuth integration for Fastify applications. */ export declare class FastifyAdapter implements NAuthAdapter { readonly name = "FastifyAdapter"; /** * Claim raw HTTP for matching paths. * * Registered as an `onRequest` hook, which is the earliest point Fastify offers and, * unlike Express, runs *before* body parsing — so a protocol handler receives an * unconsumed stream and keeps its own request size limit. * * Two Fastify specifics this relies on: * * - The hook must be added at **root scope**. Fastify encapsulates hooks registered * inside a plugin, where they fire only for routes in that plugin — which silently * misses paths that match no route at all, such as `/.well-known/*`. * - `reply.hijack()` detaches Fastify's own serialisation and 404 handling, after * which the handler owns the socket. Nothing further may be sent through `reply`. * * @param app - The root Fastify instance * @param predicate - Receives the query-stripped path; return true to claim the request * @param handler - Owns the raw Node objects and must end the response * @throws {Error} When `app` has no `addHook()` method */ mountRaw(app: unknown, predicate: RawMountPredicate, handler: RawHttpHandler): void; /** * Register a middleware handler as Fastify hook * * Handles context initialization for first hook and restoration for subsequent hooks. */ registerMiddleware(name: string, handler: NAuthMiddlewareHandler, options?: MiddlewareOptions): FastifyHook; /** * Execute handler with proper async flow control */ private executeHandler; /** * Register a response interceptor using Fastify onSend hook * * The onSend hook receives the serialized payload before sending. */ registerResponseInterceptor(handler: NAuthResponseInterceptorHandler): FastifyOnSendHook; /** * Wrap a route handler to ensure context is available * * For Fastify, this is REQUIRED for route handlers to access ContextStorage. */ wrapRouteHandler(handler: NAuthRouteHandler): FastifyRouteHandler; /** * Ensure attribute storage exists on request */ private ensureAttributes; } interface FastifyRequest { method: string; url: string; body: unknown; query: unknown; params: unknown; headers: Record; ip: string; } interface FastifyReply { code(statusCode: number): this; header(name: string, value: string | string[]): this; send(payload?: unknown): this; redirect(url: string): this; redirect(statusCode: number, url: string): this; getHeader(name: string): string | undefined; sent: boolean; } type FastifyHook = (request: FastifyRequest, reply: FastifyReply) => Promise; type FastifyOnSendHook = (request: FastifyRequest, reply: FastifyReply, payload: unknown) => Promise; type FastifyRouteHandler = (request: FastifyRequest, reply: FastifyReply) => Promise; /** * Fastify preHandler hook type for use with route registration. * * The counterpart to `ExpressMiddlewareType`. Consumer apps should type * `nauth.middleware.*` and `nauth.helpers.*` with this rather than redeclaring it: * * ```typescript * const nauth: NAuthInstance = await NAuth.create(...); * fastify.post('/auth/login', { preHandler: [nauth.helpers.public()] }, handler); * ``` * * Deliberately expressed in terms of `unknown` so consumers are not coupled to this * package's internal Fastify shims, and so it stays assignable to Fastify's own * `preHandlerHookHandler` without importing Fastify here. */ export type FastifyMiddlewareType = (request: unknown, reply: unknown) => Promise; export {}; //# sourceMappingURL=fastify.adapter.d.ts.map