// In-memory sliding-window rate limiter. Good enough for a single-instance // Docker deployment (Coolify) — resets on redeploy and doesn't share state // across replicas, but that's an acceptable MVP tradeoff for abuse-throttling // a public, unauthenticated endpoint (no external dependency like Redis needed). const hits = new Map() export function checkRateLimit(key: string, limit: number, windowMs: number): boolean { const now = Date.now() const timestamps = (hits.get(key) || []).filter((t) => now - t < windowMs) if (timestamps.length >= limit) { hits.set(key, timestamps) return false } timestamps.push(now) hits.set(key, timestamps) // Opportunistic cleanup so the map doesn't grow unbounded. if (hits.size > 5000) { for (const [k, v] of hits) { if (v.every((t) => now - t > windowMs)) hits.delete(k) } } return true }