import { prisma } from "./prisma"; type RateLimitResult = { ok: boolean; remaining: number; resetAt: Date; }; const parseNumber = (value: string | undefined, fallback: number) => { if (!value) return fallback; const parsed = Number(value); return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback; }; export const getRateLimitConfig = (envKey: string, defaultLimit: number) => { const limit = parseNumber(process.env[envKey], defaultLimit); const windowMinutes = parseNumber(process.env.RATE_LIMIT_WINDOW_MINUTES, 15); return { limit, windowMs: windowMinutes * 60 * 1000 }; }; export async function checkRateLimit({ key, limit, windowMs }: { key: string; limit: number; windowMs: number; }): Promise { const now = new Date(); const resetAt = new Date(now.getTime() + windowMs); const existing = await prisma.rateLimit.findUnique({ where: { key } }); if (!existing || existing.resetAt <= now) { await prisma.rateLimit.upsert({ where: { key }, update: { count: 1, resetAt }, create: { key, count: 1, resetAt } }); return { ok: true, remaining: Math.max(0, limit - 1), resetAt }; } if (existing.count >= limit) { return { ok: false, remaining: 0, resetAt: existing.resetAt }; } const updated = await prisma.rateLimit.update({ where: { key }, data: { count: { increment: 1 } } }); return { ok: true, remaining: Math.max(0, limit - updated.count), resetAt: updated.resetAt }; }