Skip to content

Overview

Per-request HTTP state with flareState tokens, middleware provides, and build-time provisioning checks.

AI generated, pending review Updated 10 days ago · Flare 0.3

Per-request HTTP state is typed data on FlareHttpContext for one request. You create state tokens with flareState(), write values in middleware before() hooks, read them in handlers via ctx.state, and declare dependencies so HTTP compile verifies an upstream middleware provides each token.

This is separate from host.state, which is the host lifecycle state ("starting" | "ready" | "draining" | "stopped").

  1. Middleware before() calls ctx.state.set(token, value) for tokens in provides.
  2. Route handlers read with ctx.state.require(token) or ctx.state.get(token).
  3. At build(), Flare walks each route’s middleware chain and fails when a declared token has no upstream before() provider.

Values are deep-frozen on write. Handlers get snapshots, not live mutable references.

The alternative this replaces is the mutable bag: a req.user patched on by whichever middleware happened to run, read through a cast. Nothing ties the writer to the reader there, so “did auth run before this handler” is a convention enforced by code review, and the failure mode is undefined deep in a handler, on the first request that takes an unusual path. The token graph turns each of those conventions into a checked declaration: a reader states what it needs, exactly one provider may exist, values are snapshots rather than shared mutable state, and the wiring mistake fails build() naming the token instead of failing a user.

PageCovers
Declaring stateflareState(), withDefault, from, withLogging
Reading stateget, set, require
Middleware that provides stateAuth pattern with short-circuit 401
State and loggingrequestId and log context on HTTP requests
Build-time state validationCycles, dead middleware, missing providers
import { FlareHost, FlareResponse, MiddlewareBase, flareState } from "@flare-ts/core";
import { node } from "@flare-ts/core/node";
const AuthUser = flareState<{ id: string }>("AuthUser");
class AuthMiddleware extends MiddlewareBase {
public static override deps = [];
public static override state = [];
public static override provides = [AuthUser];
before() {
this.ctx.state.set(AuthUser, { id: "u1" });
}
}
const host = new FlareHost(node);
host.http.use(AuthMiddleware);
host.http.get("/me", { state: [AuthUser] }, (ctx) => {
return new FlareResponse(200, ctx.state.require(AuthUser));
});
const app = host.build();
app.run();

Error handlers are not part of the state wiring graph. handle(err, context) receives HttpErrorContext, not FlareHttpContext. Pass request data through FlareError.detail or an injected service instead.