Skip to content

arraypress/rate-limit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@arraypress/rate-limit

Window-based rate limiting with atomic increment and probabilistic cleanup. Storage-agnostic — works with D1, SQLite, Redis, or in-memory. Zero dependencies.

Installation

npm install @arraypress/rate-limit

Usage

import { checkRateLimit, rateLimitKey, rateLimitError, createMemoryStore } from '@arraypress/rate-limit';

const store = createMemoryStore(); // Or your D1/Redis adapter

// Check rate limit: 3 requests per 5 minutes
const ip = request.headers.get('CF-Connecting-IP');
const result = await checkRateLimit(store, rateLimitKey(ip, '/login'), 3, 300);

if (!result.allowed) {
  return new Response(JSON.stringify(rateLimitError(result.retryAfter)), {
    status: 429,
    headers: { 'Retry-After': String(result.retryAfter) },
  });
}

D1/SQLite Store Example

CREATE TABLE rate_limits (key TEXT, window TEXT, count INTEGER DEFAULT 1, PRIMARY KEY (key, window));
CREATE INDEX idx_rate_limits_window ON rate_limits(window);
const d1Store = {
  async increment(key, windowStart) {
    const r = await db.prepare(
      `INSERT INTO rate_limits (key, window, count) VALUES (?, ?, 1)
       ON CONFLICT(key, window) DO UPDATE SET count = count + 1 RETURNING count`
    ).bind(key, windowStart).first();
    return r.count;
  },
  async cleanup(cutoff) {
    const r = await db.prepare('DELETE FROM rate_limits WHERE window < ?').bind(cutoff).run();
    return r.changes;
  },
};

API

checkRateLimit(store, key, maxRequests, windowSeconds)

Check rate limit. Returns { allowed, count, limit, retryAfter }. Runs probabilistic cleanup (1% chance per call).

rateLimitKey(ip, endpoint)

Build a composite key: '1.2.3.4:/login'.

getWindowStart(timestampMs, windowSeconds)

Calculate the window start timestamp for time-bucketing.

rateLimitError(retryAfter)

Create a { error, message, retryAfter } response body.

createMemoryStore()

In-memory store for testing and single-instance use.

Store Interface

interface RateLimitStore {
  increment(key: string, windowStart: string): Promise<number>;
  cleanup(cutoffTime: string): Promise<number>;
}

License

MIT

About

Window-based rate limiting with atomic increment and probabilistic cleanup. Storage-agnostic. Zero dependencies.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors