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'; /** * Remix / React Router adapter. Exposes a guard you call at the top of a `loader`/`action`: under the * limit it resolves to the standards headers (attach them via `json(data, { headers })`); over the * limit it **throws** a `429` `Response` (Remix renders thrown Responses); a fail-closed store outage * throws `503`. The key derives from the Web `Request` — `cf-connecting-ip`/trusted `x-forwarded-for` * → `"anon"` (audit TK-S01) — overridable. See THROTTLEKIT.md §§14,15. * * Also exposes {@link remixUnifiedAdmission} and {@link remixAdaptiveConcurrency} (0.9.2, * TK-1326) — HOC-style wrappers around a loader/action returning a Response. */ type RemixRateLimitOptions = LimiterOrStrategy & CommonAdapterOptions & { /** Cost of a request in limiter units. A function computes it per request. Default 1. */ cost?: number | ((request: Request) => number); /** Derive the limit key from the request. Default: edge client IP (see {@link edgeClientIp}). */ key?: (request: Request) => string; /** Observability hook fired on every denial, before the `Response` is thrown. */ onLimited?: (request: Request, decision: Decision) => void; /** Observability hook fired when the store throws (before the fail policy is applied). */ onError?: (request: Request, err: unknown) => void; /** Custom denial responder; its `Response` is thrown instead of the default 429. */ handler?: (request: Request, decision: Decision) => Response | Promise; }; /** A Remix guard: resolves to headers to attach on allow; throws a `Response` on deny. */ type RemixRateLimitGuard = (request: Request) => Promise>; /** * Build a Remix loader/action rate-limit guard. * * @example * ```ts * const rateLimit = remixRateLimit({ strategy: gcra({ limit: 60, periodMs: 60_000 }) }); * export async function loader({ request }: LoaderFunctionArgs) { * const headers = await rateLimit(request); // throws a 429 Response when over the limit * return json(await getData(), { headers }); * } * ``` */ declare function remixRateLimit(options: RemixRateLimitOptions): RemixRateLimitGuard; /** Per-axis Decision snapshot. */ type AxisSnapshot = Readonly>>; /** A Remix-style loader/action — receives `{request, ...}` and returns a Response. */ type RemixLoaderHandler = (args: { request: Request; [k: string]: unknown; }) => Response | Promise; /** Options for {@link remixUnifiedAdmission}. */ type RemixUnifiedAdmissionOptions = Pick & { admitter: UnifiedAdmitter; cost?: number | ((request: Request) => number); key?: (request: Request) => string; clock?: Clock; dropOn5xx?: boolean; onLimited?: (request: Request, decision: Decision, axes: AxisSnapshot) => void; onError?: (request: Request, err: unknown) => void; }; /** * Wrap a Remix loader/action with a {@link UnifiedAdmitter}. The release fires when the * Response body completes / errors / is cancelled. * * @example * export const loader = remixUnifiedAdmission(async ({ request }) => json(await getData()), { admitter }); */ declare function remixUnifiedAdmission(handler: RemixLoaderHandler, options: RemixUnifiedAdmissionOptions): RemixLoaderHandler; /** Options for {@link remixAdaptiveConcurrency}. */ type RemixAdaptiveConcurrencyOptions = Pick & { guard: ConcurrencyGuard; clock?: Clock; dropOn5xx?: boolean; onLimited?: (request: Request, decision: Decision) => void; }; /** Wrap a Remix loader/action with an adaptive {@link ConcurrencyGuard}. */ declare function remixAdaptiveConcurrency(handler: RemixLoaderHandler, options: RemixAdaptiveConcurrencyOptions): RemixLoaderHandler; export { CommonAdapterOptions, LimiterOrStrategy, type RemixAdaptiveConcurrencyOptions, type RemixLoaderHandler, type RemixRateLimitGuard, type RemixRateLimitOptions, type RemixUnifiedAdmissionOptions, remixAdaptiveConcurrency, remixRateLimit, remixUnifiedAdmission };