Study/src/lib/rateLimiter.ts
Elijah 95af276d2e
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m6s
Refactor login flow with reset token support
2026-07-12 07:53:48 -07:00

36 lines
1 KiB
TypeScript

/**
* In-memory sliding window rate limiter.
* Single-instance, single-user container — no need for Redis.
*/
interface RateLimitEntry {
timestamps: number[];
}
const store = new Map<string, RateLimitEntry>();
const WINDOW_MS = 60 * 1000; // 1 minute
const MAX_REQUESTS = 10;
export function checkRateLimit(
key: string,
options: { windowMs?: number; maxRequests?: number } = {}
): { allowed: boolean; retryAfterMs: number } {
const now = Date.now();
const windowMs = options.windowMs ?? WINDOW_MS;
const maxRequests = options.maxRequests ?? MAX_REQUESTS;
const entry = store.get(key) ?? { timestamps: [] };
// Remove timestamps outside the window
entry.timestamps = entry.timestamps.filter((t) => now - t < windowMs);
if (entry.timestamps.length >= maxRequests) {
const oldestInWindow = entry.timestamps[0];
const retryAfterMs = windowMs - (now - oldestInWindow);
return { allowed: false, retryAfterMs };
}
entry.timestamps.push(now);
store.set(key, entry);
return { allowed: true, retryAfterMs: 0 };
}