@chaisser/rate-limiter
v1.0.0
Published
In-memory rate limiter
Maintainers
Readme
⏱️ @chaisser/rate-limiter
A lightweight, zero-dependency, TypeScript-first in-memory rate limiting library. Fixed window, sliding window, and token bucket algorithms out of the box.
✨ Features
- 🔒 Fixed Window Rate Limiter - Classic fixed-window rate limiting per key
- 🪟 Sliding Window Rate Limiter - True sliding window with individual timestamp tracking
- 🪣 Token Bucket - Token bucket algorithm with automatic refill and async wait
- 🗝️ Per-Key Isolation - Rate limit independently per key
- 📊 Stats & Introspection - Query remaining requests, reset times, and token counts
- 🪶 Zero Dependencies - No runtime dependencies, tiny bundle size
- 🔷 Full TypeScript - Complete type safety with exported interfaces
- ⚡ ESM & CJS - Dual module support
📦 Installation
npm install @chaisser/rate-limiter🚀 Quick Start
import { RateLimiter } from '@chaisser/rate-limiter';
const limiter = new RateLimiter({ windowMs: 60_000, maxRequests: 100 });
if (limiter.tryAcquire('user-123')) {
// Request allowed
} else {
// Rate limit exceeded
}📖 What It Does
@chaisser/rate-limiter provides in-memory rate limiting primitives for Node.js applications. It offers three complementary algorithms:
- RateLimiter - Fixed window rate limiter. Tracks request counts per time window per key. Simple and efficient.
- SlidingWindowLimiter - True sliding window limiter. Tracks individual request timestamps and removes expired ones, providing more accurate rate limiting.
- TokenBucket - Token bucket algorithm. Tokens refill over time at a steady rate. Supports async waiting for token availability.
📚 Usage Examples
Fixed Window Rate Limiter
import { RateLimiter } from '@chaisser/rate-limiter';
const limiter = new RateLimiter({
windowMs: 60_000, // 1 minute window
maxRequests: 100, // max 100 requests per window
});
// Check and consume
if (limiter.tryAcquire('user-123')) {
handleRequest();
} else {
rejectWith429();
}
// Introspection
console.log(limiter.getRemaining('user-123')); // remaining requests
console.log(limiter.getResetTime('user-123')); // ms until window resets
// Reset
limiter.reset('user-123');
limiter.resetAll();Sliding Window Rate Limiter
import { SlidingWindowLimiter } from '@chaisser/rate-limiter';
const limiter = new SlidingWindowLimiter({
windowMs: 60_000,
maxRequests: 100,
});
// Same API as RateLimiter but uses true sliding window
if (limiter.tryAcquire('api-key')) {
handleRequest();
}Token Bucket
import { TokenBucket } from '@chaisser/rate-limiter';
const bucket = new TokenBucket({
capacity: 10, // max 10 tokens
refillRate: 2, // 2 tokens per second
});
// Consume tokens
if (bucket.tryConsume(3)) {
processRequest();
}
// Async wait for tokens
await bucket.tryConsumeWithWait(5); // waits until 5 tokens available
// Check available tokens
console.log(bucket.getTokens());Factory Function
import { createRateLimiter } from '@chaisser/rate-limiter';
const limiter = createRateLimiter({ windowMs: 1000, maxRequests: 10 });
limiter.tryAcquire();📋 API Reference
RateLimiter
| Method | Description |
|--------|-------------|
| new RateLimiter(options) | Create a new fixed window rate limiter |
| tryAcquire(key?) | Attempt to acquire a request slot. Returns true if allowed |
| getRemaining(key?) | Get remaining requests in the current window |
| getResetTime(key?) | Get ms until the current window resets |
| reset(key?) | Reset rate limit for a specific key |
| resetAll() | Reset all keys |
SlidingWindowLimiter
| Method | Description |
|--------|-------------|
| new SlidingWindowLimiter(options) | Create a new sliding window rate limiter |
| tryAcquire(key?) | Attempt to acquire a request slot |
| getRemaining(key?) | Get remaining requests in the current window |
| getResetTime(key?) | Get ms until the oldest request expires |
| reset(key?) | Reset rate limit for a specific key |
| resetAll() | Reset all keys |
TokenBucket
| Method | Description |
|--------|-------------|
| new TokenBucket(options) | Create a new token bucket |
| tryConsume(tokens?) | Consume tokens, returns false if not enough |
| tryConsumeWithWait(tokens?) | Wait and retry until tokens are available |
| getTokens() | Get current available tokens |
| refill() | Manually trigger refill based on elapsed time |
Interfaces
| Interface | Fields |
|-----------|--------|
| RateLimiterOptions | windowMs: number, maxRequests: number |
| TokenBucketOptions | capacity: number, refillRate: number |
| RateLimiterStats | allowed: number, rejected: number, total: number |
Functions
| Function | Returns |
|----------|---------|
| createRateLimiter(options) | RateLimiter instance |
🔗 Related Packages
| Package | Description |
|---------|-------------|
| @chaisser/chunk-array | Array chunking utility |
| @chaisser/string-wizard | String manipulation library |
| @chaisser/type-guard | Runtime type guards |
| @chaisser/uuid-v7 | UUIDv7 generation |
| @chaisser/wait-for | Async wait utilities |
| @chaisser/regex-humanizer | Regex to human-readable |
| @chaisser/password-strength | Password strength checker |
| @chaisser/human-time | Human-readable time formatting |
| @chaisser/obj-path | Deep object path access |
| @chaisser/debounce-throttle | Debounce and throttle utilities |
| @chaisser/color-utils | Color manipulation utilities |
| @chaisser/deep-clone | Deep cloning utility |
| @chaisser/array-group-by | Array groupBy utility |
| @chaisser/merge-objects | Deep object merging |
| @chaisser/event-emitter | Type-safe event emitter |
| @chaisser/unique-by | Array unique-by utility |
| @chaisser/memoize | Function memoization |
| @chaisser/base64-url | Base64 URL encoding/decoding |
| @chaisser/ip-regex | IP address regex patterns |
| @chaisser/retry-async | Async retry utility |
| @chaisser/circuit-breaker | Circuit breaker pattern |
| @chaisser/query-string | Query string parser |
| @chaisser/cookie-parser | Cookie parsing utility |
📄 License
MIT
👤 Developed by
Doruk Karaboncuk - [email protected]
Repository: github.com/Chaisser/rate-limiter
