20 lines
986 B
TypeScript
20 lines
986 B
TypeScript
import { db } from "@/lib/db";
|
|
|
|
/** SQLite-backed fixed-window limiter shared by every Web container using this database. */
|
|
export function withinRateLimit(bucket: string, limit = 30, windowMs = 60_000) {
|
|
const now = Date.now();
|
|
const transaction = db.transaction(() => {
|
|
const found = db.prepare("SELECT count,reset_at FROM rate_limits WHERE bucket=?").get(bucket) as { count: number; reset_at: number } | undefined;
|
|
if (!found || found.reset_at <= now) {
|
|
db.prepare("INSERT INTO rate_limits(bucket,count,reset_at) VALUES(?,?,?) ON CONFLICT(bucket) DO UPDATE SET count=excluded.count,reset_at=excluded.reset_at").run(bucket, 1, now + windowMs);
|
|
return true;
|
|
}
|
|
if (found.count >= limit) return false;
|
|
db.prepare("UPDATE rate_limits SET count=count+1 WHERE bucket=?").run(bucket);
|
|
return true;
|
|
});
|
|
const allowed = transaction();
|
|
if (Math.random() < 0.01) db.prepare("DELETE FROM rate_limits WHERE reset_at<?").run(now);
|
|
return allowed;
|
|
}
|