Rate limiting
A fixed window: each key has a counter that resets after the window. check(key, { max, windowSecs }) returns allowed / remaining / retry-after. Here a burst of 6 requests against a limit of 3 — the first three pass, the rest are blocked with a retry delay.
Tip
In production, derive the key with keyForRequest(request, bucket) (client IP + bucket name) and back it with a store shared across workers. attempt(key, opts, fn) runs fn only when under the limit; reset(key) clears the counter (e.g. after a successful login).
Run the burst to watch the limit kick in.
import { createRateLimiter, memoryRateStore, keyForRequest } from "@bext-stack/framework/rate-limit";
const limiter = createRateLimiter({ store: memoryRateStore() });
export async function action({ request }) {
const key = keyForRequest(request, "signup"); // client ip + bucket
const r = await limiter.check(key, { max: 5, windowSecs: 60 });
if (!r.allowed) {
return new Response("Too many requests", {
status: 429, headers: { "retry-after": String(r.retryAfterSecs) },
});
}
// …handle the request…
}