{"_id":"@codylabs/nestjs-redis-throttler-storage","_rev":"3-da8337306cbb424f12caaa8be015dd1e","name":"@codylabs/nestjs-redis-throttler-storage","dist-tags":{"latest":"0.1.0"},"versions":{"0.0.1":{"name":"@codylabs/nestjs-redis-throttler-storage","version":"0.0.1","author":"Cody Nguyen","license":"MIT","_id":"@codylabs/nestjs-redis-throttler-storage@0.0.1","maintainers":[{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"}],"dist":{"shasum":"7255f40dad94b84a402925991f36c0d007a802f1","tarball":"https://registry.npmjs.org/@codylabs/nestjs-redis-throttler-storage/-/nestjs-redis-throttler-storage-0.0.1.tgz","fileCount":42,"integrity":"sha512-YeMpgb9mlmuSOEc/1wJkbsz1WWNnK+HArqt0jbDvOSnfcYxM/wh9Q1WE8PIJ2lYgLEXkflaa7JauTvqVy549kQ==","signatures":[{"sig":"MEUCIGKTZBPfKIvnWv2aMbD9tvGpQEgpQbF5Y42HEniq/EChAiEA66I+KRcXhHl5ZxmblfUndzn+QxbF939JosDJDB96rxw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":321704},"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"scripts":{"test":"jest --passWithNoTests","build":"tsc -p tsconfig.build.json","clean":"rm -rf .turbo node_modules dist","prebuild":"rimraf dist","test:watch":"jest --watch"},"_npmUser":{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"},"description":"Redis storage for NestJS Throttler enabling distributed rate limiting across multiple application instances","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@codylabs/typescript-configs":"0.0.8"},"peerDependencies":{"redis":"^5.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-redis-throttler-storage_0.0.1_1779866804722_0.6050828778281598","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@codylabs/nestjs-redis-throttler-storage","version":"0.0.2","author":"Cody Nguyen","license":"MIT","_id":"@codylabs/nestjs-redis-throttler-storage@0.0.2","maintainers":[{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"}],"homepage":"https://github.com/cuongnd1705/codylabs#readme","bugs":{"url":"https://github.com/cuongnd1705/codylabs/issues"},"dist":{"shasum":"bd0cd69c886df6ce02bac3926737c18d79fc2106","tarball":"https://registry.npmjs.org/@codylabs/nestjs-redis-throttler-storage/-/nestjs-redis-throttler-storage-0.0.2.tgz","fileCount":42,"integrity":"sha512-GKAEQS8+bEQEhnrRP3yK3BC9odwBOWtZEO3fTvwJjYezhn6lMnnumdok491IpOJEiTXkW4cEZZAtU85ME0mLzA==","signatures":[{"sig":"MEUCIAGMA/+ivRWSxedP4QmlbI4IGU6uEf017+JeBAx9WDsyAiEAgkWj/xfXgnTygcXYTBXwaQ7dZ39013M6frSdZQCFRjc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":321937},"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"scripts":{"test":"jest --passWithNoTests","build":"tsc -p tsconfig.build.json","clean":"rm -rf .turbo node_modules dist","prebuild":"rimraf dist","test:watch":"jest --watch"},"_npmUser":{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"},"repository":{"url":"git+https://github.com/cuongnd1705/codylabs.git","type":"git"},"description":"Redis storage for NestJS Throttler enabling distributed rate limiting across multiple application instances","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@codylabs/typescript-configs":"0.0.9"},"peerDependencies":{"redis":"^6.0.0","@nestjs/common":"^11.0.0","@nestjs/throttler":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-redis-throttler-storage_0.0.2_1780126504655_0.8097543000347436","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@codylabs/nestjs-redis-throttler-storage","version":"0.1.0","description":"Redis storage for NestJS Throttler enabling distributed rate limiting across multiple application instances","homepage":"https://github.com/cuongnd1705/codylabs#readme","bugs":{"url":"https://github.com/cuongnd1705/codylabs/issues"},"license":"MIT","author":"Cody Nguyen","repository":{"type":"git","url":"git+https://github.com/cuongnd1705/codylabs.git"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"publishConfig":{"access":"public"},"devDependencies":{"@codylabs/typescript-configs":"0.1.0","@swc/core":"^1.16.1","unplugin-swc":"^1.5.11","vitest":"^4.1.11"},"peerDependencies":{"@nestjs/common":"^12.0.0","@nestjs/throttler":"^6.0.0","redis":"^6.0.0"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf .turbo node_modules dist","prebuild":"rimraf dist","test":"vitest run --passWithNoTests","test:watch":"vitest"},"_nodeVersion":"24.20.0","_id":"@codylabs/nestjs-redis-throttler-storage@0.1.0","dist":{"integrity":"sha512-XUGOTLLyDhPUaNVYbWE+8v0WsNWPf/dkgHgP/Cw/Kojf30oHuJIknSeZoTUuad0DF1FPuMeS4GaDNv57m4jZKQ==","shasum":"59e8959788dc7baa65672f0dee8169ae1a3586c7","tarball":"https://registry.npmjs.org/@codylabs/nestjs-redis-throttler-storage/-/nestjs-redis-throttler-storage-0.1.0.tgz","fileCount":42,"unpackedSize":288647,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBxHaX6YvEuhMMQAEvuP5GK99IIj3NXamVGyNk771257AiEA1joRhSe/J57KcRrf/d2jIkp8XjtL5n0z3f+YGrutAgU="}]},"_npmUser":{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"},"directories":{},"maintainers":[{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs-redis-throttler-storage_0.1.0_1788017131405_0.3586530746789762"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-27T07:26:44.532Z","modified":"2026-08-29T15:25:31.703Z","0.0.1":"2026-05-27T07:26:44.839Z","0.0.2":"2026-05-30T07:35:04.787Z","0.1.0":"2026-08-29T15:25:31.551Z"},"bugs":{"url":"https://github.com/cuongnd1705/codylabs/issues"},"author":"Cody Nguyen","license":"MIT","homepage":"https://github.com/cuongnd1705/codylabs#readme","repository":{"type":"git","url":"git+https://github.com/cuongnd1705/codylabs.git"},"description":"Redis storage for NestJS Throttler enabling distributed rate limiting across multiple application instances","maintainers":[{"name":"cuongnd1705","email":"cuongnd.work@gmail.com"}],"readme":"# @codylabs/nestjs-redis-throttler-storage\n\nRedis storage for NestJS Throttler enabling distributed rate limiting across multiple application instances.\n\n## Features\n\n- Distributed rate limiting with Redis\n- Drop-in replacement for in-memory storage\n- Works with existing `@codylabs/nestjs-redis-client` connections\n- Client, Cluster and Sentinel support\n- Six pluggable rate-limiting algorithms via `ThrottlerAlgorithm`\n- `IThrottlerAlgorithm` exported for custom algorithm typing\n- All algorithms implemented as atomic Lua scripts (EVALSHA + NOSCRIPT fallback)\n- Optional block key support: lock out a client for a configurable duration after exceeding the limit\n- Configurable Redis key prefix for multi-tenant/shared Redis environments\n\n## Installation\n\n```sh\n# npm\nnpm install @codylabs/nestjs-redis-throttler-storage @codylabs/nestjs-redis-client redis @nestjs/throttler\n\n# pnpm\npnpm add @codylabs/nestjs-redis-throttler-storage @codylabs/nestjs-redis-client redis @nestjs/throttler\n```\n\n## Usage\n\n### With Existing Redis Connection (Recommended)\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { ThrottlerModule, seconds } from '@nestjs/throttler';\nimport { RedisModule, RedisToken } from '@codylabs/nestjs-redis-client';\nimport { RedisThrottlerStorage } from '@codylabs/nestjs-redis-throttler-storage';\n\n@Module({\n  imports: [\n    RedisModule.forRoot({ options: { url: 'redis://localhost:6379' } }),\n    ThrottlerModule.forRootAsync({\n      inject: [RedisToken()],\n      useFactory: (redis) => ({\n        throttlers: [{ limit: 5, ttl: seconds(60) }],\n        storage: new RedisThrottlerStorage(redis),\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### Configure Key Prefix\n\nBy default, keys are prefixed with `_throttler`. You can override this with constructor options.\n\n```typescript\nimport { RedisThrottlerStorage } from '@codylabs/nestjs-redis-throttler-storage';\n\nconst storage = new RedisThrottlerStorage(redis, undefined, {\n  prefix: 'tenantA_throttler',\n});\n```\n\n### Without Existing Redis Connection\n\n```typescript\n@Module({\n  imports: [\n    ThrottlerModule.forRootAsync({\n      imports: [RedisModule.forRoot({ options: { url: 'redis://localhost:6379' } })],\n      inject: [RedisToken()],\n      useFactory: (redis) => ({\n        throttlers: [{ limit: 5, ttl: seconds(60) }],\n        storage: new RedisThrottlerStorage(redis),\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n## Algorithms\n\nPass a `ThrottlerAlgorithm` as the second argument to `RedisThrottlerStorage`. The default is `ThrottlerAlgorithm.FixedWindow`.\n\n```typescript\nimport { RedisThrottlerStorage, ThrottlerAlgorithm } from '@codylabs/nestjs-redis-throttler-storage';\n\nnew RedisThrottlerStorage(redis, ThrottlerAlgorithm.TokenBucket);\n```\n\n| Algorithm              | Memory | Accuracy        | Burst handling       | Best for                             |\n| ---------------------- | ------ | --------------- | -------------------- | ------------------------------------ |\n| `FixedWindow`          | O(1)   | Low at boundary | Up to 2x at boundary | Drop-in NestJS replacement (default) |\n| `SlidingWindowLog`     | O(n)   | Exact           | None                 | Strict per-user limits               |\n| `SlidingWindowCounter` | O(1)   | Good            | Smoothed             | General-purpose (recommended)        |\n| `TokenBucket`          | O(1)   | Good            | Yes (up to capacity) | Bursty clients                       |\n| `LeakyBucketPolicing`  | O(1)   | Good            | None (hard reject)   | Hard ingress cap, no queuing         |\n| `LeakyBucketShaping`   | O(1)   | Good            | None (queued)        | Smooth output rate with queuing      |\n\n**`FixedWindow` is the default** because `@nestjs/throttler`'s built-in in-memory storage uses fixed window internally, making this a true drop-in replacement with identical behavior. For new projects, **`SlidingWindowCounter`** is the recommended general-purpose choice.\n\n`SlidingWindowCounter` uses millisecond-level time calculations to avoid silently losing precision on sub-second TTLs.\n\n### Custom Algorithm\n\nYou can bring your own Lua script. `IThrottlerAlgorithm` is exported so you can type your implementation directly. The script receives `KEYS[1]` (the rate-limit key) and `ARGV[1..3]` (`ttlMs`, `limit`, `blockDurationMs`), and must return a 4-element array `[totalHits, timeToExpireMs, timeToBlockExpireMs, isBlocked]`.\n\n```typescript\nimport type { IThrottlerAlgorithm } from '@codylabs/nestjs-redis-throttler-storage';\n\nconst customAlgorithm: IThrottlerAlgorithm = {\n  script: `\n    local key = KEYS[1]\n    local ttl_ms = tonumber(ARGV[1])\n    local limit = tonumber(ARGV[2])\n    -- ... your logic ...\n    return { count, pttl, -1, 0 }\n  `,\n};\n\nnew RedisThrottlerStorage(redis, customAlgorithm);\n```\n\n### Block Duration\n\nAll algorithms support an optional block period. When `blockDuration` is set in your throttler config, a client that exceeds the limit is locked out for the full block duration.\n\n```typescript\nThrottlerModule.forRootAsync({\n  inject: [RedisToken()],\n  useFactory: (redis) => ({\n    throttlers: [{\n      limit: 10,\n      ttl: seconds(60),\n      blockDuration: seconds(300), // block for 5 minutes after exceeding limit\n    }],\n    storage: new RedisThrottlerStorage(redis, ThrottlerAlgorithm.SlidingWindowLog),\n  }),\n}),\n```\n\n### Manual Reset / Unblock\n\nUse `reset()` when you need to manually clear limiter and block keys for a client.\n\n```typescript\nawait storage.reset('user:123', 'default');\n```\n\n## License\n\nMIT\n","readmeFilename":""}