mirror of
https://github.com/HeyPuter/puter.git
synced 2026-10-14 15:50:10 +00:00
feat: consumeRouteRateLimit takes the array spec form too
Review follow-up on #3870: a multi-window spec passed whole would have read an undefined window and silently never pruned. Charge each window in order instead, refusing on the first refusal, matching the gate.
This commit is contained in:
1 parent
1e0721fdc5
commit
57857cbb14
2 files changed
+21
No files matched your search
@@ -722,8 +722,15 @@ export async function checkRateLimit(key, limit, windowMs, backend) {
|
||||
* budget. This resolves the key and the per-subscription limit exactly as the
|
||||
* gate does — same spec in, same bucket out — so a handler can charge a second
|
||||
* scope conditionally. Returns true if allowed; fails open on backend error.
|
||||
* Takes the array form too; windows charge in order, no refund on refusal.
|
||||
*/
|
||||
export async function consumeRouteRateLimit(req, spec) {
|
||||
if (Array.isArray(spec)) {
|
||||
for (const window of spec) {
|
||||
if (!(await consumeRouteRateLimit(req, window))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const {
|
||||
window: windowMs,
|
||||
key: strategy = 'fingerprint',
|
||||
|
||||
@@ -1506,6 +1506,20 @@ describe('consumeRouteRateLimit', () => {
|
||||
expect(await consumeRouteRateLimit(reqFor(2), opts)).toBe(true);
|
||||
});
|
||||
|
||||
it('charges every window of an array spec, and any refusal refuses', async () => {
|
||||
// The array form routes use (burst + sustained); the tightest bites.
|
||||
const specs = [
|
||||
{ limit: 5, window: 60_000, key: 'user', scope: uniqueScope() },
|
||||
{ limit: 2, window: 60_000, key: 'user', scope: uniqueScope() },
|
||||
];
|
||||
const req = { actor: { user: { id: 9 } }, headers: {} };
|
||||
expect(await consumeRouteRateLimit(req, specs)).toBe(true);
|
||||
expect(await consumeRouteRateLimit(req, specs)).toBe(true);
|
||||
expect(await consumeRouteRateLimit(req, specs)).toBe(false);
|
||||
// The refusing window really was the second one, not the first.
|
||||
expect(await consumeRouteRateLimit(req, specs[0])).toBe(true);
|
||||
});
|
||||
|
||||
it('applies bySubscription overrides via the wired metering service', async () => {
|
||||
configureRateLimit({
|
||||
metering: {
|
||||
|
||||
Reference in new issue
Block a user