interface WindowEntry { count: number; resetAt: number; } const windows = new Map(); // Purge expired entries every 60s setInterval(() => { const now = Date.now(); for (const [key, entry] of windows) { if (now > entry.resetAt) windows.delete(key); } }, 60_000).unref(); /** * Fixed-window rate limiter. Returns null if allowed, * or a 429 Response if the limit is exceeded. */ export function rateLimit( key: string, limit: number, windowMs: number, ): Response | null { const now = Date.now(); const entry = windows.get(key); if (!entry || now > entry.resetAt) { windows.set(key, { count: 1, resetAt: now + windowMs }); return null; } if (entry.count >= limit) { const retryAfter = Math.ceil((entry.resetAt - now) / 1000); return new Response("Too many requests", { status: 429, headers: { "Retry-After": String(retryAfter) }, }); } entry.count++; return null; } export function getClientIp(request: Request): string { return ( request.headers.get("cf-connecting-ip") ?? request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown" ); }