import { T as ThrottleKitError, Q as QuotaCadence } from './quota-CCmM2Fni.cjs'; import { S as Store, L as Limiter, d as Strategy } from './types-DKirIBQt.cjs'; /** * A practical YAML subset for `.throttlekit.yaml` — **zero-dep**, deliberately narrow. * * Supports: block maps (consistent leading-space indent), scalars (bare string, double/single-quoted * string, number, `true`/`false`, `null`/`~`), inline flow maps `{ k: v, k2: v2 }`, `#` end-of-line * and whole-line comments, blank lines. * * Does **not** support: block lists, anchors/aliases, multiline scalars, multi-document streams, * nested flow maps. Anything outside the subset throws {@link YamlParseError} with a 1-based line * number — the config format is intentionally constrained so its meaning is unambiguous. */ declare class YamlParseError extends ThrottleKitError { readonly line: number; constructor(message: string, line: number); } /** Parse a YAML-subset document into a plain object. Throws {@link YamlParseError} on any deviation. */ declare function parseYaml(text: string): Record; /** * Rate-limit-as-code: load a `.throttlekit.yaml` (or `.throttlekit.json`) into ready-to-use * {@link Limiter} instances. The config declares **strategies and policies**, not live clients — * the {@link Store} is injected at load time (you can't serialise an `ioredis` client into YAML). * * @example * ```yaml * # .throttlekit.yaml * version: 1 * limiters: * api: { strategy: gcra, limit: 100, period: 1m, burst: 20 } * uploads: { strategy: fixedWindow, limit: 10, period: 1h } * monthly: { strategy: quota, limit: 1000000, resetCadence: calendar-month } * ``` * ```ts * import { loadConfig } from "throttlekit/config"; * import { RedisStore } from "throttlekit/redis"; * const { limiters } = loadConfig(readFileSync(".throttlekit.yaml", "utf8"), { store: new RedisStore({ client }) }); * app.use("/api", expressRateLimit({ limiter: limiters.api })); * app.use("/uploads", expressRateLimit({ limiter: limiters.uploads })); * ``` */ /** Strategy name a {@link LimiterSpec} can pick. */ type ConfigStrategy = "gcra" | "tokenBucket" | "fixedWindow" | "slidingWindow" | "slidingWindowLog" | "quota"; /** One named limiter in the config — declares its strategy and policy. */ interface LimiterSpec { /** Which algorithm to use. */ strategy: ConfigStrategy; /** Sustained ceiling (gcra/fixedWindow/slidingWindow/slidingWindowLog/quota). */ limit?: number; /** Window/period — `"1m"`, `"30s"`, `"1h"`, `"1d"`, or a number of ms. */ period?: string | number; /** GCRA burst allowance (default = `limit`). */ burst?: number; /** Token-bucket capacity. */ capacity?: number; /** Token-bucket refill rate (tokens per second; may be fractional). */ refillPerSec?: number; /** Explicit `windowMs` if you'd rather not use `period`. */ windowMs?: number; /** Sub-buckets for `slidingWindow` (default 10). */ buckets?: number; /** Quota reset cadence — `"calendar-month"` etc. (required for `quota`). */ resetCadence?: QuotaCadence; /** Fixed offset (minutes) for calendar cadences. */ offsetMinutes?: number; /** Day the week starts on for `calendar-week` (0=Sun … 6=Sat). */ weekStartsOn?: number; /** Anchor for `quota({ resetCadence: "fixed" })`. */ anchor?: number; /** Period (ms) for `quota` `"fixed"` / `"rolling"` if you prefer ms over `period`. */ periodMs?: number; /** Key prefix override for this limiter (defaults to the entry name). */ prefix?: string; } /** The top-level shape of `.throttlekit.yaml` / `.throttlekit.json`. */ interface ConfigFile { /** Schema version (current: 1). */ version?: number; /** Defaults applied where a limiter doesn't override. */ defaults?: { prefix?: string; }; /** Named limiters keyed by their human label. */ limiters: Record; } interface LoadConfigOptions { /** Shared store for every built limiter (default: a private in-process store per limiter). */ store?: Store; /** Force a format. Default: auto-detect (text starting with `{` or `[` is JSON, else YAML). */ format?: "yaml" | "json"; } interface LoadedConfig { /** Limiters keyed by config name, ready to pass into any adapter. */ limiters: Record; } /** Parse and build limiters from raw config text. */ declare function loadConfig(text: string, options?: LoadConfigOptions): LoadedConfig; /** Build limiters from an already-parsed config object (use when your app brings its own parser). */ declare function loadConfigObject(data: ConfigFile, options?: LoadConfigOptions): LoadedConfig; /** * Build a {@link Strategy} from one declarative {@link LimiterSpec} — the same constructor * {@link loadConfigObject} uses internally, exposed as a low-level building block. `name` is used * only for error context; the returned strategy is a pure function of `spec`. * * The motivating consumer is the **replay testkit** (`throttlekit/testkit` replay primitives), which * rebuilds the exact leaf limiter a decision trace was recorded over by re-running this on the * trace's recorded spec. Because the build is pure, the same spec always yields a behaviourally * identical strategy — the precondition for deterministic replay. * * @experimental Outside the `1.x` SemVer freeze (see STABILITY.md). The signature is expected to be * stable, but it is opt-in and may change in a minor. */ declare function buildStrategy(name: string, spec: LimiterSpec): Strategy; export { type ConfigFile, type ConfigStrategy, type LimiterSpec, type LoadConfigOptions, type LoadedConfig, YamlParseError, buildStrategy, loadConfig, loadConfigObject, parseYaml };