@brume/limit is the typed client for the rate-limiting API. Small on purpose: two operations, one result type, and three behaviors that save you from writing them yourself.
Install
Two operations
const limit = createLimitClient({ apiKey: process.env.BRUME_API_KEY! });
// Consume one unit of capacity.
const verdict = await limit.limit('api', user.id);
// Read state without consuming.
const state = await limit.check('api', user.id);
Both return a LimitResult: success, limit, remaining, reset, retry_after, window, degraded, and parsed headers. Multi-rule variants (limitMulti, checkMulti) evaluate several rules in one round trip and return the most restrictive result.
Ephemeral cache for blocked identifiers
When limit() denies an identifier, the SDK remembers the reset timestamp and denies subsequent calls from the same identifier locally — no network round trip. An already-blocked client hammering your API costs the gateway nothing. The cache is in-process, on by default, and cleared the moment the identifier is allowed again. check() never uses the cache: it exists to read live state.
Timeout and error fallbacks
const limit = createLimitClient({
apiKey: process.env.BRUME_API_KEY!,
timeout: { ms: 500, fallback: 'allow' },
onError: 'allow',
});
timeout.fallback: 'allow' | 'deny' — what to do when the gateway is slow.
onError: 'allow' | 'deny' — what to do on network failure.
Both return synthetic results with degraded: true, so your code path is identical whether the degradation happened at Redis or on the wire. Availability over correctness, or the reverse — your call, made once, in config.
What the SDK is not
It is not a framework integration. There are no middleware opinions, no React hooks, no decorators. It is a typed HTTP client you can drop into any runtime that has fetch — Node, Bun, Deno, edge functions, Cloudflare Workers.