{"id":27070288,"url":"https://github.com/stacksjs/ts-rate-limiter","last_synced_at":"2025-04-12T15:53:31.589Z","repository":{"id":286321071,"uuid":"961055715","full_name":"stacksjs/ts-rate-limiter","owner":"stacksjs","description":"A high-performance, flexible rate limiting library for TypeScript.","archived":false,"fork":false,"pushed_at":"2025-04-11T00:09:25.000Z","size":2158,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-11T15:06:07.081Z","etag":null,"topics":["bun","library","rate-limit","rate-limiter","rate-limiting","typescript"],"latest_commit_sha":null,"homepage":"https://ts-rate-limiter.netlify.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stacksjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["stacksjs","chrisbbreuer"],"open_collective":"stacksjs"}},"created_at":"2025-04-05T16:53:28.000Z","updated_at":"2025-04-06T19:10:32.000Z","dependencies_parsed_at":"2025-04-11T12:07:56.273Z","dependency_job_id":null,"html_url":"https://github.com/stacksjs/ts-rate-limiter","commit_stats":null,"previous_names":["stacksjs/ts-rate-limiter"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fts-rate-limiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fts-rate-limiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fts-rate-limiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stacksjs%2Fts-rate-limiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stacksjs","download_url":"https://codeload.github.com/stacksjs/ts-rate-limiter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248592206,"owners_count":21130206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","library","rate-limit","rate-limiter","rate-limiting","typescript"],"created_at":"2025-04-05T22:20:15.609Z","updated_at":"2025-04-12T15:53:31.562Z","avatar_url":"https://github.com/stacksjs.png","language":"TypeScript","funding_links":["https://github.com/sponsors/stacksjs","https://github.com/sponsors/chrisbbreuer","https://opencollective.com/stacksjs"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\".github/art/cover.jpg\" alt=\"Social Card of this repo\"\u003e\u003c/p\u003e\n\n[![npm version][npm-version-src]][npm-version-href]\n[![GitHub Actions][github-actions-src]][github-actions-href]\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\u003c!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] --\u003e\n\u003c!-- [![Codecov][codecov-src]][codecov-href] --\u003e\n\n# ts-rate-limiter\n\nA high-performance, flexible rate limiting library for TypeScript and Bun.\n\n## Features\n\n- **Multiple Rate Limiting Algorithms**:\n  - Fixed Window\n  - Sliding Window\n  - Token Bucket\n\n- **Storage Providers**:\n  - In-memory storage (default)\n  - Redis storage\n\n- **Performance Optimizations**:\n  - Batch operations\n  - LUA scripting for Redis\n  - Automatic cleanup of expired records\n\n- **Flexible Configuration**:\n  - Custom key generators\n  - Skip and handler functions\n  - Draft mode (record but don't block)\n  - Standard and legacy headers\n\n## Installation\n\n```bash\nbun add ts-rate-limiter\n```\n\n## Basic Usage\n\n```ts\nimport { RateLimiter } from 'ts-rate-limiter'\n\n// Create a rate limiter with 100 requests per minute\nconst limiter = new RateLimiter({\n  windowMs: 60 * 1000, // 1 minute\n  maxRequests: 100 // limit each IP to 100 requests per windowMs\n})\n\n// In your Bun server\nconst server = Bun.serve({\n  port: 3000,\n  async fetch(req) {\n    // Use as middleware\n    const limiterResponse = await limiter.middleware()(req)\n    if (limiterResponse) {\n      return limiterResponse\n    }\n\n    // Continue with your normal request handling\n    return new Response('Hello World')\n  }\n})\n```\n\n## Configuration Options\n\n```ts\n// Create a rate limiter with more options\nconst limiter = new RateLimiter({\n  windowMs: 15 * 60 * 1000, // 15 minutes\n  maxRequests: 100, // limit each IP to 100 requests per windowMs\n  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers\n  legacyHeaders: false, // Disable the `X-RateLimit-*` headers\n  algorithm: 'sliding-window', // 'fixed-window', 'sliding-window', or 'token-bucket'\n\n  // Skip certain requests\n  skip: (request) =\u003e {\n    return request.url.includes('/api/health')\n  },\n\n  // Custom handler for rate-limited requests\n  handler: (request, result) =\u003e {\n    return new Response('Too many requests, please try again later.', {\n      status: 429,\n      headers: {\n        'Retry-After': Math.ceil(result.remaining / 1000).toString()\n      }\n    })\n  },\n\n  // Custom key generator\n  keyGenerator: (request) =\u003e {\n    // Use user ID if available, otherwise fall back to IP\n    const userId = getUserIdFromRequest(request)\n    return userId || request.headers.get('x-forwarded-for') || '127.0.0.1'\n  },\n\n  // Draft mode - don't actually block requests, just track them\n  draftMode: process.env.NODE_ENV !== 'production'\n})\n```\n\n## Using Redis Storage\n\n```ts\nimport { RateLimiter, RedisStorage } from 'ts-rate-limiter'\n\n// Create Redis client\nconst redis = createRedisClient() // Use your Redis client library\n\n// Create Redis storage\nconst storage = new RedisStorage({\n  client: redis,\n  keyPrefix: 'ratelimit:',\n  enableSlidingWindow: true\n})\n\n// Create rate limiter with Redis storage\nconst limiter = new RateLimiter({\n  windowMs: 60 * 1000,\n  maxRequests: 100,\n  storage\n})\n```\n\n## Distributed Rate Limiting\n\nFor applications running on multiple servers, use Redis storage to ensure consistent rate limiting:\n\n```ts\nimport { createClient } from 'redis'\nimport { RateLimiter, RedisStorage } from 'ts-rate-limiter'\n\n// Create and connect Redis client\nconst redisClient = createClient({\n  url: 'redis://redis-server:6379'\n})\nawait redisClient.connect()\n\n// Create Redis storage with sliding window for more accuracy\nconst storage = new RedisStorage({\n  client: redisClient,\n  keyPrefix: 'app:ratelimit:',\n  enableSlidingWindow: true\n})\n\n// Create rate limiter with Redis storage\nconst limiter = new RateLimiter({\n  windowMs: 60 * 1000,\n  maxRequests: 100,\n  storage,\n  algorithm: 'sliding-window'\n})\n\n// Make sure to handle Redis errors\nredisClient.on('error', (err) =\u003e {\n  console.error('Redis error:', err)\n  // You might want to fall back to memory storage in case of Redis failure\n})\n```\n\n## Best Practices\n\n### Choosing the Right Algorithm\n\n- **Fixed Window**: Simplest approach, best for non-critical rate limiting with good performance\n- **Sliding Window**: More accurate, prevents traffic spikes at window boundaries\n- **Token Bucket**: Best for APIs that need to allow occasional bursts of traffic\n\n### Performance Considerations\n\n- Use memory storage for single-instance applications\n- Use Redis storage for distributed applications\n- Enable automatic cleanup for long-running applications:\n\n  ```ts\n  const memoryStorage = new MemoryStorage({\n    enableAutoCleanup: true,\n    cleanupIntervalMs: 60000 // cleanup every minute\n  })\n  ```\n\n- Use batch operations for bulk processing:\n\n  ```ts\n  // Process multiple keys at once\n  const results = await storage.batchIncrement(['key1', 'key2', 'key3'], windowMs)\n  ```\n\n### Rate Limiting by User or IP\n\nBy default, the rate limiter uses IP addresses. For user-based rate limiting:\n\n```ts\nconst userRateLimiter = new RateLimiter({\n  windowMs: 60 * 1000,\n  maxRequests: 100,\n  keyGenerator: (request) =\u003e {\n    // Extract user ID from auth token, session, etc.\n    const userId = getUserIdFromRequest(request)\n    if (!userId) {\n      throw new Error('User not authenticated')\n    }\n    return `user:${userId}`\n  },\n  skipFailedRequests: true // Allow unauthenticated requests to bypass rate limiting\n})\n```\n\n## Benchmarks\n\nPerformance comparison of different algorithms and storage providers:\n\n| Algorithm | Storage | Requests/sec | Latency (avg) |\n|-----------|---------|--------------|---------------|\n| Fixed Window | Memory | 2,742,597 | 0.000365ms |\n| Sliding Window | Memory | 10,287 | 0.097203ms |\n| Token Bucket | Memory | 5,079,977 | 0.000197ms |\n| Fixed Window | Redis | 10,495 | 0.095277ms |\n| Sliding Window | Redis | 1,843 | 0.542406ms |\n| Token Bucket | Redis | 4,194,263 | 0.000238ms |\n\n*Benchmarked on Bun v1.2.9, MacBook Pro M3, 100,000 requests per test for Memory, 10,000 requests per test for Redis. All tests performed with Redis running locally.*\n\n## Algorithms\n\n### Fixed Window\n\nThe traditional rate limiting approach that counts requests in a fixed time window.\n\n### Sliding Window\n\nMore accurate limiting by considering the distribution of requests within the window.\n\n### Token Bucket\n\nOffers a smoother rate limiting experience by focusing on request rates rather than fixed counts.\n\n## Testing\n\n```bash\nbun test\n```\n\n## Changelog\n\nPlease see our [releases](https://github.com/stackjs/ts-rate-limiter/releases) page for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.\n\n## Community\n\nFor help, discussion about best practices, or any other conversation that would benefit from being searchable:\n\n[Discussions on GitHub](https://github.com/stacksjs/ts-rate-limiter/discussions)\n\nFor casual chit-chat with others using this package:\n\n[Join the Stacks Discord Server](https://discord.gg/stacksjs)\n\n## Postcardware\n\n\"Software that is free, but hopes for a postcard.\" We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.\n\nOur address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎\n\n## Sponsors\n\nWe would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.\n\n- [JetBrains](https://www.jetbrains.com/)\n- [The Solana Foundation](https://solana.com/)\n\n## License\n\nThe MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.\n\nMade with 💙\n\n\u003c!-- Badges --\u003e\n[npm-version-src]: https://img.shields.io/npm/v/ts-rate-limiter?style=flat-square\n[npm-version-href]: https://npmjs.com/package/ts-rate-limiter\n[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/ts-rate-limiter/ci.yml?style=flat-square\u0026branch=main\n[github-actions-href]: https://github.com/stacksjs/ts-rate-limiter/actions?query=workflow%3Aci\n\n\u003c!-- [codecov-src]: https://img.shields.io/codecov/c/gh/stacksjs/ts-rate-limiter/main?style=flat-square\n[codecov-href]: https://codecov.io/gh/stacksjs/ts-rate-limiter --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstacksjs%2Fts-rate-limiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstacksjs%2Fts-rate-limiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstacksjs%2Fts-rate-limiter/lists"}