@aksparadise/valkey-token-bucket
v1.0.0
Published
Production-ready, highly-scalable, and distributed Rate Limiter using Token Bucket algorithm in Valkey/Redis. Prevents race-conditions atomically via Lua scripting. Highly optimized with zero runtime dependencies. Created by AksParadise.
Readme
@aksparadise/valkey-token-bucket ⏱️
A production-ready, highly-scalable, and distributed Token Bucket Rate Limiter for Valkey and Redis in Node.js.
Atomically eliminates distributed race-conditions using high-speed server-side Lua scripts. Zero runtime dependencies for absolute security and safety. Built by AksParadise.
✨ Features
- 🏎️ Zero-Latency Atomic Evaluation: Recalculates limits inside a single-threaded Lua script on Valkey, preventing concurrency race-conditions (TOCTOU) completely.
- 🛡️ Zero-Vulnerability Architecture: Has 0 direct runtime dependencies, fully protecting your project from nested package CVE chains.
- 📦 Dual CJS + ESM Packaging: Supports modern ES6
importsyntax as well as legacy CommonJSrequire()natively. - 🔌 Native Driver Support: Out-of-the-box auto-detection for both
ioredisandredis(node-redis v4+). - 💡 Advanced Express Middleware Wrapper: Built-in, RFC-compliant rate limiter supporting standard headers and custom user dynamic keys (e.g. rate limit by Session Account IDs, API keys, or custom headers).
- 📐 TypeScript Definitions Included: Fully typed out-of-the-box (
d.tsdefinitions).
📋 Prerequisites
To use this library, ensure your project setup has:
- Node.js version
16.0.0or newer. - Valkey version
7.2.0+OR Redis version2.6.0+(sinceEVALexecution was introduced). - Either of the following driver clients installed in your project:
redis(node-redis version^4.0.0)ioredis(version^5.0.0)
🚀 Installation
npm install @aksparadise/valkey-token-bucket💻 Usage
1. Simple Express Middleware Integration (By Client IP)
By default, the middleware tracks client IP addresses and enforces rate limiting:
import express from "express";
import { createClient } from "redis";
import { expressRateLimiter } from "@aksparadise/valkey-token-bucket";
const app = express();
const redisClient = createClient();
await redisClient.connect();
const limiter = expressRateLimiter({
redisClient: redisClient,
capacity: 100, // Max tokens
windowMs: 60000, // Duration to fully refill (1 minute)
keyPrefix: "limit:api:"
});
// Apply to routes
app.use("/api/v3", limiter);2. Advanced Express Middleware Integration (By Custom Session User)
You can provide a keyGenerator callback to rate-limit by custom session properties (like logged-in user account IDs or custom auth API keys) rather than client IP addresses:
import express from "express";
import { expressRateLimiter } from "@aksparadise/valkey-token-bucket";
const app = express();
const folderSyncLimiter = expressRateLimiter({
redisClient: myRedisClient,
capacity: 10,
windowMs: 60000,
keyPrefix: "ratelimit:sync:",
// Custom key resolver:
keyGenerator: (req) => req.session?.accountId // Defaults to client IP if undefined
});
app.get("/folders", folderSyncLimiter, (req, res) => {
res.json({ success: true, folders: [] });
});3. Programmatic Usage (Any Framework)
You can use the core class directly inside any web framework, microservice, gRPC, or WebSocket server:
import { TokenBucketLimiter } from "@aksparadise/valkey-token-bucket";
const limiter = new TokenBucketLimiter({
redisClient: myRedisClient,
capacity: 250,
windowMs: 60000, // 250 requests per minute
keyPrefix: "api-limit:"
});
async function handleRequest(userId) {
const result = await limiter.consume(userId, 1);
if (result.allowed) {
console.log(`Allowed! Tokens left: ${result.remaining}`);
// Proceed with request...
} else {
console.log(`Rate limited! Retry after ${result.retryAfterSeconds} seconds.`);
// Return 429 Too Many Requests...
}
}📈 Standard HTTP Response Headers
The built-in Express middleware automatically attaches standard RFC-compliant headers:
| Header Name | Description |
| :--- | :--- |
| X-RateLimit-Limit | The maximum capacity of the rate limit bucket. |
| X-RateLimit-Remaining | Remaining tokens left in the bucket. |
| Retry-After | Time (in seconds) the client must wait before making another request (returned only on 429). |
🛡️ Security & Fail-Open Philosophy
In enterprise production architectures, a database lag or caching server crash should never lock legitimate users out of your core services.
Our package operates under a strict Fail-Open Policy: if your Valkey or Redis server goes offline or suffers connection timeouts, the library catches the incident, prints a structured warning log console, and silently allows the user request to proceed (calls next()), keeping your user experience 100% seamless during infrastructure updates.
📄 License
MIT © AksParadise
