Skip to content

Commit c182dac

Browse files
committed
docs(overview): Describe AsyncLocalStorage wrapping and global context (#2060)
1 parent 0b4171c commit c182dac

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

docs/implementation-docs/2026-03-26-cedarjs-project-overview.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,58 @@ Routes.tsx ← 4 routes added inside <Set wrap={ScaffoldLayout} title="Posts" ..
257257
| cookie-jar | Typed cookie map. get/set/has/unset/serialize. |
258258
| utils | Pluralization wrapper. |
259259

260+
## ALS WRAPPING & GLOBAL CONTEXT
261+
262+
Cedar provides two related but distinct mechanisms:
263+
264+
- **ALS wrapping** (`store.run(new Map(), ...)`) — ensures the AsyncLocalStorage
265+
store exists for the duration of a request. Needed because serverless
266+
environments (Netlify, Vercel) may reuse the same process across requests —
267+
without a fresh store per request, state from one request could leak into
268+
another. Also prevents the `context` proxy from crashing (without an active
269+
store, `getStore()` returns `undefined`).
270+
- **`context`** (auto-imported from `@cedarjs/context`) — a Proxy that
271+
reads/writes from the ALS store. Exists so services deep in the GraphQL
272+
resolver chain can access `currentUser` without threading it through every
273+
function parameter.
274+
275+
`setContext()` populates the store with the resolved GraphQL context
276+
(including `currentUser`) and is only called by the
277+
`useRedwoodGlobalContextSetter` plugin
278+
(`packages/graphql-server/src/plugins/useRedwoodGlobalContextSetter.ts:16`).
279+
It's GraphQL-only because:
280+
281+
1. GraphQL has a plugin chain where `currentUser` is resolved once by
282+
`useRedwoodAuthContext` (from `ctx.serverAuthState`) and then made available
283+
to all downstream resolvers and directive validators via the store.
284+
2. Regular functions are single-entry-point: they get the request, do one thing,
285+
return a response. Different function types handle auth differently, but none
286+
need `setContext()` for `currentUser`:
287+
288+
- **Auth functions** (login/signup/logout): integral to the auth flow, but
289+
they create/destroy sessions by reading the request body and cookies
290+
directly. On login the user isn't authenticated yet; on logout the session
291+
is already in the cookie. `currentUser` is resolved _after_ these functions
292+
succeed, by the auth decoder on subsequent GraphQL requests.
293+
- **Webhooks** (Stripe, SendGrid): external POSTs with no Cedar auth context
294+
at all. No way to construct a `currentUser` from the request.
295+
- **Custom API endpoints**: if they need auth they decode the token or read
296+
the cookie themselves. Preferrably with the help of the `useRequireAuth()`
297+
hook.
298+
299+
| Path | Mechanism | ALS wrapping | `setContext()` | `context.currentUser` |
300+
| --------------------------------------------------------- | -------------------------- | ------------ | --------------- | --------------------- |
301+
| **Non-UD dev** — GraphQL | Fastify `onRequest` hook || ✅ plugin chain ||
302+
| **Non-UD dev** — Functions | Fastify `onRequest` hook |||`undefined` |
303+
| **Non-UD serve/deploy** (baremetal/docker) — GraphQL | Fastify `onRequest` hook || ✅ plugin chain ||
304+
| **Non-UD serve/deploy** (baremetal/docker) — Functions | Fastify `onRequest` hook |||`undefined` |
305+
| **Non-UD deploy** (Netlify/Vercel serverless) — GraphQL | Babel safety net in output || ✅ plugin chain ||
306+
| **Non-UD deploy** (Netlify/Vercel serverless) — Functions | Babel safety net in output |||`undefined` |
307+
| **UD dev** — GraphQL | Vite Babel transform || ✅ plugin chain ||
308+
| **UD dev** — Functions | Vite Babel transform |||`undefined` |
309+
| **UD built/deploy** — GraphQL | Generated `store.run()` || ✅ plugin chain ||
310+
| **UD built/deploy** — Functions | Generated `store.run()` |||`undefined` |
311+
260312
## CONVENTIONS
261313

262314
- Config: `cedar.toml` (fallback `redwood.toml`)

0 commit comments

Comments
 (0)