TypeScript 98.3%
CSS 0.9%
Shell 0.7%
1// Limitation de débit en mémoire (fenêtre glissante). Suffisant pour un déploiement mono-nœud ;2// remplacer par Redis pour un déploiement multi-instances (docs/deployment.md).34type Bucket = { times: number[] };5const buckets = new Map<string, Bucket>();67export function rateLimit(key: string, max: number, windowMs: number): { ok: boolean; retryAfterS: number } {8 const now = Date.now();9 let b = buckets.get(key);10 if (!b) {11 b = { times: [] };12 buckets.set(key, b);13 }14 b.times = b.times.filter((t) => now - t < windowMs);15 if (b.times.length >= max) {16 const retryAfterS = Math.ceil((b.times[0] + windowMs - now) / 1000);17 return { ok: false, retryAfterS };18 }19 b.times.push(now);20 if (buckets.size > 10_000) {21 // purge simple pour borner la mémoire22 for (const [k, v] of buckets) if (v.times.every((t) => now - t > windowMs)) buckets.delete(k);23 }24 return { ok: true, retryAfterS: 0 };25}26