import { Request, Response, RequestHandler } from 'express'; 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'; /** * Express adapter. Wraps a {@link Limiter} (prebuilt or constructed inline) as a `RequestHandler` * 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. See THROTTLEKIT.md §§14,15. * * Also exposes {@link expressUnifiedAdmission} and {@link expressAdaptiveConcurrency} (0.9.2, * TK-1325) that wire the `release()` lifecycle to `res.on("finish")` + `res.on("close")` using * the first-fire-wins pattern. See `research/bigger-bets/middleware-integration/DESIGN.md`. */ type ExpressRateLimitOptions = LimiterOrStrategy & CommonAdapterOptions & { /** Cost of a request in limiter units. A function computes it per request. Default 1. */ cost?: number | ((req: Request) => number); /** Derive the limit key from a request. Default: proxy-correct, aggregated client IP. */ key?: (req: Request) => string; /** Observability hook fired on every denial, before the response is written. */ onLimited?: (req: Request, res: Response, decision: Decision) => void; /** Observability hook fired when the store throws (before the fail policy is applied). */ onError?: (req: Request, res: Response, err: unknown) => void; /** Custom 429 responder. When provided, it fully owns the denial response. */ handler?: (req: Request, res: Response, decision: Decision) => void; }; /** * Create an Express middleware enforcing a rate limit. * * @example * app.use(expressRateLimit({ strategy: gcra({ limit: 100, periodMs: 60_000 }) })); */ declare function expressRateLimit(options: ExpressRateLimitOptions): RequestHandler; /** Per-axis Decision snapshot from `admitter.lastDecisions()`. */ type AxisSnapshot = Readonly>>; /** Options for {@link expressUnifiedAdmission}. */ type ExpressUnifiedAdmissionOptions = 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 | ((req: Request) => number); /** Key passed to the rate/cost axes (concurrency is keyless). Defaults to the proxy-correct client IP. */ key?: (req: Request) => string; /** Clock used for header delta math. Default {@link systemClock}. */ clock?: Clock; /** * Treat 5xx responses as `dropped: true` for the adaptive controller. Default `false` * (a returned 5xx is application policy; the lifecycle nominally completed). See DESIGN.md §5. */ dropOn5xx?: boolean; /** Fired on every denial, with the combined Decision and per-axis snapshot. */ onLimited?: (req: Request, res: Response, decision: Decision, axes: AxisSnapshot) => void; /** Fired when `admit()` throws (before the fail policy is applied). */ onError?: (req: Request, res: Response, err: unknown) => void; /** Custom 429 responder; when provided it fully owns the denial response. */ handler?: (req: Request, res: Response, decision: Decision, axes: AxisSnapshot) => void; }; /** * Express middleware enforcing a {@link UnifiedAdmitter} — rate + adaptive concurrency + cost * in one call. On admit it wires `release()` to the response lifecycle (D-M-3 + §6 of the design): * `finish` first ⇒ `dropped: false`, `close` first (client hangup / handler throw without error * middleware) ⇒ `dropped: true`. On deny it short-circuits with 429; no slot is held. * * @example * const admitter = unifiedAdmission({ rate, concurrency, cost }); * app.use(expressUnifiedAdmission({ admitter, dropOn5xx: false })); */ declare function expressUnifiedAdmission(options: ExpressUnifiedAdmissionOptions): RequestHandler; /** Options for {@link expressAdaptiveConcurrency}. */ type ExpressAdaptiveConcurrencyOptions = Pick & { /** The concurrency guard to enforce. Build with `adaptiveConcurrency({...})` and pass it in. */ guard: ConcurrencyGuard; /** Clock used for header delta math. Default {@link systemClock}. */ clock?: Clock; /** Treat 5xx responses as `dropped: true` for the adaptive controller. Default `false`. See §5 of DESIGN.md. */ dropOn5xx?: boolean; /** Fired on every denial. */ onLimited?: (req: Request, res: Response, decision: Decision) => void; /** Custom 429 responder. */ handler?: (req: Request, res: Response, decision: Decision) => void; }; /** * Express middleware enforcing an adaptive {@link ConcurrencyGuard}. On admit it wires * `release()` to the response lifecycle so completions/aborts feed the controller's RTT * sampler correctly. On deny (over the inferred ceiling) it short-circuits with 429 + * `Retry-After: max(1, round(lastRtt))` — the honest Little's-Law hint. * * Concurrency is keyless: the guard counts global in-flight slots, not per-IP. If you need * per-tenant fairness, compose with `weightedFairEscrow` (0.9.1) ahead of this middleware. * * @example * const guard = adaptiveConcurrency({ minLimit: 4, maxLimit: 128 }); * app.use(expressAdaptiveConcurrency({ guard })); */ declare function expressAdaptiveConcurrency(options: ExpressAdaptiveConcurrencyOptions): RequestHandler; export { CommonAdapterOptions, type ExpressAdaptiveConcurrencyOptions, type ExpressRateLimitOptions, type ExpressUnifiedAdmissionOptions, LimiterOrStrategy, expressAdaptiveConcurrency, expressRateLimit, expressUnifiedAdmission };