The pluggable store
Swap the in-memory store for a shared one to back throttle, cache and sessions — get/set + TTL, plus the optional verbs that make a throttle fleet-wide.
Swap the in-memory store for a shared one when you want throttle counters and
auth sessions to live outside a single process — back them with Redis, Postgres,
or anything else by implementing two async methods, get and set, and attaching
it via store. A few more are optional capabilities you add when your backend can
do them atomically.
Example
import { } from 'stitchapi';
import type { StitchStore } from 'stitchapi';
// A StitchStore is `get` + `set` with TTL — back it with anything. `increment`
// is one of the optional capabilities: add it only if your backend has an atomic counter.
const : StitchStore = {
async () {
/* read from your shared backend */
return ;
},
async (, , ) {
/* write, honoring ttl */
},
async (, ) {
/* atomic counter with a TTL window */
return 1;
},
};
const = ({
: 'https://api.example.com',
: '/users/{id}',
: ,
});Don't hand-roll one unless you need to — @stitchapi/redis is the
first-party store: redisStore(fromIoredis(client)) (or fromNodeRedis),
proven against the conformance.store kit.
Options
A store is the StitchStore contract. Two async methods are required: get(key)
returns the value or undefined, and set(key, value, ttl?) writes with an
optional expiry (set(key, undefined) deletes). Everything else is an optional
capability the runtime uses when it's there:
increment(key, ttl?)— an atomic counter scoped to a TTL window, the throttle's fallback for pacingrateacross processes;reserve(...)— the atomic pacing cursor that makesrateexact fleet-wide;lease(...)/release(...)— a semaphore that makesconcurrencyfleet-wide.
Leave out what your backend can't do atomically: the throttle falls back to
per-process limits and emits one throttle.per-process info event saying so. The
capability table shows what each store
implements. The runtime keeps three kinds of state behind this interface: throttle
state, the response cache, and auth session/token state (captured cookies and
refreshed tokens).
The default is memoryStore() — single process, in-memory. It works until you
run more than one worker, where each process keeps its own counters and its own
sessions.
Point store at one shared backend and that splits apart: the rate counter
becomes a single window every process increments, so the limit holds across the
fleet — see Distributed throttle —
and a captured session is written once and replayed everywhere, so workers don't
each re-run the login — see Shared sessions.
Concurrency limits go fleet-wide only when the store implements the lease pair; without it they stay in-process. See Distributed throttle.