// Per-route runtime state: sequence cursors + rate-limit windows. // Keyed by route file; reset on server restart. const seqCursor = new Map() /** Return the next index in a sequence of length n, advancing the cursor. */ export function nextSeqIndex(key: string, n: number): number { const i = seqCursor.get(key) ?? 0 seqCursor.set(key, i + 1) return i % n } const rlHits = new Map() /** Sliding-window rate limit. Returns remaining + whether this call is allowed. */ export function rateCheck(key: string, max: number, windowMs: number, now: number) { const hits = (rlHits.get(key) ?? []).filter((t) => now - t < windowMs) if (hits.length >= max) { rlHits.set(key, hits) const retryMs = windowMs - (now - hits[0]) return { allowed: false, remaining: 0, retryMs } } hits.push(now) rlHits.set(key, hits) return { allowed: true, remaining: max - hits.length, retryMs: 0 } }