A flexible TypeScript rate limiting library with multiple algorithms and storage adapters for Node.js applications.
- 🎯 Simple and intuitive API
- 🔌 Multiple rate limiting algorithms (Sliding Window, Token Bucket, Leaky Bucket, Fixed Window, Sliding Window Counter)
- 💾 Pluggable storage adapters (Memory, SQLite, Redis)
- 📦 Written in TypeScript with full type safety
- âš¡ ESM modules
- 🧪 Comprehensive test coverage
- 🎨 Formatted with Biome
```bash npm install rate-limit-lib ```
For specific adapters, install the required dependencies:
```bash
npm install better-sqlite3
npm install redis ```
```typescript import { RateLimit, MemoryRateLimitStore } from 'rate-limit-lib';
// Create a rate limiter with in-memory storage const store = new MemoryRateLimitStore(); const rateLimit = new RateLimit(store, { maxHits: 10, // Allow 10 requests intervalMs: 60000, // Per 60 seconds (1 minute) });
// Check and track a request const userId = 'user123';
if (await rateLimit.isHit(userId)) { console.log('Rate limit exceeded!'); } else { await rateLimit.trackHit(userId); console.log('Request allowed'); }
// Or use the convenient attempt method const allowed = await rateLimit.attempt(userId); if (!allowed) { console.log('Rate limit exceeded!'); } ```
Tracks individual hits with timestamps. Most accurate but requires more storage.
```typescript const rateLimit = new RateLimit(store, { maxHits: 100, intervalMs: 60000, algorithm: 'sliding-window', // or omit for default }); ```
Pros: Most accurate, no burst issues Cons: Higher memory usage, more complex
Tokens refill at a constant rate. Requests consume tokens. Allows controlled bursts.
```typescript const rateLimit = new RateLimit(store, { maxHits: 100, // Bucket capacity intervalMs: 60000, // Refill interval algorithm: 'token-bucket', }); ```
Pros: Allows bursts, smooth rate limiting Cons: Can allow bursts up to bucket size
Processes requests at a constant rate. Excess requests are queued (or rejected if queue is full).
```typescript const rateLimit = new RateLimit(store, { maxHits: 100, // Queue capacity intervalMs: 60000, // Time window algorithm: 'leaky-bucket', leakRate: 10, // Process 10 requests per second }); ```
Pros: Smooth, predictable rate Cons: No bursts allowed, may delay valid requests
Simple counter that resets at fixed intervals. Fast but can allow bursts at window boundaries.
```typescript const rateLimit = new RateLimit(store, { maxHits: 100, intervalMs: 60000, algorithm: 'fixed-window', }); ```
Pros: Simple, fast, low memory Cons: Burst issues at window boundaries
Hybrid approach using weighted counts from current and previous windows. Good balance of accuracy and performance.
```typescript const rateLimit = new RateLimit(store, { maxHits: 100, intervalMs: 60000, algorithm: 'sliding-window-counter', }); ```
Pros: Good accuracy, lower memory than sliding window Cons: Approximation, not perfectly accurate
Best for single-process applications or testing.
```typescript import { RateLimit, MemoryRateLimitStore } from 'rate-limit-lib';
const store = new MemoryRateLimitStore(); const rateLimit = new RateLimit(store, { maxHits: 100, intervalMs: 3600000, // 1 hour }); ```
Best for persistent storage in single-server applications.
```typescript import { RateLimit, SqliteRateLimitStore } from 'rate-limit-lib';
const store = new SqliteRateLimitStore('./rate-limits.db'); const rateLimit = new RateLimit(store, { maxHits: 100, intervalMs: 3600000, });
// Don't forget to close the connection when done store.close(); ```
Best for distributed applications with multiple servers.
```typescript import { RateLimit, RedisRateLimitStore } from 'rate-limit-lib';
const store = new RedisRateLimitStore('redis://localhost:6379'); await store.connect();
const rateLimit = new RateLimit(store, { maxHits: 100, intervalMs: 3600000, });
// Don't forget to disconnect when done await store.disconnect(); ```
```typescript new RateLimit(store: RateLimitStore, config: RateLimitConfig) ```
isHit(key: string): Promise<boolean>- Check if rate limit is exceededtrackHit(key: string): Promise<void>- Record a hitreset(key: string): Promise<void>- Reset rate limit for a keyattempt(key: string): Promise<boolean>- Check and track in one operation
```typescript interface RateLimitConfig { maxHits: number; // Maximum hits allowed intervalMs: number; // Time window in milliseconds algorithm?: RateLimitAlgorithm; // Algorithm to use (default: 'sliding-window') leakRate?: number; // For leaky-bucket: requests per second }
type RateLimitAlgorithm = | 'sliding-window' | 'token-bucket' | 'leaky-bucket' | 'fixed-window' | 'sliding-window-counter'; ```
All storage adapters implement this interface:
```typescript interface RateLimitStore { getHits(key: string, windowStart: number): Promise; recordHit(key: string, timestamp: number): Promise; reset(key: string): Promise; cleanup?(olderThan: number): Promise; getBucketState(key: string): Promise<BucketState | null>; setBucketState(key: string, state: BucketState): Promise; getWindowCounter(key: string): Promise<WindowCounter | null>; setWindowCounter(key: string, counter: WindowCounter): Promise; incrementWindowCounter(key: string, windowStart: number): Promise<{ count: number; windowStart: number }>; } ```
```typescript // Limit API requests per user const apiLimiter = new RateLimit(store, { maxHits: 1000, intervalMs: 3600000, // 1 hour algorithm: 'sliding-window', });
app.use(async (req, res, next) => { const userId = req.user.id;
if (await apiLimiter.isHit(userId)) { return res.status(429).json({ error: 'Rate limit exceeded' }); }
await apiLimiter.trackHit(userId); next(); }); ```
```typescript // Prevent brute force attacks const loginLimiter = new RateLimit(store, { maxHits: 5, intervalMs: 900000, // 15 minutes algorithm: 'fixed-window', });
app.post('/login', async (req, res) => { const ip = req.ip;
if (!await loginLimiter.attempt(ip)) { return res.status(429).json({ error: 'Too many login attempts' }); }
// Process login... }); ```
```typescript // Process requests at steady rate const trafficShaper = new RateLimit(store, { maxHits: 100, intervalMs: 60000, algorithm: 'leaky-bucket', leakRate: 10, // 10 requests per second }); ```
```bash
npm install
npm test
npm run test:watch
npm run lint npm run format
npm run build ```
MIT