rateLimiter.ts
Raw
1import config from "../config.ts";
2
3interface Bucket {
4 count: number;
5 resetAt: number;
6}
7
8const buckets = new Map<string, Bucket>();
9let sweepCounter = 0;
10
11function maybeSweep() {
12 if (++sweepCounter < 1000) return;
13 sweepCounter = 0;
14 const now = Date.now();
15 for (const [key, bucket] of buckets) {
16 if (now > bucket.resetAt) buckets.delete(key);
17 }
18}
19
20export function checkRateLimit(
21 ip: string | null,
22 maxRequests: number,
23 windowMs: number,
24): boolean {
25 if (config.RATE_LIMIT_DISABLED || !ip) return true;
26 const now = Date.now();
27 const bucket = buckets.get(ip);
28 if (!bucket || now > bucket.resetAt) {
29 buckets.set(ip, { count: 1, resetAt: now + windowMs });
30 maybeSweep();
31 return true;
32 }
33 if (bucket.count >= maxRequests) return false;
34 bucket.count++;
35 return true;
36}
37
38export function getClientIp(
39 request: Request,
40 server: Bun.Server<unknown> | null,
41): string | null {
42 if (config.TRUSTED_PROXY) {
43 return (
44 request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ??
45 null
46 );
47 }
48 return server?.requestIP(request)?.address ?? null;
49}
50