ratelimit.mjs
Language JavaScript1.5 KB31 lines
// Offline verification of the rate limiter. NO network.// Run after `npm run build`: node verify/ratelimit.mjsimport { reserveSlot, InMemoryRateLimiter, PLINTH_RATE_LIMIT } from "../dist/lib/rateLimit.js";let pass = 0, fail = 0;const eq = (desc, got, want) => {const ok = JSON.stringify(got) === JSON.stringify(want);console.log(`${ok ? "PASS" : "FAIL"} ${desc} got=${JSON.stringify(got)}${ok ? "" : ` want=${JSON.stringify(want)}`}`);ok ? pass++ : fail++;};eq("PLINTH_RATE_LIMIT = 9 per 10000ms", PLINTH_RATE_LIMIT, { max: 9, windowMs: 10000 });let slots = [];const delays = [];for (let i = 0; i < 5; i++) { const r = reserveSlot(slots, 0, 2, 1000); delays.push(r.delayMs); slots = r.slots; }eq("burst of 5 (max=2/1000ms) spreads", delays, [0, 0, 1000, 1000, 2000]);eq("slot array bounded to max", slots.length <= 2, true);eq("aged-out slots don't delay", reserveSlot([0, 0], 100000, 2, 1000).delayMs, 0);const lim = new InMemoryRateLimiter(2, 300);const t0 = Date.now();const elapsed = [];for (let i = 0; i < 5; i++) { await lim.acquire(); elapsed.push(Date.now() - t0); }console.log(" completion times (ms):", elapsed);eq("first 2 immediate", elapsed[0] < 100 && elapsed[1] < 100, true);eq("3rd & 4th delayed ~1 window", elapsed[2] >= 250 && elapsed[3] >= 250, true);eq("5th delayed ~2 windows", elapsed[4] >= 550, true);console.log(`\n${fail === 0 ? "ALL PASS" : "FAILURES"} - ${pass} passed, ${fail} failed`);process.exit(fail === 0 ? 0 : 1);