{"_id":"@debasish-debnath/ratelimiter","_rev":"2-10897c9b30f6604fccffae823d494127","name":"@debasish-debnath/ratelimiter","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@debasish-debnath/ratelimiter","version":"1.0.0","keywords":["rate-limit","rate-limiter","token-bucket","typescript","node","express","middleware","backend","api","security"],"author":{"name":"Debasish Debnath"},"license":"MIT","_id":"@debasish-debnath/ratelimiter@1.0.0","maintainers":[{"name":"debasish-debnath","email":"debasish03debnath@gmail.com"}],"homepage":"https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts","bugs":{"url":"https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts/issues"},"dist":{"shasum":"8fbccb526d6109ccc55158e2bac54289b3709ba0","tarball":"https://registry.npmjs.org/@debasish-debnath/ratelimiter/-/ratelimiter-1.0.0.tgz","fileCount":9,"integrity":"sha512-xiTM5rv1/A6UZECKVDbj4Zdoh+DaqVMi3ta0ygfp0RNmcTuj+p/uSXqFCyXgWzMyMohvbLiZDuc22I6SqP+/Cg==","signatures":[{"sig":"MEUCIQCiJxaBHKPhG6yVYD6avhtpY1Xi1M3UEjSqY+zb2aL8JAIgUHLIdvECpPF9uZx9+vNzaaHSow89PJsvXPGS/DmPUjE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76025},"main":"./dist/index.cjs","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"d2d796a5db06d997598b394e5c5994cff9727969","scripts":{"dev":"tsup --watch","docs":"typedoc src/index.ts","test":"vitest","build":"tsup","typecheck":"tsc --noEmit","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"debasish-debnath","email":"debasish03debnath@gmail.com"},"repository":{"url":"git+https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts.git","type":"git"},"_npmVersion":"10.8.2","description":"Production-grade Token Bucket Rate Limiter for Node.js and TypeScript","directories":{},"sideEffects":false,"_nodeVersion":"20.19.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.9","express":"^5.2.1","typedoc":"^0.28.20","typescript":"5.9.2","@types/node":"^26.1.0","@types/express":"^5.0.6","@vitest/coverage-v8":"^4.1.10"},"peerDependencies":{"express":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ratelimiter_1.0.0_1783344736224_0.616375990322882","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@debasish-debnath/ratelimiter","version":"1.0.1","description":"Production-grade Token Bucket Rate Limiter for Node.js and TypeScript","license":"MIT","author":{"name":"Debasish Debnath"},"homepage":"https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts","repository":{"type":"git","url":"git+https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts.git"},"bugs":{"url":"https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts/issues"},"keywords":["rate-limit","rate-limiter","token-bucket","typescript","node","express","middleware","backend","api","security"],"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"sideEffects":false,"engines":{"node":">=18"},"publishConfig":{"access":"public"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"vitest","test:coverage":"vitest run --coverage","docs":"typedoc src/index.ts"},"peerDependencies":{"express":"^5.0.0"},"devDependencies":{"@types/express":"^5.0.6","@types/node":"^26.1.0","@vitest/coverage-v8":"^4.1.10","express":"^5.2.1","tsup":"^8.5.1","typedoc":"^0.28.20","typescript":"5.9.2","vitest":"^4.1.9"},"_id":"@debasish-debnath/ratelimiter@1.0.1","gitHead":"38c07406b4cdeb14ce6114c15f25b63f4d540b37","_nodeVersion":"20.19.3","_npmVersion":"10.8.2","dist":{"integrity":"sha512-ELhDYOOUizI5tmJK3vtTzudoRZEZvfxvsZcW7doMUfOktlsq0m2g+fs596g8DyaR7oEObZaB0e3ai5seEU8AAQ==","shasum":"ba0fddceab3487b05fedb86f5fef7dbf27bc5bcf","tarball":"https://registry.npmjs.org/@debasish-debnath/ratelimiter/-/ratelimiter-1.0.1.tgz","fileCount":9,"unpackedSize":77908,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHaMhmM7LTqN6loCMN83Gw03uT74EkqgBNsujJUIDUCLAiBpiF4U3ClHr0XfG+/+OpGVkUVMLXt0CDBxOT0cIfU6XA=="}]},"_npmUser":{"name":"debasish-debnath","email":"debasish03debnath@gmail.com"},"directories":{},"maintainers":[{"name":"debasish-debnath","email":"debasish03debnath@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ratelimiter_1.0.1_1783345515584_0.2888080912990547"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-06T13:32:16.037Z","modified":"2026-07-06T13:45:15.847Z","1.0.0":"2026-07-06T13:32:16.365Z","1.0.1":"2026-07-06T13:45:15.718Z"},"bugs":{"url":"https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts/issues"},"author":{"name":"Debasish Debnath"},"license":"MIT","homepage":"https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts","keywords":["rate-limit","rate-limiter","token-bucket","typescript","node","express","middleware","backend","api","security"],"repository":{"type":"git","url":"git+https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts.git"},"description":"Production-grade Token Bucket Rate Limiter for Node.js and TypeScript","maintainers":[{"name":"debasish-debnath","email":"debasish03debnath@gmail.com"}],"readme":"# Token Bucket Rate Limiter\r\n\r\n[![npm version](https://img.shields.io/npm/v/@debasish-debnath/ratelimiter)](https://www.npmjs.com/package/@debasish-debnath/ratelimiter)\r\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\r\n[![CI](https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts/actions)\r\n\r\nA TypeScript implementation of the **Token Bucket** rate limiting algorithm for Node.js applications.\r\n\r\nThe library is designed with clean architecture principles and separates the rate limiting algorithm from storage, locking, cleanup, and time management through interfaces, making it easy to test, extend, and maintain.\r\n\r\n---\r\n\r\n## Features\r\n\r\n- Token Bucket rate limiting algorithm\r\n- Fractional token refill\r\n- Per-key rate limiting\r\n- Asynchronous per-key locking\r\n- Automatic cleanup of idle buckets\r\n- Clock abstraction for deterministic testing\r\n- Fake clock for unit testing\r\n- Express middleware\r\n- Dependency injection support\r\n- TypeScript-first API\r\n- ESM and CommonJS support\r\n- High unit test coverage\r\n\r\n---\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @debasish-debnath/ratelimiter\r\n```\r\n\r\nor\r\n\r\n```bash\r\npnpm add @debasish-debnath/ratelimiter\r\n```\r\n\r\n---\r\n\r\n# Quick Start\r\n\r\n```ts\r\nimport { TokenBucket } from \"@debasish-debnath/ratelimiter\";\r\n\r\nconst limiter = new TokenBucket({\r\n    capacity: 10,\r\n    refillRate: 5,\r\n\r\n    cleanup: {\r\n        cleanupInterval: 60_000,\r\n        maxIdleTime: 300_000,\r\n    },\r\n});\r\n\r\nconst result = await limiter.consume(\"user-123\");\r\n\r\nconsole.log(result);\r\n```\r\n\r\nExample output:\r\n\r\n```ts\r\n{\r\n    allowed: true,\r\n    remainingTokens: 9,\r\n    retryAfter: null,\r\n    limit: 10,\r\n    resetAfter: 0\r\n}\r\n```\r\n\r\n---\r\n\r\n# Express Middleware\r\n\r\n```ts\r\nimport express from \"express\";\r\nimport {\r\n    TokenBucket,\r\n    rateLimit,\r\n} from \"@debasish-debnath/ratelimiter\";\r\n\r\nconst app = express();\r\n\r\nconst limiter = new TokenBucket({\r\n    capacity: 20,\r\n    refillRate: 5,\r\n\r\n    cleanup: {\r\n        cleanupInterval: 60_000,\r\n        maxIdleTime: 300_000,\r\n    },\r\n});\r\n\r\napp.use(rateLimit(limiter));\r\n\r\napp.get(\"/\", (_, res) => {\r\n    res.send(\"Hello World\");\r\n});\r\n\r\napp.listen(3000);\r\n```\r\n\r\n---\r\n\r\n# Configuration\r\n\r\n```ts\r\nnew TokenBucket({\r\n    capacity: 10,\r\n    refillRate: 5,\r\n\r\n    cleanup: {\r\n        cleanupInterval: 60_000,\r\n        maxIdleTime: 300_000,\r\n    },\r\n});\r\n```\r\n\r\n| Option | Description |\r\n|---------|-------------|\r\n| capacity | Maximum number of tokens in a bucket |\r\n| refillRate | Tokens added per second |\r\n| cleanup.cleanupInterval | Interval between cleanup cycles (ms) |\r\n| cleanup.maxIdleTime | Idle time before a bucket is removed (ms) |\r\n\r\n---\r\n\r\n# API\r\n\r\n## consume(key)\r\n\r\nConsumes one token from the bucket associated with the supplied key.\r\n\r\n```ts\r\nconst result = await limiter.consume(\"user-123\");\r\n```\r\n\r\nReturns\r\n\r\n```ts\r\ninterface ConsumeResult {\r\n    allowed: boolean;\r\n    remainingTokens: number;\r\n    retryAfter: number | null;\r\n    limit: number;\r\n    resetAfter: number;\r\n}\r\n```\r\n\r\n---\r\n\r\n## destroy()\r\n\r\nStops the background cleanup service.\r\n\r\n```ts\r\nlimiter.destroy();\r\n```\r\n\r\nThis should be called before shutting down the application.\r\n\r\n---\r\n\r\n# Architecture\r\n\r\n```\r\n                 Express Middleware\r\n                         │\r\n                         ▼\r\n                  RateLimiter Interface\r\n                         ▲\r\n                         │\r\n                  TokenBucket\r\n                         │\r\n        ┌────────────────┼────────────────┐\r\n        │                │                │\r\n        ▼                ▼                ▼\r\n BucketStorage      LockManager        Clock\r\n        │                                │\r\n        ▼                                ▼\r\n BucketCleanup                   FakeClock/SystemClock\r\n```\r\n\r\n---\r\n\r\n# Project Structure\r\n\r\n```\r\nsrc\r\n├── bucket\r\n│   ├── interfaces\r\n│   ├── BucketCleanup.ts\r\n│   ├── BucketStorage.ts\r\n│   ├── LockManager.ts\r\n│   ├── TokenBucket.ts\r\n│   └── index.ts\r\n│\r\n├── clock\r\n│   ├── Clock.ts\r\n│   ├── FakeClock.ts\r\n│   ├── SystemClock.ts\r\n│   └── index.ts\r\n│\r\n├── middleware\r\n│\r\n├── common\r\n│\r\n└── index.ts\r\n```\r\n\r\n---\r\n\r\n# Design Principles\r\n\r\nThe project follows a modular architecture where each component has a single responsibility.\r\n\r\n### TokenBucket\r\n\r\nOwns the rate limiting algorithm.\r\n\r\n### BucketStorage\r\n\r\nResponsible only for bucket persistence.\r\n\r\n### LockManager\r\n\r\nProvides asynchronous per-key mutual exclusion to prevent race conditions.\r\n\r\n### BucketCleanup\r\n\r\nRemoves idle buckets periodically to prevent unbounded memory growth.\r\n\r\n### Clock\r\n\r\nProvides a time abstraction for deterministic testing.\r\n\r\n---\r\n\r\n# Why a Clock Abstraction?\r\n\r\nUsing `Date.now()` directly makes testing difficult.\r\n\r\nThe library introduces a `Clock` interface.\r\n\r\nProduction:\r\n\r\n```ts\r\nSystemClock\r\n```\r\n\r\nTesting:\r\n\r\n```ts\r\nFakeClock\r\n```\r\n\r\nThis allows unit tests to simulate time instantly without waiting.\r\n\r\n---\r\n\r\n# Concurrency\r\n\r\nConcurrent requests targeting the same key are protected using a per-key asynchronous mutex.\r\n\r\nThis guarantees that bucket state remains consistent even under heavy concurrent load.\r\n\r\n---\r\n\r\n# Testing\r\n\r\nRun all tests\r\n\r\n```bash\r\npnpm test\r\n```\r\n\r\nGenerate coverage\r\n\r\n```bash\r\npnpm test:coverage\r\n```\r\n\r\nThe project includes deterministic tests using `FakeClock`.\r\n\r\n---\r\n\r\n# Build\r\n\r\n```bash\r\npnpm build\r\n```\r\n\r\nThe package is built using **tsup** and generates:\r\n\r\n- ESM bundle\r\n- CommonJS bundle\r\n- TypeScript declaration files\r\n\r\n---\r\n\r\n# Roadmap\r\n\r\n## Version 1.x\r\n\r\n- In-memory Token Bucket\r\n- Express middleware\r\n- Fake clock\r\n- Automatic cleanup\r\n- Dependency injection\r\n- TypeScript support\r\n\r\n## Version 2.x\r\n\r\n- Redis-backed implementation\r\n- Lua scripts for distributed atomicity\r\n- Sliding Window algorithm\r\n- Leaky Bucket algorithm\r\n- Fastify middleware\r\n- NestJS integration\r\n- Benchmark suite\r\n\r\n---\r\n\r\n# Contributing\r\n\r\nContributions are welcome.\r\n\r\nTo get started:\r\n\r\n```bash\r\ngit clone https://github.com/Dev-Git8/TokenBucket-RateLimiter-ts.git\r\n\r\npnpm install\r\n\r\npnpm test\r\n```\r\n\r\nPlease open an issue before submitting large feature changes.\r\n\r\n---\r\n\r\n# License\r\n\r\nMIT License.\r\n\r\n---\r\n\r\n# Author\r\n\r\n**Debasish Debnath**\r\n\r\nGitHub: https://github.com/Dev-Git8\r\n\r\nnpm: https://www.npmjs.com/~debasish-debnath","readmeFilename":"README.md"}