/superrate

Primary LanguageTypeScript

Rate Limit Library

A flexible TypeScript rate limiting library with multiple algorithms and storage adapters for Node.js applications.

Features

  • 🎯 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

Installation

```bash npm install rate-limit-lib ```

For specific adapters, install the required dependencies:

```bash

For SQLite

npm install better-sqlite3

For Redis

npm install redis ```

Quick Start

```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!'); } ```

Rate Limiting Algorithms

Sliding Window (Default)

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

Token Bucket

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

Leaky Bucket

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

Fixed Window

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

Sliding Window Counter

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

Storage Adapters

Memory Store

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 }); ```

SQLite Store

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(); ```

Redis Store

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(); ```

API Reference

RateLimit

Constructor

```typescript new RateLimit(store: RateLimitStore, config: RateLimitConfig) ```

Methods

  • isHit(key: string): Promise<boolean> - Check if rate limit is exceeded
  • trackHit(key: string): Promise<void> - Record a hit
  • reset(key: string): Promise<void> - Reset rate limit for a key
  • attempt(key: string): Promise<boolean> - Check and track in one operation

RateLimitConfig

```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'; ```

RateLimitStore Interface

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 }>; } ```

Use Cases

API Rate Limiting

```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(); }); ```

Login Attempt Limiting

```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... }); ```

Smooth Traffic Shaping

```typescript // Process requests at steady rate const trafficShaper = new RateLimit(store, { maxHits: 100, intervalMs: 60000, algorithm: 'leaky-bucket', leakRate: 10, // 10 requests per second }); ```

Development

```bash

Install dependencies

npm install

Run tests

npm test

Run tests in watch mode

npm run test:watch

Lint and format

npm run lint npm run format

Build

npm run build ```

License

MIT