import type { AdmissionController } from "@nifrajs/core/server"; /** * Adaptive capacity admission. Rate limiting bounds request *frequency* and `@nifrajs/core/budget` bounds * request *duration*; neither stops a healthy instance from accepting more *concurrent* work than it * can finish. This gate admits on live capacity evidence - in-flight count + event-loop lag - briefly * queues at the edge, and sheds the rest with `429` + `Retry-After`, so p99 stays bounded under load * instead of collapsing. * * Public mechanics (in-flight + loop lag) know nothing about tenants. An application-supplied {@link AdmissionPolicy} * hook layers tenant priority and reserved capacity on top without leaking * those concerns into the OSS core. * * Wire it as the server's `admission` option (NOT an `onRequest` hook - a hook disables the native * route table). Off by default: when unset, the request path is untouched. */ export type ShedReason = "inflight" | "loop-lag" | "queue-timeout" | "policy" | "cancelled"; /** Pure capacity evidence handed to the policy hook. The mechanics never invent tenant concepts. */ export interface AdmissionEvidence { readonly inFlight: number; readonly maxInFlight: number; readonly lagMs: number; readonly maxLagMs: number; readonly queued: number; } /** * Application-supplied admission policy. Return a decision to override the default mechanics * for this request, or `undefined` to defer to them. `admit` may draw from reserved headroom above * `maxInFlight`; `shed` forces rejection. */ export type AdmissionPolicy = (req: Request, evidence: AdmissionEvidence) => { decision: "admit" | "shed"; retryAfterSec?: number; } | undefined; export interface AdmissionOptions { /** Max requests running concurrently before the gate queues or sheds. */ readonly maxInFlight: number; /** Event-loop lag ceiling (ms); above it, shed even when slots are free (protects p99). Default ∞. */ readonly maxLagMs?: number; /** How many requests may briefly wait for a slot before shedding. `0` (default) never queues. */ readonly maxQueue?: number; /** How long a queued request waits for a slot before shedding. Default 50ms. */ readonly queueTimeoutMs?: number; /** Reserved slots ABOVE `maxInFlight` that only a policy `admit` may draw from. Default 0. */ readonly reservedForPolicy?: number; /** Base `Retry-After`, in seconds, for shed responses. Default 1. */ readonly baseRetryAfterSec?: number; /** * Live event-loop lag source, in ms. Pass {@link createEventLoopLagSampler} to sample the real loop; * default `() => 0` disables lag-based shedding (in-flight only). */ readonly lagMs?: () => number; readonly policy?: AdmissionPolicy; /** Test seam for deterministic queue timeouts; defaults to real timers. */ readonly setTimer?: (fn: () => void, ms: number) => { cancel(): void; }; } export interface AdmissionSnapshot { readonly inFlight: number; readonly queued: number; readonly fastPathAdmits: number; readonly slowPathEntries: number; readonly everQueued: number; readonly shed: number; } export interface AdmissionControllerHandle extends AdmissionController { /** Point-in-time counters for observability (otel gauges/counters). */ snapshot(): AdmissionSnapshot; } /** The slice of a `perf_hooks` event-loop-delay histogram the sampler needs. */ export interface LoopDelayHistogram { enable(): void; reset(): void; readonly mean: number; } /** * Acquires a loop-delay histogram for a resolution, or `undefined` when the runtime has none. This is * an optional test/runtime seam; the default sampler is a portable timer-drift monitor. */ export type LoopDelayMonitor = (resolutionMs: number) => LoopDelayHistogram | undefined; /** * Event-loop-lag sampler. By default it measures timer drift using only Web/JS runtime primitives, so * it works under Node ESM, Bun, Deno, and workers without a hidden CommonJS `require` fallback. An * injected histogram remains available for deterministic tests or a runtime-native monitor. Each read * returns recent mean lag and resets the sampling window. */ export declare function createEventLoopLagSampler(resolutionMs?: number, monitor?: LoopDelayMonitor): () => number; /** * Build a capacity-admission controller. Pass the returned handle as the server's `admission` option. */ export declare function createAdmissionController(options: AdmissionOptions): AdmissionControllerHandle; //# sourceMappingURL=admission.d.ts.map