// Limitation de débit en mémoire (fenêtre glissante). Suffisant pour un déploiement mono-nœud ; // remplacer par Redis pour un déploiement multi-instances (docs/deployment.md). type Bucket = { times: number[] }; const buckets = new Map(); export function rateLimit(key: string, max: number, windowMs: number): { ok: boolean; retryAfterS: number } { const now = Date.now(); let b = buckets.get(key); if (!b) { b = { times: [] }; buckets.set(key, b); } b.times = b.times.filter((t) => now - t < windowMs); if (b.times.length >= max) { const retryAfterS = Math.ceil((b.times[0] + windowMs - now) / 1000); return { ok: false, retryAfterS }; } b.times.push(now); if (buckets.size > 10_000) { // purge simple pour borner la mémoire for (const [k, v] of buckets) if (v.times.every((t) => now - t > windowMs)) buckets.delete(k); } return { ok: true, retryAfterS: 0 }; }