ADR-025: React Router RSC Entry Request Scope
React Router RSC Server Functions execute in an RSC request that is separate from ordinary Framework Mode route actions. Palamedes needs one request-local i18n initialization point that is active before a Server Function's arguments and default parameters are evaluated and survives its async rendering and revalidation work.
Status: Accepted Date: 2026-08-08 Revised: 2026-08-11
Context
React Router 8.3.0's generated Framework Mode entry.rsc.tsx accepts the
original Fetch Request and invokes unstable_matchRSCServerRequest from its
default fetch() method. Its supported custom-entry convention permits
wrapping that default method. The RSC API is experimental and explicitly may
break in patch or minor releases.
Decision
Publish the opt-in @palamedes/react-router-rsc package. Applications create
one request scope in app/entry.rsc.tsx and wrap React Router's default RSC
entry fetch() method. The resolver receives the original request and returns
a fresh, activated i18n instance. The package runs the complete default entry
inside @palamedes/runtime/server's AsyncLocalStorage scope.
Support exactly the tested RSC Framework Mode contract: @react-router/dev
and react-router 8.3.0 plus @vitejs/plugin-rsc 0.5.34. Do not instrument
"use server" bodies for this integration. Do not claim RSC Data Mode support.
Alternatives Considered
Directive-aware Server Function transform
Rejected. It initializes at function-body entry, after parameter/default evaluation. The runtime entry is earlier and covers the complete RSC and SSR request without rewriting user source. Reusing the Next.js transform would also require its eager-default safety diagnostic for no benefit on this path.
Per-function initialization
Rejected. It duplicates locale and catalog policy throughout application code, misses helpers before the initializer, and cannot cover default parameters.
Consequences
- Direct macros and synchronous, asynchronous, and cross-module helpers read the active locale during Server Function dispatch, rendering, and streaming.
- Concurrent RSC and SSR graphs use isolated async contexts.
- Resolver/catalog failures are clear server failures and prevent dispatch.
- Vite's current graph-splitting manifest does not identify RSC Server Function module fragments. Applications load the active locale's server catalog in the resolver until upstream exposes a safe mapping.
- Node-compatible
AsyncLocalStorageis required; Edge/Worker runtimes remain unsupported without application-specific verification.scope.run()restores its caller after the entry settles, while async resources created inside the request inherit its locale if they execute later. Separately initiated work without an inherited context has no active locale and needs explicit data or an appropriate new scope.
Validation And Review Triggers
The production fixture builds and browser-verifies a real client-to-server
"use server" call, default parameter, helpers, concurrent locale isolation,
and post-action revalidation. Revisit this decision when React Router changes
custom RSC entry semantics, unstable_matchRSCServerRequest, the RSC request
dispatch order, or Vite exposes an RSC server fragment manifest.