import { FastifyRequest, FastifyReply } from 'fastify'; import { C as ConcurrencyGuard, j as UnifiedAdmitter, k as UnifiedAxis } from './unified-BouIz5EX.js'; import { C as Clock, D as Decision } from './types-DKirIBQt.js'; import { a as CommonAdapterOptions, L as LimiterOrStrategy } from './core-DcpxT2lH.js'; import './store-CQjuAFM_.js'; /** * Fastify v5 adapter. Wraps a {@link Limiter} (prebuilt or constructed inline) as an `onRequest` * hook that derives a proxy-correct client-IP key by default, enforces the limit, emits standards * headers, and responds `429` with `Retry-After` on a denial — with explicit fail-open/closed * behavior when the store is unreachable. Mirrors the Express adapter's option shape and control * flow exactly. See THROTTLEKIT.md §§14,15. * * Also exposes {@link fastifyUnifiedAdmission} and {@link fastifyAdaptiveConcurrency} (0.9.2, * TK-1325) that wire the `release()` lifecycle to `reply.raw.on("finish")` + * `reply.raw.on("close")` using the first-fire-wins pattern. See * `research/bigger-bets/middleware-integration/DESIGN.md`. */ type FastifyRateLimitOptions = LimiterOrStrategy & CommonAdapterOptions & { /** Cost of a request in limiter units. A function computes it per request. Default 1. */ cost?: number | ((request: FastifyRequest) => number); /** Derive the limit key from a request. Default: proxy-correct, aggregated client IP. */ key?: (request: FastifyRequest) => string; /** Observability hook fired on every denial, before the response is written. */ onLimited?: (request: FastifyRequest, reply: FastifyReply, decision: Decision) => void; /** Observability hook fired when the store throws (before the fail policy is applied). */ onError?: (request: FastifyRequest, reply: FastifyReply, err: unknown) => void; /** Custom 429 responder. When provided, it fully owns the denial response. */ handler?: (request: FastifyRequest, reply: FastifyReply, decision: Decision) => void; }; /** * Create a Fastify `onRequest` hook enforcing a rate limit. Register it with `addHook`; sending a * terminal reply inside an async `onRequest` hook short-circuits the lifecycle, so denials never * reach the route handler. * * @example * fastify.addHook("onRequest", fastifyRateLimit({ strategy: gcra({ limit: 100, periodMs: 60_000 }) })); */ declare function fastifyRateLimit(options: FastifyRateLimitOptions): (request: FastifyRequest, reply: FastifyReply) => Promise; /** Per-axis Decision snapshot from `admitter.lastDecisions()`. */ type AxisSnapshot = Readonly>>; /** Options for {@link fastifyUnifiedAdmission}. */ type FastifyUnifiedAdmissionOptions = Pick & { /** The unified admitter to enforce. Build it once with `unifiedAdmission({...})` and pass it in. */ admitter: UnifiedAdmitter; /** Cost passed to the cost axis. Defaults to 1. */ cost?: number | ((request: FastifyRequest) => number); /** Key passed to the rate/cost axes. Defaults to the proxy-correct client IP. */ key?: (request: FastifyRequest) => string; /** Clock used for header delta math. Default {@link systemClock}. */ clock?: Clock; /** Treat 5xx responses as `dropped: true`. Default `false`. See DESIGN.md §5. */ dropOn5xx?: boolean; /** Fired on every denial. */ onLimited?: (request: FastifyRequest, reply: FastifyReply, decision: Decision, axes: AxisSnapshot) => void; /** Fired when `admit()` throws. */ onError?: (request: FastifyRequest, reply: FastifyReply, err: unknown) => void; /** Custom 429 responder. */ handler?: (request: FastifyRequest, reply: FastifyReply, decision: Decision, axes: AxisSnapshot) => void; }; /** * Build a Fastify hook that enforces a {@link UnifiedAdmitter}. Register as `preHandler` * (NOT `onRequest`) so `reply.raw` has subscribers — `onRequest` runs before * the routing layer attaches handlers to the response stream. The hook wires * `release()` to `reply.raw`'s `finish` + `close` events. * * @example * const admitter = unifiedAdmission({ rate, concurrency, cost }); * fastify.addHook("preHandler", fastifyUnifiedAdmission({ admitter })); */ declare function fastifyUnifiedAdmission(options: FastifyUnifiedAdmissionOptions): (request: FastifyRequest, reply: FastifyReply) => Promise; /** Options for {@link fastifyAdaptiveConcurrency}. */ type FastifyAdaptiveConcurrencyOptions = Pick & { /** The concurrency guard to enforce. */ guard: ConcurrencyGuard; /** Clock used for header delta math. Default {@link systemClock}. */ clock?: Clock; /** Treat 5xx as `dropped: true`. Default false. */ dropOn5xx?: boolean; /** Fired on every denial. */ onLimited?: (request: FastifyRequest, reply: FastifyReply, decision: Decision) => void; /** Custom 429 responder. */ handler?: (request: FastifyRequest, reply: FastifyReply, decision: Decision) => void; }; /** * Build a Fastify `preHandler` hook that enforces an adaptive {@link ConcurrencyGuard}. * Wires `release()` to `reply.raw` lifecycle so completion/abort feeds the RTT sampler. * * @example * fastify.addHook("preHandler", fastifyAdaptiveConcurrency({ guard })); */ declare function fastifyAdaptiveConcurrency(options: FastifyAdaptiveConcurrencyOptions): (request: FastifyRequest, reply: FastifyReply) => Promise; export { CommonAdapterOptions, type FastifyAdaptiveConcurrencyOptions, type FastifyRateLimitOptions, type FastifyUnifiedAdmissionOptions, LimiterOrStrategy, fastifyAdaptiveConcurrency, fastifyRateLimit, fastifyUnifiedAdmission };