/** * Simple in-memory rate limiter using fixed window approach. * Tracks request counts per key (typically IP) within time windows. * * For production with multiple instances, replace with Redis-based solution. */ type RateLimitEntry = { count: number resetAt: number } const store = new Map() export type RateLimitResult = { success: boolean remaining: number resetAt: number } /** * Check rate limit for a given key. * @param key - Identifier (e.g., IP address) * @param limit - Max requests per window * @param windowMs - Window size in milliseconds */ export function checkRateLimit( key: string, limit: number, windowMs: number ): RateLimitResult { const now = Date.now() const entry = store.get(key) if (!entry || now > entry.resetAt) { const resetAt = now + windowMs store.set(key, { count: 1, resetAt }) return { success: true, remaining: limit - 1, resetAt } } if (entry.count >= limit) { return { success: false, remaining: 0, resetAt: entry.resetAt } } entry.count++ return { success: true, remaining: limit - entry.count, resetAt: entry.resetAt } } // Clean up stale entries every 5 minutes to prevent memory leaks if (typeof setInterval !== 'undefined') { setInterval(() => { const now = Date.now() for (const [key, entry] of store) { if (now > entry.resetAt) { store.delete(key) } } }, 5 * 60 * 1000).unref?.() }