EveryDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/AmeyaBorkar/throttlekit/llms.txt
Use this file to discover all available pages before exploring further.
check, checkSync, peek, peekSync, and forecast call in ThrottleKit returns — or is based on — a Decision. It is an immutable snapshot of the limiter’s verdict for a single key at a single point in time. Understanding its fields is the foundation for writing correct rate-limit handling, setting HTTP headers, and scheduling client retries.
The Decision interface
Whether the request is permitted.
true means the request was admitted and capacity was consumed. false means the limit has been reached and the request should be rejected.The effective ceiling reported to clients — the burst capacity (for GCRA and token bucket) or the window quota (for fixed/sliding window strategies). This is the value used in
RateLimit-Limit HTTP headers.Whole units remaining before the next rejection. This value is never negative. For a consuming
check, it reflects the capacity after the current request was charged. For a non-consuming peek, it reflects current capacity without any deduction.Epoch milliseconds at which the limiter is fully replenished to its ceiling from the current state. Use
new Date(resetAt) to convert for display. This drives RateLimit-Reset and X-RateLimit-Reset headers.Milliseconds the client should wait before retrying. Always
0 when allowed is true. When allowed is false, this is the minimum wait before the request would be permitted again — the value used in the Retry-After HTTP header (converted to seconds, rounded up to a minimum of 1).Why all fields are integers
All numeric fields —limit, remaining, resetAt, retryAfterMs — are integers. This is a load-bearing constraint, not a cosmetic choice.
Redis truncates Lua numbers to integers on reply. By restricting Decision fields to integers, ThrottleKit guarantees that the JavaScript execution path (in-memory) and the Redis-Lua execution path produce bit-identical values for every decision. This is what makes the dual-path conformance proof possible: the same timeline run through MemoryStore and RedisStore must produce the exact same sequence of decisions.
Internal strategy state (e.g. a GCRA theoretical-arrival-time timestamp) is stored at full IEEE-754 precision inside the store. Only the
Decision fields surfaced to callers are integer-projected, preserving accuracy while enabling cross-backend byte equality.Using Decision fields in practice
peek() — non-consuming introspection
peek (and its synchronous counterpart peekSync) returns a Decision describing the current capacity without consuming any. The remaining and resetAt fields describe what is available now, not after a deduction.
peek is available on rateLimit-constructed limiters when the strategy implements the optional peek method. All eight built-in strategies implement it.
check() vs peek() — consuming vs non-consuming
| Method | Consumes capacity | When to use |
|---|---|---|
check(key, cost?) | ✅ Yes | Normal request admission — charges the key and returns the post-charge decision |
checkSync(key, cost?) | ✅ Yes | Same as check but synchronous; requires MemoryStore |
peek(key) | ❌ No | Read current capacity without admitting a request |
peekSync(key) | ❌ No | Synchronous peek; requires MemoryStore |
peek call never writes to the store. On Redis, it uses a read-only Lua path that issues no writes. On MemoryStore, persist: false is set on the transform result so no state update occurs.
forecast() — capacity projection
forecast (and forecastSync) returns a Forecast — a non-consuming projection of the key’s near-future capacity for a given cost:
forecast is useful for adaptive retry scheduling and client-side quota planning. It is implemented by all built-in strategies and available on rateLimit-constructed limiters. Like peek, it never writes to the store.Stability guarantee
Decision is a producer type — the library returns it, you read it. Per the 1.x SemVer stability contract, it grows only by appending optional readonly fields. Future minor releases may add fields like bindingAxis. Do not use zod.strict() or exhaustive property validation on a Decision object — a strict consumer would break on any new optional field.