All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- ROADMAP.md — contributor-facing roadmap: open bugs, adapters, tests, docs, and performance items with difficulty labels
- CONTRIBUTING.md — link to the roadmap for discoverability
- README — added CI status badge (GitHub Actions workflow) as the first badge
- CI —
publishjob now auto-creates a GitHub Release with generated notes on everyv*tag push (gh release create --generate-notes) - CI — added
contents: writeper-job permission topublishjob sogh release createworks without elevated repo permissions
- CI: set
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=trueto silence Node.js 20 deprecation warning in GitHub Actions (deadline: June 2026)
- README — restructured with badges, complete config reference table, and advanced usage section
- package.json — added
author,repository,homepage,bugsfields; expanded keywords for npm discoverability - Build —
tsupconfig now includesminify: trueandtarget: 'node18'for smaller output
- Express integration test: added
keyGeneratorto isolate per-test rate limit counters, eliminating cross-test interference flakiness
- Algorithm extensibility —
algorithm: 'sliding-window' | 'token-bucket'config option alongside the existing'fixed-window'defaultSlidingWindowLimiter— rolling window with no boundary burst (spec-002 US1)TokenBucketLimiter— burst-friendly with steady token refill (spec-002 US2)
- RedisStore — multi-process storage adapter via
limiterx/redis(spec-002 US3)- Duck-typed
RedisClientInterfacecompatible with ioredis and node-redis - Atomic Lua INCR + EXPIRE to prevent race conditions
RedisStore.decrement()for skipSuccessfulRequests support
- Duck-typed
- Custom store —
store?: StorageAdapterconfig field to plug in any backend (spec-002) - Dynamic
max—maxnow accepts(ctx: RequestContext) => number | Promise<number>for per-request tier limits (spec-003 GAP-1) skipSuccessfulRequests— decrement counter on 2xx responses; finish-event hook on Express/Koa/Next (spec-003 GAP-2a)skipFailedRequests— decrement counter on 4xx/5xx responses (spec-003 GAP-2b)requestWasSuccessful— custom predicate(ctx) => boolean | Promise<boolean>for skip options (spec-003 GAP-2c)RateLimiter.decrement(key)— public API to manually decrement a counter- IETF draft selector —
standardHeaders: 'draft-6' | 'draft-7' | 'draft-8'(default:'draft-7') (spec-003 GAP-5)draft-6: single combinedRateLimitheaderdraft-8: draft-7 fields +RateLimit-Policy: {limit};w={windowSec}
identifier— customRateLimit-Policyname for draft-8 (spec-003 GAP-6)validate—boolean | Record<string, boolean>to suppress runtime warnings (spec-003 GAP-10)- Warns when
windowMs > 2_147_483_647(max safe setTimeout); deduped per process
- Warns when
- IPv6 subnet masking —
ipv6Subnet?: number | false(default:/56) on all backend adapters (spec-003 GAP-7) - Legacy headers —
legacyHeaders?: booleanemitsX-RateLimit-*with epoch-second Reset (spec-003 GAP-4) - Async
keyGeneratorandskip— both now acceptasync (ctx) => ...(spec-003 GAP-11) requestPropertyName— customise the property set onreq/ctx(default:'rateLimit') (spec-003 GAP-8)passOnStoreError— fail-open mode on storage errors (spec-003 GAP-9)handler— replace built-in 429 response with a custom callback (spec-003 GAP-12)message— now accepts sync/async function(result, ctx) => string | object(spec-003 GAP-3)MemoryStore.decrement(key, ttlMs)— no-op if key missing or expired, floor at 0
maxtype widened fromnumbertonumber | ((ctx: RequestContext) => number | Promise<number>)— fully backwards-compatibleStorageAdapterinterface gainsdecrement(key: string, ttlMs: number): Promise<void>RateLimiterinterface gainsdecrement(key: string): Promise<void>- Package size: 179.5 kB unpacked (down from 621 kB in v1.0.1 —
splitting: true,sourcemap: false)
- BREAKING: npm package name is now
limiterx(unscoped). Subpath imports uselimiterx/express,limiterx/react, etc. - BREAKING:
FlowGuardConfigrenamed toLimiterxConfig. - Error and debug log prefixes use
[limiterx]; internal storage key namespace islimiterx:.
- Core rate limiting engine with fixed window algorithm
createRateLimiter()factory function with unified configurationparseWindow()for human-readable duration strings ('30s', '5m', '1h', '1d')MemoryStorewith LRU eviction (default 10,000 keys) and periodic TTL cleanup- Express middleware adapter (
limiterx/express) - Raw Node.js HTTP adapter (
limiterx/node) - Next.js API route and Edge middleware adapter (
limiterx/next) - Koa middleware adapter (
limiterx/koa) - React hook
useRateLimit(limiterx/react) - Fetch wrapper
rateLimitFetch(limiterx/fetch) - Axios interceptor
rateLimitAxios(limiterx/axios) RateLimitErrorclass for frontend adapter rejections- Standard
RateLimit-Limit,RateLimit-Remaining,RateLimit-Resetheaders Retry-Afterheader on denied responses- Config validation with descriptive
[limiterx]error messages skipfunction for bypassing rate limitingonLimitcallback for limit exceeded eventsdebugflag for console diagnosticskeyGeneratorfor custom key resolution- Tree-shakeable subpath exports with
sideEffects: false - Dual ESM/CJS output
- TypeScript strict mode with full type exports
- CI/CD pipeline with Node 18/20/22 matrix and Bun testing
- Automated npm publishing on
v*tags with provenance