(ip: string)
| 15 | const hits = new Map<string, number[]>(); |
| 16 | |
| 17 | function isRateLimited(ip: string): boolean { |
| 18 | if (!RATE_LIMIT_ENABLED) return false; |
| 19 | const now = Date.now(); |
| 20 | const timestamps = hits.get(ip)?.filter(t => t > now - RATE_LIMIT_WINDOW_MS) ?? []; |
| 21 | timestamps.push(now); |
| 22 | hits.set(ip, timestamps); |
| 23 | return timestamps.length > RATE_LIMIT_MAX; |
| 24 | } |
| 25 | |
| 26 | // Prune stale entries every 5 min to prevent unbounded memory growth |
| 27 | if (RATE_LIMIT_ENABLED) { |