/** * Wrap a user-supplied store into the interface the rate-limit algorithms * expect. Validates that the required methods exist so misconfigurations * surface at startup, not at the first blocked request. * * Required methods (all may be async): * - `get(key)` → { count, expiresAt } | null * - `incr(key, ttlMs)` → { count, expiresAt } (atomic) * - `set(key, count, ttlMs)` → void * - `delete(key)` → void * * Optional: * - `reset(key)` → void (defaults to `delete`) * - `decr(key)` → void — atomic decrement of an existing * key. When provided, `sliding` uses it for race-free rollback of a * rejected request's tentative increment. * - `compareAndSet(key, expected, value, ttlMs)` → boolean — atomic CAS * (`expected: null` = key must not exist). When provided, * `tokenBucket` / `leakyBucket` become race-free under concurrency. * * Atomicity guarantee: `incr` must be atomic across concurrent callers. On * Redis, wrap `INCR + EXPIRE` in a Lua script or MULTI/EXEC. On Mongo, use * `findOneAndUpdate` with upsert. Non-atomic implementations race and let * requests bypass the limit under load. * * @param {Partial} impl * @returns {import('../index.js').RateLimitStore} */ export function customStore(impl: Partial): import("../index.js").RateLimitStore;