Summary
The current fixed-window limiter allows bursts at window edges and isn't isolated per tenant. Implement a sliding-window limiter keyed per tenant/API key so limits are smooth and fair.
Why this matters
Fixed windows let a client send 2x the limit across a boundary, and a shared counter lets one tenant starve others. A per-key sliding window is fair and burst-resistant.
Requirements
- Implement a sliding-window counter keyed by tenant/API key.
- Return
429 with Retry-After and a structured rate_limited error when exceeded.
- Expose remaining/limit/reset via response headers.
- Window size and limit are configurable with safe defaults.
Technical guidance
- Keep the counter store behind an interface (in-memory impl now).
- Compute the sliding count from the prior + current sub-windows to avoid storing every timestamp.
Edge cases — each must have a test
Acceptance criteria
Out of scope
- Distributed rate limiting
- Dynamic per-plan limits
Rewards
Part of the GrantFox OSS / Official Campaign (FWC26) — this task may be rewarded. PR quality is assessed by AI: depth, correctness under edge cases, meaningful tests, and clean design are what earn the reward. Shallow changes (typos, formatting, trivial docs) do not qualify.
Summary
The current fixed-window limiter allows bursts at window edges and isn't isolated per tenant. Implement a sliding-window limiter keyed per tenant/API key so limits are smooth and fair.
Why this matters
Fixed windows let a client send 2x the limit across a boundary, and a shared counter lets one tenant starve others. A per-key sliding window is fair and burst-resistant.
Requirements
429withRetry-Afterand a structuredrate_limitederror when exceeded.Technical guidance
Edge cases — each must have a test
Acceptance criteria
npm run lint,npm test, andnpm run buildall pass locallyCloses #<issue>Out of scope
Rewards
Part of the GrantFox OSS / Official Campaign (FWC26) — this task may be rewarded. PR quality is assessed by AI: depth, correctness under edge cases, meaningful tests, and clean design are what earn the reward. Shallow changes (typos, formatting, trivial docs) do not qualify.