Resolve the client IP from forwarding headers, falling back to a shared bucket.
(req: Request)
| 65 | |
| 66 | /** Resolve the client IP from forwarding headers, falling back to a shared bucket. */ |
| 67 | function getClientIp(req: Request): string { |
| 68 | const forwarded = req.headers.get('x-forwarded-for') |
| 69 | if (forwarded) return forwarded.split(',')[0].trim() |
| 70 | return req.headers.get('x-real-ip') ?? 'unknown' |
| 71 | } |
| 72 | |
| 73 | /** Fixed-window check. Returns retry-after seconds when the caller is over the limit, else null. */ |
| 74 | function rateLimit(ip: string, now: number): number | null { |