{"_id":"@agentine/sluice","name":"@agentine/sluice","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agentine/sluice","version":"0.1.0","description":"Task scheduler and rate limiter for Node.js — drop-in replacement for bottleneck","repository":{"type":"git","url":"git+https://github.com/agentine/sluice.git"},"license":"MIT","type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/esm/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./compat/bottleneck":{"types":"./dist/esm/compat/bottleneck.d.ts","import":"./dist/esm/compat/bottleneck.js","require":"./dist/cjs/compat/bottleneck.js"}},"main":"./dist/cjs/index.js","module":"./dist/esm/index.js","types":"./dist/esm/index.d.ts","scripts":{"build":"npm run build:esm && npm run build:cjs","build:esm":"tsc -p tsconfig.json","build:cjs":"tsc -p tsconfig.cjs.json && cp src/cjs-package.json dist/cjs/package.json","clean":"rm -rf dist","test":"vitest run"},"devDependencies":{"@types/node":"^22.0.0","typescript":"^5.4.0","vitest":"^3.0.0"},"peerDependencies":{"ioredis":">=5.0.0"},"peerDependenciesMeta":{"ioredis":{"optional":true}},"_id":"@agentine/sluice@0.1.0","gitHead":"1cf2b6fa11d7d80660a969029e3d9432cc4a1bb6","bugs":{"url":"https://github.com/agentine/sluice/issues"},"homepage":"https://github.com/agentine/sluice#readme","_nodeVersion":"22.22.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-Fc8hklZ3Zp1f8Pwe36QxidGFtNp9AxqRY/GZCXZwf1O1XxpXNqmOXV9YG6HWZ10EoxpRsGi+2MwH75t6wHajkA==","shasum":"c6b04c1b7fe73fb9e7ea407cf15d2a6c04f25cbe","tarball":"https://registry.npmjs.org/@agentine/sluice/-/sluice-0.1.0.tgz","fileCount":92,"unpackedSize":176631,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@agentine%2fsluice@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFF3uGJLOxZpVAZfguASc58iW/AcDeEAEdv2Lv1M5SOjAiBYRW8iSsmS5FTHULI/cCfan48EhmzVX9su9kNaiN3Rkg=="}]},"_npmUser":{"name":"mtingers","email":"matthingersoll@gmail.com"},"directories":{},"maintainers":[{"name":"mtingers","email":"matthingersoll@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sluice_0.1.0_1773634526819_0.6376945995685002"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-16T04:15:26.744Z","0.1.0":"2026-03-16T04:15:26.964Z","modified":"2026-03-16T04:15:27.405Z"},"maintainers":[{"name":"mtingers","email":"matthingersoll@gmail.com"}],"description":"Task scheduler and rate limiter for Node.js — drop-in replacement for bottleneck","homepage":"https://github.com/agentine/sluice#readme","repository":{"type":"git","url":"git+https://github.com/agentine/sluice.git"},"bugs":{"url":"https://github.com/agentine/sluice/issues"},"license":"MIT","readme":"# @agentine/sluice\n\nTask scheduler and rate limiter for Node.js — drop-in replacement for [bottleneck](https://github.com/SGrondin/bottleneck).\n\n## Features\n\n- **Concurrency control** — limit parallel tasks with `maxConcurrent`\n- **Rate limiting** — enforce minimum time between task starts with `minTime`\n- **Reservoir** — finite quota with auto-refresh and incremental increase\n- **Priority queues** — 10 priority levels (0-9), weighted tasks\n- **Job lifecycle events** — received, queued, scheduled, executing, done, failed, dropped, depleted, empty, idle\n- **Group** — keyed limiter instances with shared settings and idle cleanup\n- **Redis clustering** — distributed rate limiting via ioredis (optional)\n- **Bottleneck compatibility** — drop-in migration path via `@agentine/sluice/compat/bottleneck`\n- **TypeScript-first** — accurate types with generics\n- **ESM + CJS** — dual package, native ES module support\n- **Zero runtime dependencies** — ioredis is an optional peer dependency for clustering\n\n## Install\n\n```bash\nnpm install @agentine/sluice\n```\n\n## Quick Start\n\n```typescript\nimport { Sluice } from \"@agentine/sluice\";\n\nconst limiter = new Sluice({\n  maxConcurrent: 5,\n  minTime: 200,\n});\n\nconst result = await limiter.schedule(() => fetch(\"https://api.example.com/data\"));\n```\n\n## API\n\n### Constructor Options\n\n```typescript\nconst limiter = new Sluice({\n  maxConcurrent: 5,       // Max parallel jobs (null = unlimited)\n  minTime: 200,           // Min ms between job starts\n  highWater: 100,         // Max queued jobs before strategy kicks in\n  strategy: Strategy.LEAK, // LEAK, OVERFLOW, or BLOCK\n  rejectOnDrop: true,     // Reject promise when job is dropped\n  reservoir: 50,          // Finite job quota\n  reservoirRefreshInterval: 60000,  // Reset reservoir every N ms\n  reservoirRefreshAmount: 50,       // Reset reservoir to this value\n  reservoirIncreaseInterval: 1000,  // Increase reservoir every N ms\n  reservoirIncreaseAmount: 1,       // Increase by this amount\n  reservoirIncreaseMaximum: 100,    // Max reservoir value\n  id: \"my-limiter\",       // Identifier for debugging\n  trackDoneStatus: false, // Track completed job count\n});\n```\n\n### Methods\n\n```typescript\n// Schedule a job (returns promise with result)\nconst result = await limiter.schedule(async () => doWork());\nconst result = await limiter.schedule({ priority: 1, weight: 2 }, async () => doWork());\n\n// Wrap a function for automatic rate limiting\nconst limited = limiter.wrap(fetch);\nconst data = await limited(\"https://api.example.com\");\n\n// Chain limiters (multi-level rate limiting)\nconst perEndpoint = new Sluice({ maxConcurrent: 5 });\nconst global = new Sluice({ maxConcurrent: 20 });\nperEndpoint.chain(global);\n\n// Reservoir management\nawait limiter.currentReservoir();      // Get current count\nawait limiter.incrementReservoir(10);  // Add to reservoir\n\n// Status\nawait limiter.running();   // Currently executing jobs\nawait limiter.queued();    // Jobs waiting in queue\nawait limiter.done();      // Completed jobs (if trackDoneStatus)\nawait limiter.empty();     // True if no running or queued jobs\n\n// Update settings at runtime\nlimiter.updateSettings({ maxConcurrent: 10 });\n\n// Stop\nlimiter.stop({ dropWaitingJobs: true });\nlimiter.disconnect();\n```\n\n### Events\n\n```typescript\nlimiter.on(\"executing\", (info) => console.log(\"Job started:\", info.options.id));\nlimiter.on(\"done\", (info) => console.log(\"Job completed\"));\nlimiter.on(\"failed\", (error, info) => console.error(\"Job failed:\", error));\nlimiter.on(\"depleted\", () => console.log(\"Reservoir exhausted\"));\nlimiter.on(\"idle\", () => console.log(\"All jobs complete\"));\n```\n\n### Job Options\n\n```typescript\nawait limiter.schedule({\n  id: \"job-1\",        // Job identifier\n  priority: 1,        // 0-9, lower = higher priority (default: 5)\n  weight: 2,          // Reservoir units consumed (default: 1)\n  expiration: 5000,   // Timeout in ms (default: null)\n}, async () => doWork());\n```\n\n### Strategy\n\n```typescript\nimport { Strategy } from \"@agentine/sluice\";\n\nStrategy.LEAK      // 1 — drop lowest priority job when at highWater\nStrategy.OVERFLOW  // 2 — drop new incoming job when at highWater\nStrategy.BLOCK     // 3 — pause processing when at highWater\n```\n\n### Group\n\n```typescript\nimport { Group } from \"@agentine/sluice\";\n\nconst group = new Group({\n  maxConcurrent: 5,\n  minTime: 200,\n  timeout: 60000, // Auto-delete idle limiters after 60s\n});\n\nconst userLimiter = group.key(\"user-123\");\nawait userLimiter.schedule(() => fetchUserData());\n\ngroup.on(\"created\", (limiter, key) => console.log(\"New limiter:\", key));\ngroup.deleteKey(\"user-123\");\n```\n\n## Migrating from Bottleneck\n\nSee [MIGRATION.md](MIGRATION.md) for a complete guide.\n\n**Quick version:**\n\n```diff\n- import Bottleneck from \"bottleneck\";\n+ import Bottleneck from \"@agentine/sluice/compat/bottleneck\";\n```\n\nNo other code changes needed.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-34ed40a8e11c0b89c1dddb684b9f3143"}