/** * Sliding-window rate limiter with FIFO queue. * * Replaces the previous busy-wait loop which, under concurrent calls, * could pile up setTimeout handles and serve callers out of order. * * Guarantees: * - At most `maxRequests` acquires resolve within any `windowMs` period. * - Callers are served strictly in FIFO order. * - At most one scheduled timer is outstanding at any time. */ export interface RateLimiterOptions { /** Max number of acquires per sliding window. */ maxRequests: number; /** Window size in ms. */ windowMs: number; /** * Injectable clock for tests. Only affects internal time calculations in * `acquire()`; real `setTimeout` calls used by `scheduleDrain()` are not * steered by this. When testing queued `acquire()` behavior, pair a fake * `now` with fake timers (e.g. `vi.useFakeTimers()` + `advanceTimersByTime`). */ now?: () => number; } export declare class SlidingWindowRateLimiter { private readonly maxRequests; private readonly windowMs; private readonly now; private timestamps; private queue; private scheduled; constructor(opts?: Partial); /** * Waits until a slot is available, then records it and resolves. * Concurrent callers are served FIFO. */ acquire(): Promise; /** Drops timestamps older than the window. */ private prune; /** * Ensures exactly one timer is outstanding. On fire, drains as many * queued callers as free slots allow, then reschedules if needed. */ private scheduleDrain; private drain; }