import { D as Decision, d as Strategy } from './types-DKirIBQt.cjs'; /** * Stable, machine-readable discriminant carried by every {@link ThrottleKitError}. Prefer it over * `instanceof` when robustness matters across realms or a dependency tree that bundled ThrottleKit * twice (`instanceof` fails across two copies of the class; the `code` string does not). Frozen at * 1.0 — the value set grows only additively. */ type ThrottleKitErrorCode = "throttlekit_error" | "store_unavailable" | "not_implemented" | "rate_limit_exceeded" | "queue_full" | "config_invalid"; /** Base class for all errors thrown by ThrottleKit. */ declare class ThrottleKitError extends Error { /** Machine-readable discriminant — see {@link ThrottleKitErrorCode}. Robust to cross-realm `instanceof`. */ readonly code: ThrottleKitErrorCode; constructor(message: string, options?: ErrorOptions & { code?: ThrottleKitErrorCode; }); } /** * The backing store could not be reached or returned an error. The adapter's `fail` policy * decides whether this resolves to allow (`"open"`) or deny (`"closed"`). */ declare class StoreUnavailableError extends ThrottleKitError { constructor(message?: string, options?: ErrorOptions); } /** * Thrown by a placeholder code path that has been declared but not yet * implemented. Used during incremental rollout (e.g. the `FederatedStore` * skeleton in TK-902 throws this from `apply()` until TK-903/904 land the * real behavior). Catching this specifically lets tests and integrators * distinguish "this is a known stub" from a generic ThrottleKitError. */ declare class NotImplementedError extends ThrottleKitError { constructor(message: string, options?: ErrorOptions); } /** * Convenience error for callers that prefer throwing over inspecting a {@link Decision}. * Carries the denying decision and its `retryAfterMs`. */ declare class RateLimitExceededError extends ThrottleKitError { readonly retryAfterMs: number; readonly decision: Decision; constructor(decision: Decision, message?: string); } /** A calendar cadence whose period boundary lands on a civil-calendar edge. */ type CalendarCadence = "calendar-month" | "calendar-week" | "calendar-day"; /** How a {@link quota}'s budget resets. */ type QuotaCadence = CalendarCadence | "fixed" | "rolling"; interface QuotaOptions { /** Units admitted per billing period. */ limit: number; /** * When the budget resets: * - `"calendar-month"` — on the 1st of each civil month (the canonical "1M calls/month" quota); * - `"calendar-week"` — on `weekStartsOn` each week; * - `"calendar-day"` — at local midnight; * - `"fixed"` — every `periodMs` from `anchor` (epoch-aligned by default); * - `"rolling"` — a trailing `periodMs` window (delegates to {@link slidingWindow}). */ resetCadence: QuotaCadence; /** Period width in ms. Required for `"fixed"` and `"rolling"`; ignored by calendar cadences. */ periodMs?: number; /** `"fixed"` windows align to this epoch-ms anchor. Default `0` (epoch-aligned). */ anchor?: number; /** * Fixed UTC offset, in minutes, applied to calendar cadences (e.g. `330` for IST, `-300` for * EST). Default `0` (UTC). This is a **fixed offset, not a DST-aware zone** — see {@link * calendarPeriod}; a fixed offset is the only calendar math reproducible bit-identically in the * Redis Lua form. */ offsetMinutes?: number; /** For `"calendar-week"`, the weekday the week starts on (`0`=Sun … `6`=Sat). Default `1` (Mon). */ weekStartsOn?: number; /** For `"rolling"`, the number of sub-buckets (accuracy vs memory). Default `10`. */ buckets?: number; } /** * First-class billing-period **quota** — a budget that resets on a real calendar boundary, distinct * from a sliding rate limit. The motivating case is "1,000,000 calls/month, resetting on the 1st": * `Decision.remaining` is the quota left this period and `Decision.resetAt` is the *true* next * boundary (the next civil 1st, leap-year-correct), not an approximation. * * Runs the pure {@link Strategy} contract (`check` + atomic Lua) so it is bit-identical on every * store. Calendar boundaries are computed at a fixed UTC offset (`offsetMinutes`); see {@link * calendarPeriod} for why DST-aware zones are out of scope. The `"rolling"` cadence delegates to the * proven {@link slidingWindow}. As with the other strategies, a denied request never consumes — * `remaining` stays meaningful. */ declare function quota(options: QuotaOptions): Strategy; export { NotImplementedError as N, type QuotaCadence as Q, RateLimitExceededError as R, StoreUnavailableError as S, ThrottleKitError as T, type QuotaOptions as a, type ThrottleKitErrorCode as b, quota as q };