limix
v0.1.0
Published
Storage-agnostic rate limiting algorithms (fixed window, sliding window, token bucket)
Maintainers
Readme
limix
Typed rate-limiting primitives for Node.js with in-memory and Redis stores.
npm install limiximport { Algorithms, MemoryStore, createRateLimiter } from 'limix';
const limiter = createRateLimiter({
algorithm: Algorithms.FIXED_WINDOW,
limit: 100,
windowMs: 60_000,
store: new MemoryStore(),
});
const result = await limiter.consume('tenant:acme');result contains allowed, integer remaining, epoch-millisecond resetAt,
and retryAfterMs (0 when allowed).
Algorithms
- Fixed window is inexpensive but permits bursts across adjacent boundaries.
- Sliding window weights the previous epoch-aligned chunk and includes the incoming request before admission. It is a constant-space approximation; its error is bounded by the previous chunk's request count.
- Token bucket permits bursts up to
limitand refills from empty to full overwindowMs. ItsresetAtis the full-refill time after the current decision.
Memory
Use new MemoryStore() so state ownership is explicit. It is bounded, removes
expired entries opportunistically, and exposes cleanup() and clear().
Memory state is local to one process and is not suitable for distributed limits.
Redis
Install the Redis client you intend to use (for example, npm install ioredis),
then pass it to the store:
import Redis from 'ioredis';
import { RedisStore } from 'limix';
const redis = new Redis(process.env.REDIS_URL!);
const store = new RedisStore(redis, { keyPrefix: 'billing-api' });Redis decisions are atomic and use Redis server time. Identifiers are hashed; keys are isolated by prefix, algorithm, limit, and window. Use a different prefix for independently enforced policies with otherwise identical settings. The application owns the Redis client, connection timeouts, retries, and shutdown.
Failures
Library errors expose a stable code. Configuration failures use
RateLimiterConfigurationError; memory capacity, Redis command, and malformed
Redis response failures use RateLimiterStoreError with an operation field.
Limix does not retry ambiguous Redis decisions. Choose fail-open or fail-closed
handling in the application based on endpoint risk.
For HTTP responses, use Math.ceil(result.retryAfterMs / 1000) for
Retry-After when denied. Node.js 18+, ESM, CommonJS, and TypeScript are
supported. Public behavior follows semantic versioning.
