@rangojs/router 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/dist/bin/rango.js +1 -1
  2. package/dist/types/__internal.d.ts +7 -1
  3. package/dist/types/browser/action-fence.d.ts +2 -1
  4. package/dist/types/browser/event-controller.d.ts +8 -2
  5. package/dist/types/browser/history-state.d.ts +3 -9
  6. package/dist/types/browser/navigation-store.d.ts +8 -6
  7. package/dist/types/browser/partial-update.d.ts +11 -0
  8. package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
  9. package/dist/types/browser/react/use-action.d.ts +7 -2
  10. package/dist/types/browser/react/use-handle.d.ts +19 -16
  11. package/dist/types/browser/react/use-link-status.d.ts +5 -2
  12. package/dist/types/browser/segment-reconciler.d.ts +32 -4
  13. package/dist/types/browser/types.d.ts +24 -5
  14. package/dist/types/browser/wire-protocol.d.ts +26 -0
  15. package/dist/types/cache/cache-key-utils.d.ts +11 -5
  16. package/dist/types/cache/cache-scope.d.ts +34 -22
  17. package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
  18. package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
  19. package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
  20. package/dist/types/cache/handle-snapshot.d.ts +9 -4
  21. package/dist/types/cache/segment-codec.d.ts +14 -0
  22. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  23. package/dist/types/cache/taint.d.ts +5 -3
  24. package/dist/types/cache/types.d.ts +7 -3
  25. package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
  26. package/dist/types/prefetch-markers.d.ts +5 -14
  27. package/dist/types/prerender/store.d.ts +31 -0
  28. package/dist/types/prerender/warm-request.d.ts +3 -3
  29. package/dist/types/prerender.d.ts +2 -2
  30. package/dist/types/route-name.d.ts +5 -0
  31. package/dist/types/router/error-handling.d.ts +11 -5
  32. package/dist/types/router/instrument.d.ts +4 -3
  33. package/dist/types/router/intercept-resolution.d.ts +25 -9
  34. package/dist/types/router/match-context.d.ts +6 -11
  35. package/dist/types/router/match-handlers.d.ts +2 -6
  36. package/dist/types/router/match-middleware/background-revalidation.d.ts +13 -22
  37. package/dist/types/router/match-middleware/cache-lookup.d.ts +34 -86
  38. package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
  39. package/dist/types/router/navigation-snapshot.d.ts +7 -0
  40. package/dist/types/router/prerender-match.d.ts +21 -6
  41. package/dist/types/router/preview-match.d.ts +2 -7
  42. package/dist/types/router/request-classification.d.ts +5 -0
  43. package/dist/types/router/router-context.d.ts +7 -46
  44. package/dist/types/router/router-interfaces.d.ts +8 -14
  45. package/dist/types/router/segment-resolution/helpers.d.ts +19 -3
  46. package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
  47. package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
  48. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
  49. package/dist/types/router/segment-resolution/resolution-pass.d.ts +95 -0
  50. package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
  51. package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +2 -0
  52. package/dist/types/router/segment-resolution.d.ts +1 -2
  53. package/dist/types/router/segment-wrappers.d.ts +11 -48
  54. package/dist/types/router/telemetry.d.ts +2 -0
  55. package/dist/types/router/types.d.ts +11 -1
  56. package/dist/types/rsc/full-payload.d.ts +2 -2
  57. package/dist/types/rsc/handler-context.d.ts +6 -6
  58. package/dist/types/rsc/json-route-result.d.ts +5 -9
  59. package/dist/types/rsc/request-stages.d.ts +203 -0
  60. package/dist/types/rsc/response-cache-serve.d.ts +7 -12
  61. package/dist/types/rsc/response-route-handler.d.ts +2 -2
  62. package/dist/types/rsc/routine-plan.d.ts +1 -1
  63. package/dist/types/rsc/server-action.d.ts +2 -2
  64. package/dist/types/rsc/shell-capture-constants.d.ts +1 -1
  65. package/dist/types/rsc/shell-capture.d.ts +132 -15
  66. package/dist/types/rsc/shell-serve.d.ts +37 -12
  67. package/dist/types/server/context.d.ts +9 -8
  68. package/dist/types/server/handle-store.d.ts +16 -0
  69. package/dist/types/server/render-pass.d.ts +72 -0
  70. package/dist/types/server/request-context.d.ts +53 -104
  71. package/dist/types/server/rewrite-trail.d.ts +2 -2
  72. package/dist/types/testing/dispatch.d.ts +35 -18
  73. package/dist/types/testing/render-route.d.ts +43 -8
  74. package/dist/types/testing/serve-shell-request.d.ts +8 -1
  75. package/dist/types/types/cache-types.d.ts +6 -3
  76. package/dist/types/types/error-types.d.ts +30 -3
  77. package/dist/types/types/handler-context.d.ts +9 -1
  78. package/dist/types/types/segments.d.ts +1 -1
  79. package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
  80. package/dist/types/vite/discovery/build-env.d.ts +22 -0
  81. package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
  82. package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
  83. package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
  84. package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
  85. package/dist/types/vite/discovery/state.d.ts +12 -0
  86. package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
  87. package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
  88. package/dist/types/vite/router-discovery.d.ts +8 -47
  89. package/dist/types/vite/temp-rsc-server.d.ts +39 -0
  90. package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
  91. package/dist/types/wire-params.d.ts +39 -0
  92. package/dist/vite/index.js +3822 -3727
  93. package/package.json +1 -1
  94. package/skills/cache-guide/SKILL.md +8 -5
  95. package/skills/caching/SKILL.md +37 -18
  96. package/skills/client-urls/SKILL.md +4 -2
  97. package/skills/document-cache/SKILL.md +13 -1
  98. package/skills/handler-use/SKILL.md +1 -1
  99. package/skills/hooks/SKILL.md +1 -1
  100. package/skills/hooks/data.md +8 -1
  101. package/skills/hooks/handle-and-actions.md +33 -2
  102. package/skills/hooks/navigation.md +121 -15
  103. package/skills/hooks/state.md +6 -4
  104. package/skills/hooks/urls.md +16 -5
  105. package/skills/intercept/SKILL.md +23 -7
  106. package/skills/middleware/SKILL.md +18 -0
  107. package/skills/observability/SKILL.md +30 -0
  108. package/skills/ppr/SKILL.md +18 -3
  109. package/skills/prerender/SKILL.md +39 -15
  110. package/skills/rango/SKILL.md +5 -1
  111. package/skills/server-actions/SKILL.md +15 -1
  112. package/skills/testing/client-components.md +25 -18
  113. package/skills/testing/response-routes.md +6 -4
  114. package/skills/testing/serve-shell-request.md +7 -7
  115. package/skills/use-cache/SKILL.md +46 -8
  116. package/skills/view-transitions/SKILL.md +1 -1
  117. package/src/__internal.ts +7 -1
  118. package/src/browser/action-fence.ts +2 -1
  119. package/src/browser/connection-warmup.ts +3 -1
  120. package/src/browser/event-controller.ts +37 -13
  121. package/src/browser/history-state.ts +6 -12
  122. package/src/browser/navigation-bridge.ts +59 -26
  123. package/src/browser/navigation-client.ts +20 -25
  124. package/src/browser/navigation-store.ts +25 -27
  125. package/src/browser/navigation-transaction.ts +4 -1
  126. package/src/browser/network-error-handler.ts +4 -0
  127. package/src/browser/partial-update.ts +33 -6
  128. package/src/browser/prefetch/cache.ts +2 -1
  129. package/src/browser/prefetch/fetch.ts +8 -16
  130. package/src/browser/prefetch/queue.ts +4 -4
  131. package/src/browser/react/NavigationProvider.tsx +2 -1
  132. package/src/browser/react/filter-segment-order.ts +2 -2
  133. package/src/browser/react/use-action.ts +24 -48
  134. package/src/browser/react/use-handle.ts +22 -18
  135. package/src/browser/react/use-link-status.ts +48 -60
  136. package/src/browser/react/use-navigation.ts +92 -41
  137. package/src/browser/rsc-router.tsx +1 -0
  138. package/src/browser/segment-reconciler.ts +109 -53
  139. package/src/browser/server-action-bridge.ts +81 -61
  140. package/src/browser/types.ts +25 -5
  141. package/src/browser/wire-protocol.ts +43 -0
  142. package/src/cache/cache-key-utils.ts +11 -5
  143. package/src/cache/cache-runtime.ts +132 -75
  144. package/src/cache/cache-scope.ts +110 -64
  145. package/src/cache/cf/cf-cache-constants.ts +2 -2
  146. package/src/cache/cf/cf-cache-store.ts +486 -874
  147. package/src/cache/cf/cf-kv-utils.ts +1 -1
  148. package/src/cache/document-cache.ts +64 -46
  149. package/src/cache/handle-snapshot.ts +19 -7
  150. package/src/cache/read-through-swr.ts +20 -18
  151. package/src/cache/segment-codec.ts +55 -0
  152. package/src/cache/shell-snapshot.ts +2 -2
  153. package/src/cache/tag-invalidation.ts +6 -2
  154. package/src/cache/taint.ts +5 -3
  155. package/src/cache/types.ts +7 -3
  156. package/src/cache/vercel/vercel-cache-store.ts +243 -310
  157. package/src/handles/pushed-by.ts +1 -1
  158. package/src/prefetch-markers.ts +5 -16
  159. package/src/prerender/store.ts +76 -0
  160. package/src/prerender/warm-request.ts +8 -4
  161. package/src/prerender.ts +2 -2
  162. package/src/route-name.ts +8 -0
  163. package/src/router/error-handling.ts +22 -10
  164. package/src/router/instrument.ts +4 -3
  165. package/src/router/intercept-resolution.ts +82 -75
  166. package/src/router/loader-resolution.ts +5 -4
  167. package/src/router/match-api.ts +5 -5
  168. package/src/router/match-context.ts +23 -12
  169. package/src/router/match-handlers.ts +8 -20
  170. package/src/router/match-middleware/background-revalidation.ts +46 -57
  171. package/src/router/match-middleware/cache-lookup.ts +677 -726
  172. package/src/router/match-middleware/cache-store.ts +4 -8
  173. package/src/router/match-middleware/intercept-resolution.ts +3 -23
  174. package/src/router/match-middleware/segment-resolution.ts +34 -61
  175. package/src/router/middleware.ts +69 -11
  176. package/src/router/navigation-snapshot.ts +14 -4
  177. package/src/router/prerender-match.ts +100 -44
  178. package/src/router/preview-match.ts +6 -41
  179. package/src/router/request-classification.ts +13 -7
  180. package/src/router/route-snapshot.ts +2 -5
  181. package/src/router/router-context.ts +10 -95
  182. package/src/router/router-interfaces.ts +8 -14
  183. package/src/router/segment-resolution/helpers.ts +49 -13
  184. package/src/router/segment-resolution/loader-cache.ts +15 -9
  185. package/src/router/segment-resolution/loader-mask.ts +5 -5
  186. package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
  187. package/src/router/segment-resolution/resolution-pass.ts +139 -0
  188. package/src/router/segment-resolution/revalidation.ts +939 -789
  189. package/src/router/segment-resolution/streamed-handler-boundary.ts +3 -0
  190. package/src/router/segment-resolution.ts +4 -13
  191. package/src/router/segment-wrappers.ts +51 -269
  192. package/src/router/telemetry.ts +5 -0
  193. package/src/router/types.ts +11 -1
  194. package/src/router.ts +19 -17
  195. package/src/rsc/full-payload.ts +6 -5
  196. package/src/rsc/handler-context.ts +8 -14
  197. package/src/rsc/handler.ts +126 -507
  198. package/src/rsc/json-route-result.ts +5 -9
  199. package/src/rsc/loader-fetch.ts +6 -5
  200. package/src/rsc/progressive-enhancement.ts +5 -0
  201. package/src/rsc/request-stages.ts +759 -0
  202. package/src/rsc/response-cache-serve.ts +10 -14
  203. package/src/rsc/response-route-handler.ts +13 -5
  204. package/src/rsc/rewrite-passes.ts +2 -1
  205. package/src/rsc/routine-plan.ts +1 -1
  206. package/src/rsc/rsc-rendering.ts +164 -349
  207. package/src/rsc/server-action.ts +87 -113
  208. package/src/rsc/shell-capture-constants.ts +1 -1
  209. package/src/rsc/shell-capture.ts +275 -227
  210. package/src/rsc/shell-serve.ts +121 -18
  211. package/src/rsc/ssr-setup.ts +5 -4
  212. package/src/segment-system.tsx +3 -3
  213. package/src/server/context.ts +22 -25
  214. package/src/server/handle-store.ts +55 -0
  215. package/src/server/render-pass.ts +291 -0
  216. package/src/server/request-context.ts +75 -115
  217. package/src/server/rewrite-trail.ts +6 -4
  218. package/src/ssr/index.tsx +1 -1
  219. package/src/testing/dispatch.ts +226 -710
  220. package/src/testing/e2e/page-helpers.ts +2 -2
  221. package/src/testing/render-route.tsx +199 -13
  222. package/src/testing/serve-shell-request.ts +36 -40
  223. package/src/types/cache-types.ts +6 -3
  224. package/src/types/error-types.ts +30 -3
  225. package/src/types/handler-context.ts +12 -1
  226. package/src/types/segments.ts +1 -1
  227. package/src/vite/discovery/build-discovery-phase.ts +204 -0
  228. package/src/vite/discovery/build-env.ts +148 -0
  229. package/src/vite/discovery/bundle-scan-phase.ts +128 -0
  230. package/src/vite/discovery/dev-prerender-cache.ts +8 -3
  231. package/src/vite/discovery/dev-server-phase.ts +1776 -0
  232. package/src/vite/discovery/discover-routers.ts +1 -1
  233. package/src/vite/discovery/discovery-errors.ts +1 -1
  234. package/src/vite/discovery/prerender-collection.ts +24 -39
  235. package/src/vite/discovery/state.ts +15 -0
  236. package/src/vite/plugins/version-plugin.ts +1 -1
  237. package/src/vite/plugins/virtual-entries.ts +1 -1
  238. package/src/vite/router-discovery.ts +29 -2428
  239. package/src/vite/temp-rsc-server.ts +223 -0
  240. package/src/vite/utils/prerender-utils.ts +47 -0
  241. package/src/wire-params.ts +40 -0
  242. package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
  243. package/src/router/segment-resolution/fresh.ts +0 -945
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Derived render passes over a request past its middleware (PPR shell
3
+ * capture, PPR HIT tail, background re-render, document cache re-run), each
4
+ * `Object.create(base)`.
5
+ * A field missing from a RENDER_PASS_FIELDS row reads the foreground
6
+ * request's value (#684). derived-context-shape.rsc-test.tsx pins each row's
7
+ * own keys.
8
+ */
9
+ import type { RecordingShellStore } from "../cache/shell-snapshot.js";
10
+ import type { HandleStore } from "./handle-store.js";
11
+ import { type RequestContext } from "./request-context.js";
12
+ type ShellImplicitCache = NonNullable<RequestContext["_shellImplicitCache"]>;
13
+ /** _handleStore, readonly on RequestContext, is written by the rows. */
14
+ type PassUnderConstruction = RequestContext<any> & {
15
+ _handleStore: HandleStore;
16
+ };
17
+ /** What each purpose's caller builds for its row. */
18
+ export interface RenderPassInit {
19
+ "shell-capture": {
20
+ handleStore: HandleStore;
21
+ /** A navigation-only capture renders this URL instead of the request's. */
22
+ identity: {
23
+ request: Request;
24
+ url: URL;
25
+ } | undefined;
26
+ /** Only with a cache store on the request. */
27
+ recording: {
28
+ store: RecordingShellStore;
29
+ implicitCache: ShellImplicitCache;
30
+ } | undefined;
31
+ };
32
+ "ppr-tail": {
33
+ /** The request's store, shared: the tail's handles are this response's. */
34
+ handleStore: HandleStore;
35
+ loaderSeed: RequestContext["_shellLoaderSeed"];
36
+ implicitCache: ShellImplicitCache;
37
+ };
38
+ "background-revalidation": {
39
+ handleStore: HandleStore;
40
+ /** Throwaway: the pass's response writes land here and are dropped. */
41
+ sink: RequestContext<any>;
42
+ };
43
+ "document-revalidation": {
44
+ /** The request's: the stale HIT pushed nothing into it. */
45
+ handleStore: HandleStore;
46
+ /**
47
+ * Holds the re-run's response writes, which make the response the
48
+ * document cache stores; starts from the request's response stub.
49
+ */
50
+ sink: RequestContext<any>;
51
+ };
52
+ }
53
+ export type RenderPurpose = keyof RenderPassInit;
54
+ interface PassFieldPolicy<I> {
55
+ /** "own": wireRenderBarrier(pass, init.handleStore) before `own` runs. */
56
+ readonly renderBarrier: "own" | "inherited";
57
+ /**
58
+ * Named stores, not one Object.assign: on Node 24 an Object.assign that
59
+ * takes the object to 20 own properties leaves it in V8 dictionary mode
60
+ * (#1109).
61
+ */
62
+ readonly own: (pass: PassUnderConstruction, init: I, base: RequestContext<any>) => void;
63
+ }
64
+ export declare const RENDER_PASS_FIELDS: {
65
+ readonly [P in RenderPurpose]: PassFieldPolicy<RenderPassInit[P]>;
66
+ };
67
+ /**
68
+ * `Object.create(base)` with RENDER_PASS_FIELDS[purpose]'s own fields. The only
69
+ * place a request context is derived (tools/check-internals.mjs).
70
+ */
71
+ export declare function deriveRenderPass<P extends RenderPurpose, TEnv>(base: RequestContext<TEnv>, purpose: P, init: RenderPassInit[P]): RequestContext<TEnv>;
72
+ export {};
@@ -29,6 +29,7 @@ import type { RenderMode, RenderPhase } from "../router/timeout.js";
29
29
  import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
30
30
  import type { RoutineTrace } from "../rsc/routine-plan.js";
31
31
  import type { ActionContinuation } from "../rsc/server-action.js";
32
+ import type { ShellCaptureState } from "../rsc/shell-capture.js";
32
33
  import type { FormActionOutcome } from "../rsc/progressive-enhancement.js";
33
34
  import { type ExecutionStart } from "../cache/invalidation-order.js";
34
35
  export interface RenderForegroundCursor {
@@ -182,8 +183,8 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
182
183
  method: string;
183
184
  /**
184
185
  * @internal Handle store for tracking handle data across segments.
185
- * Readonly: a background render that needs its own store derives a context
186
- * (rerenderAndCacheRoute, shell-capture.ts) instead of swapping this field,
186
+ * Readonly: a render that needs its own store derives a render pass
187
+ * (deriveRenderPass, server/render-pass.ts) instead of swapping this field,
187
188
  * which the foreground still reads while it produces the page.
188
189
  */
189
190
  readonly _handleStore: HandleStore;
@@ -233,52 +234,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
233
234
  */
234
235
  _searchParamsFilter?: import("../cache/search-params-filter.js").SearchParamsFilter;
235
236
  /**
236
- * @internal PPR shell-capture ACTIVE marker. True ONLY inside the background
237
- * capture task's derived request context (built by shell-capture.ts). This is
238
- * the switch every capture-specific behavior reads: loader masking
239
- * (loader-mask.ts isShellCaptureActive / fresh.ts emitStreaming) and the
240
- * identity-read capture guard (server/context.ts guardIdentityRead). The
241
- * foreground render never sets it, so the
242
- * served response is byte-identical to axis 1. The capture descriptor itself
243
- * (key/ttl/swr/tags/store) is NOT threaded through the request context — the
244
- * integrated PPR serve path (rsc/shell-serve.ts + rsc-rendering.ts) builds it
245
- * locally and passes it to scheduleShellCapture directly.
246
- */
247
- _shellCaptureRun?: boolean;
248
- /**
249
- * @internal Set beside `_shellCaptureRun` when the shell is keyed by the
250
- * visitor's URL (`rewrite(...).shell("visitor")`): the capture renders the
251
- * visitor's location and `ctx.rewrittenFrom`; the theme stays the default.
252
- */
253
- _shellCaptureForVisitor?: boolean;
254
- /**
255
- * @internal Bake-lane loader containers collected DURING a shell capture:
256
- * segment-key -> the loader's (pre-wrap) result promise. Populated by
257
- * resolveLoaderData for bake-lane loaders (lane rule: see its JSDoc in
258
- * loader-cache.ts). Drained by captureAndStoreShell after the shell
259
- * quiesces: settled containers are promise-elided, Flight-serialized, and
260
- * pinned into the snapshot's loader family; a REJECTED container refuses
261
- * the capture (error UI must never bake into the shared shell). Own
262
- * property of the capture's derived context only.
263
- */
264
- _shellCaptureLoaderRecords?: Map<string, Promise<unknown>>;
265
- /**
266
- * @internal Set on a capture's derived context when a loader pushed a
267
- * value the record cannot keep (masked nested promises, a pushed promise
268
- * that settled to one, a live-lane loader's push, or a push outside a
269
- * loader body): the loader records then carry `runs: 1`, so a HIT still
270
- * runs their bodies for those pushes.
271
- */
272
- _shellCaptureUnrecordedLoaderPush?: true;
273
- /**
274
- * @internal The lane of each loader the capture's matched route registers
275
- * (loader-cache.ts routeLoaderLanes), set by createMatchContextForFull
276
- * before any loader runs. The capture's push funnel credits a push made
277
- * under a live-lane loader's body, at any depth, to that loader
278
- * (shell-capture.ts deriveShellCaptureContext). Own property of the
279
- * capture's derived context only.
280
- */
281
- _shellCaptureLoaderLanes?: ReadonlyMap<string, "live" | "bake">;
237
+ * @internal A PPR shell capture's own state (rsc/shell-capture.ts
238
+ * ShellCaptureState): created by RENDER_PASS_FIELDS["shell-capture"]
239
+ * (server/render-pass.ts) on the capture's derived context. The foreground
240
+ * render and every background re-render never have one, so
241
+ * `_shellCaptureState?.run` is the capture switch.
242
+ */
243
+ _shellCaptureState?: ShellCaptureState;
282
244
  /**
283
245
  * @internal Record keys resolved for this request (CacheScope
284
246
  * resolveKeyFrom): by the scope's `key()` (one result) or its store's
@@ -295,9 +257,9 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
295
257
  _shellKey?: string;
296
258
  /**
297
259
  * @internal The request carried the forced-MISS reload marker
298
- * (shell-serve.ts SHELL_MISS_PARAM). The handler strips the marker from the
299
- * request on entry and sets this; the shell gate renders the request like a
300
- * cache miss.
260
+ * (`WIRE.shellMiss`). The handler strips the marker from the request on
261
+ * entry (shell-serve.ts withoutShellMissMarker) and sets this; the shell
262
+ * gate renders the request like a cache miss.
301
263
  */
302
264
  _shellForcedMiss?: true;
303
265
  /**
@@ -314,16 +276,6 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
314
276
  * runtime has no AsyncLocalStorage.snapshot.
315
277
  */
316
278
  _runAtRequestEntry?: <T>(fn: () => T) => T;
317
- /**
318
- * @internal The freshness window of the route cache() records this
319
- * request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
320
- * timestamps: `freshUntil` is the record's `expiresAt`, `staleUntil` adds
321
- * its scope's swr. The narrowest record wins. A shell capture caps its
322
- * entry's ttl and ttl+swr to it (shell-capture.ts capShellWindow), so a
323
- * shell is never fresher, or served longer, than the route cache() entry
324
- * it replayed or wrote.
325
- */
326
- _routeRecordWindow?: RouteRecordWindow;
327
279
  /**
328
280
  * @internal Loader-family snapshot seed for a shell HIT's tail render:
329
281
  * loader id -> the capture's elided container (already Flight-deserialized
@@ -445,30 +397,6 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
445
397
  * it as an own property for exactly that reason.
446
398
  */
447
399
  _shellFragmentPayload?: boolean;
448
- /**
449
- * @internal Set by the capture guard (server/context.ts
450
- * guardIdentityRead) when it throws DURING a capture render: the read
451
- * ("cookies()", "headers()", `ctx.get() for a non-cacheable variable`,
452
- * "ctx.theme") and the fix the
453
- * refusal warning gives for it. Load-bearing for the
454
- * bake lane: a guard throw inside an executing loader is swallowed by
455
- * wrapLoaderPromise into per-loader error UI, which would otherwise bake
456
- * silently into the shared shell — the capture checks this flag after the
457
- * render and refuses instead. Deterministic, so the capture does not retry.
458
- */
459
- _shellCaptureGuardTripped?: {
460
- surface: string;
461
- fix: string;
462
- };
463
- /**
464
- * @internal The loader $$id whose BODY was executing when the capture guard
465
- * tripped (read off the loader-body ALS scope at trip time), or undefined
466
- * when the read came from handler/render code. Only used to make the
467
- * once-per-key refusal warning name the real source — the old text
468
- * hardcoded "a bake-lane loader", which misattributed handler-land reads
469
- * and sent users debugging the wrong lane (issue #672, secondary).
470
- */
471
- _shellCaptureGuardTrippedLoaderId?: string;
472
400
  /**
473
401
  * @internal Handler-owned registry of explicit per-scope stores from
474
402
  * cache({ store }). Created once per createRSCHandler() and threaded into
@@ -732,8 +660,8 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
732
660
  * (loader(Def, { ssr: false })): segment resolution awaits these
733
661
  * before returning, so the render barrier cannot resolve until they settle.
734
662
  * rendered() checks this set to fail fast — a flagged loader awaiting the
735
- * barrier is a guaranteed cycle, not a race. Registered by resolveLoaders
736
- * (fresh.ts) before loader kickoff; only ever populated on document renders
663
+ * barrier is a guaranteed cycle, not a race. Registered by resolveOwnerLoaders
664
+ * before loader kickoff; only ever populated on document renders
737
665
  * (the flag is stamped per-isSSR at DSL evaluation).
738
666
  */
739
667
  _awaitBeforeFlushLoaderIds?: Set<string>;
@@ -755,6 +683,15 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
755
683
  _renderBarrierGuardClosed?: boolean;
756
684
  /** @internal Per-request error dedup set for onError reporting */
757
685
  _reportedErrors: WeakSet<object>;
686
+ /**
687
+ * @internal The segment a parallel slot's or orphan layout's error came
688
+ * from, for the owning entry's catch (segment-resolution/helpers.ts
689
+ * noteThrower). Per request: an error object can be thrown by several.
690
+ */
691
+ _throwers?: WeakMap<object, {
692
+ id: string;
693
+ type: string;
694
+ }>;
758
695
  /**
759
696
  * @internal The errors this request printed to the server console, so a
760
697
  * failure prints once where it originated (server/print-server-error.ts). A derived context shares it through the prototype.
@@ -811,6 +748,12 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
811
748
  * keeping phases that began before the opt-in at their true (non-negative) offset.
812
749
  */
813
750
  _handlerStart?: number;
751
+ /**
752
+ * @internal Handler-level Server-Timing entries (rsc/handler.ts): the
753
+ * bootstrap timings, then the core handler's classify. A stale document
754
+ * cache entry's re-run has its own (render-pass.ts).
755
+ */
756
+ _handlerTiming?: string[];
814
757
  /** @internal Resolved platform phase-span tracing for this request (Cloudflare or OTel) */
815
758
  _tracing?: ResolvedTracing;
816
759
  /** @internal Router basename for this request (used by redirect()) */
@@ -846,27 +789,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
846
789
  */
847
790
  _cacheSignal?: import("../router/telemetry.js").CacheSegmentSignal[];
848
791
  }
849
- /**
850
- * @internal The freshness window of a route cache() record, as ms
851
- * timestamps: fresh until `freshUntil` (its `expiresAt`), stale until
852
- * `staleUntil` (plus its scope's swr). `ttl`, `swr` and `written` describe
853
- * the record that sets `staleUntil`: its cache() config, and whether this
854
- * request wrote it (cacheRoute) rather than read it.
855
- */
856
- export interface RouteRecordWindow {
857
- freshUntil: number;
858
- staleUntil: number;
859
- ttl: number;
860
- swr: number;
861
- written: boolean;
862
- }
863
792
  /**
864
793
  * Public view of RequestContext, without internal methods and fields.
865
794
  *
866
795
  * This is the type exported to library consumers. Internal code should
867
796
  * use the full RequestContext interface directly.
868
797
  */
869
- export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellCaptureForVisitor" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_routeName" | "_prevRouteKey" | "_visitorMoved" | "_inActionRevalidation" | "_actionRan" | "_reportedErrors" | "_printedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
798
+ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureState" | "_shellImplicitCache" | "_shellLoaderSeed" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_shellFragmentPayload" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_routeName" | "_prevRouteKey" | "_visitorMoved" | "_inActionRevalidation" | "_actionRan" | "_reportedErrors" | "_throwers" | "_printedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_handlerTiming" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
870
799
  /**
871
800
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
872
801
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -896,6 +825,26 @@ export declare function captureRequestEntryContext(): (<T>(fn: () => T) => T) |
896
825
  * Used by the RSC handler to provide context to server actions
897
826
  */
898
827
  export declare function runWithRequestContext<TEnv, T>(context: RequestContext<TEnv>, fn: () => T): T;
828
+ /**
829
+ * Run work whose output goes only to a cache, never to the response of the
830
+ * request that started it, on `context`: a stale entry's refresh (a "use
831
+ * cache" function, a cached loader, a cache() record, a document), a
832
+ * navigation's proactive cache() write, a PPR shell capture. No visitor made
833
+ * the invalidations in it, so they set no fresh-reads cookie
834
+ * (cache/tag-invalidation.ts), and onError marks every error reported inside
835
+ * it `background` (router/error-handling.ts invokeOnError). Its failure is
836
+ * reported inside it too: a catch outside runs on the visitor's frame.
837
+ */
838
+ export declare function runAsBackgroundWork<TEnv, T>(context: RequestContext<TEnv>, fn: () => T): T;
839
+ /** Whether the caller runs inside runAsBackgroundWork. */
840
+ export declare function isBackgroundWork(): boolean;
841
+ /**
842
+ * The set onError's dedupe records a reported error in. Background work keeps
843
+ * its own: an error object both the visitor's render and background work
844
+ * reach (a memoized rejection, a thrown constant) is reported by each, so a
845
+ * background report never takes the place of the visitor's.
846
+ */
847
+ export declare function reportedErrorsOf(context: RequestContext<any>): WeakSet<object>;
899
848
  /**
900
849
  * Get the current request context
901
850
  * Throws if called outside of a request context
@@ -1004,8 +953,8 @@ export declare function rebaseRequestContext(ctx: RequestContext<any>, request:
1004
953
  /**
1005
954
  * Wire a fresh render barrier onto `ctx`, closure-bound to THIS ctx and THIS
1006
955
  * handle store. Called by createRequestContext for every fresh context, and by
1007
- * deriveShellCaptureContext (rsc/shell-capture.ts) for the PPR capture's
1008
- * derived context.
956
+ * deriveRenderPass (server/render-pass.ts) for a derived pass whose
957
+ * RENDER_PASS_FIELDS row owns its barrier (the PPR capture and the HIT tail).
1009
958
  *
1010
959
  * The derived-context call is load-bearing (issue #684, plan 009): the capture
1011
960
  * context is `Object.create(reqCtx)`, so without its own wiring every
@@ -25,12 +25,12 @@ export declare function recordRewriteHop(reqCtx: TrailContext, from: URL, to: UR
25
25
  export declare function recordRewriteShell(reqCtx: TrailContext, audience: RewriteShell | undefined): void;
26
26
  /** The last hop's `rewrite(...).shell()` choice; undefined: none. */
27
27
  export declare function rewriteShellAudience(reqCtx: TrailContext | undefined): RewriteShell | undefined;
28
- type AudienceContext = Pick<RequestContext<any>, "_shellCaptureRun" | "_documentCacheRender" | "res">;
28
+ type AudienceContext = Pick<RequestContext<any>, "_shellCaptureState" | "_documentCacheRender" | "res">;
29
29
  /**
30
30
  * A render other visitors may be served: a PPR shell capture, or a render
31
31
  * the document cache stores (its response opted in before next()). It shows
32
32
  * no visitor theme, and no visitor URL unless it is a visitor-keyed shell
33
- * capture (`_shellCaptureForVisitor`).
33
+ * capture (`_shellCaptureState.forVisitor`).
34
34
  */
35
35
  export declare function rendersForSharedAudience(reqCtx: AudienceContext): boolean;
36
36
  /**
@@ -2,9 +2,12 @@
2
2
  * dispatch — in-process request -> Response for unit/integration tests,
3
3
  * WITHOUT the Flight RSC runtime.
4
4
  *
5
- * dispatch runs the router's real matching and middleware execution so that
6
- * redirects, 404s, response routes (path.json / path.text / path.html / ...),
7
- * and middleware short-circuits behave exactly as in production. It deliberately
5
+ * dispatch runs the production handler's request stages
6
+ * (rsc/request-stages.ts: classify, the terminal plans, the global middleware
7
+ * passes, the response route and the response's finalization) so that
8
+ * redirects, 404s, reloads, response routes (path.json / path.text /
9
+ * path.html / ...), and middleware short-circuits behave exactly as in
10
+ * production. It deliberately
8
11
  * does NOT render React Server Components: there is no Flight stream, no SSR,
9
12
  * and no DOM. Hit an RSC (component) route and dispatch throws a clear error
10
13
  * directing you to renderToFlightString/renderServerTree/renderHandler or an e2e test.
@@ -17,19 +20,20 @@
17
20
  * so a global auth middleware can 401/redirect them and middleware-set
18
21
  * cookies/headers merge onto the 308/404 the way createResponseWithMergedHeaders
19
22
  * merges them in production.
20
- * - Response routes (non-RSC) -> serialized Response
23
+ * - Response routes (non-RSC), served by production's handleResponseRoute
24
+ * (rsc/response-route-handler.ts) -> serialized Response
21
25
  * - json: JSON.stringify(result) (bare value) with application/json
22
26
  * - text/html/xml/md: String(result) with the mapped MIME type
23
- * - handler returning or throwing a Response: re-wrapped like
24
- * handleResponseRoute (stub headers/cookies merged, Set-Cookie preserved,
25
- * WebSocket upgrade passed through without reconstruction)
27
+ * - handler returning or throwing a Response: re-wrapped (stub
28
+ * headers/cookies merged, Set-Cookie preserved, WebSocket upgrade passed
29
+ * through without reconstruction)
26
30
  * - handler throwing a non-Response error: typed 500 / RouterError
27
- * status, matching handleResponseRoute (RFC 9457 problem+json body with
28
- * application/problem+json for json routes, text/plain message otherwise)
31
+ * status (RFC 9457 problem+json body with application/problem+json for
32
+ * json routes, text/plain message otherwise)
29
33
  * - content-negotiated route: Vary: Accept appended
30
34
  * - cached response route (cache({...})): getResponse/putResponse
31
- * hit/SWR/tag write, resolved from the matched entry tree exactly as
32
- * handleResponseRoute does. The write is scheduled via ctx.waitUntil
35
+ * hit/SWR/tag write, resolved from the matched entry tree. The write is
36
+ * scheduled via ctx.waitUntil
33
37
  * (a microtask without an executionContext), so a HIT-asserting test must
34
38
  * flush microtasks between the seeding dispatch and the asserting one.
35
39
  * - Global middleware (router.use(...)) AND route-level middleware, with full
@@ -38,10 +42,17 @@
38
42
  * global middleware runs first (so an auth gate can still 401/redirect),
39
43
  * then — if it passes through — an X-RSC-Reload is returned. Route-level
40
44
  * middleware is skipped on a partial, exactly as production skips it.
41
- * - A middleware redirect (3xx + Location) on a partial/action request
42
- * (?_rsc_partial / ?_rsc_action): converted to a 204 + X-RSC-Redirect via the
43
- * real interceptRedirectForPartial, so fetch() does not auto-follow the 3xx —
45
+ * - A global middleware redirect (3xx + Location) on a partial/action request
46
+ * (?_rsc_partial / ?_rsc_action), and a findMatch() redirect on a partial
47
+ * request: a 204 + X-RSC-Redirect, so fetch() does not auto-follow the 3xx —
44
48
  * identical to production's no-location-state path.
49
+ * - The terminal plans production answers inside the global chain
50
+ * (terminalPlanResponse): a `_rsc_v` version mismatch and a `_rsc_rid` app
51
+ * switch reload (X-RSC-Reload), and an action (?_rsc_action) a rewrite moved
52
+ * to a target that is not a page route throws production's error.
53
+ * - Route params and name are set inside the global chain, after classify, by
54
+ * the stage production's executeRequest runs (recordPlanRoute): global
55
+ * middleware sees them after next(), not before it.
45
56
  * - The open-redirect guard (rsc/redirect-guard.ts) on full (browser-followed)
46
57
  * redirects: a cross-origin Location is rewritten to the basename root unless
47
58
  * redirect(url, { external: true }) opted out, mirroring production's single
@@ -60,7 +71,9 @@
60
71
  * after finalizeResponse (segmentCount 0 / cacheHit false — dispatch renders no
61
72
  * RSC segments and holds no match-cache state), and a thrown non-Response error
62
73
  * emits request.error with phase "routing". All three carry the same requestId
63
- * (getRequestId). Emission is gated entirely on a configured sink; with none,
74
+ * (getRequestId), as does a response-route timeout on a rewritten pass
75
+ * (runRequestPasses carries the id to each pass's request, as in
76
+ * production). Emission is gated entirely on a configured sink; with none,
64
77
  * dispatch does zero new work and stays byte-identical for existing callers.
65
78
  * Lets a consumer unit-test their sink wiring in-process instead of only at e2e.
66
79
  * - Response-route `renderStartMs` timeouts and `onTimeout`: dispatch races the
@@ -96,9 +109,13 @@
96
109
  * request.start/end/error lifecycle above; cover cache/loader telemetry with an
97
110
  * e2e test driving a real RSC request.
98
111
  *
99
- * dispatch reuses router.previewMatch(), which itself runs content negotiation
100
- * and resolves route middleware from the matched entry tree, so dispatch's
101
- * route-middleware collection is exactly the router's, not a re-implementation.
112
+ * Each pass is classified with the handler's classify stage
113
+ * (router/request-classification.ts classifyRequest), which runs content
114
+ * negotiation and resolves route middleware from the matched entry tree, so
115
+ * dispatch's route-middleware collection is exactly the router's, not a
116
+ * re-implementation. The origin guard is not run: it gates only the action,
117
+ * loader and PE-form plans, which classify gives a component route only, and
118
+ * dispatch throws on those before the pass's middleware.
102
119
  */
103
120
  import type { Rango } from "../router/router-interfaces.js";
104
121
  /**
@@ -26,24 +26,30 @@
26
26
  * - navigate() drives the navigation lifecycle as a click does:
27
27
  * useNavigation() reads loading from the call and idle with the commit,
28
28
  * and useLinkStatus().pending is true for a link to the destination until
29
- * the commit is handed to React. A `transition` spec plus a pending
29
+ * the commit, which React holds with it. A `transition` spec plus a pending
30
30
  * Promise seeded via navigate(url, { loaders }) commits through
31
31
  * production's commitInTransition (browser/partial-update.ts), which React
32
32
  * holds: useNavigation() stays loading and the held reader's
33
33
  * useLoader().isLoading reads true until the data lands. Without
34
34
  * `transition` the commit is urgent (production's same-structure hold is
35
- * not modeled). useAction().state stays idle: no action runs.
35
+ * not modeled). navigate(url, { streamUntil }) gives the navigation a
36
+ * response stream that stays open past the commit (isStreaming).
37
+ * useAction().state stays idle: no action runs.
36
38
  * - A spec's transition({ when }) decides every commit with production's
37
39
  * browser decision: navigate() and useRouter().push model kind "push",
38
- * useRouter().replace kind "replace", refresh() kind "revalidate".
39
- * Back/forward, action and optimistic clientUrls() swap decisions are
40
- * e2e territory.
40
+ * useRouter().replace kind "replace", refresh() kind "revalidate", and a
41
+ * back/forward that restores a page kind "pop". Action and optimistic
42
+ * clientUrls() swap decisions are e2e territory.
41
43
  * - Location state reaches readers the way it does in production:
42
44
  * NavigationProvider holds the committed entry's state next to the
43
45
  * payload, so a navigation whose loader the test holds keeps the entry
44
46
  * being left on screen with its own state. A `popstate` event is a
45
- * back/forward onto the entry history.state holds; the tree has one
46
- * location, so no page is restored with it. A server action's state, a
47
+ * back/forward onto the entry history.state holds. When it is the
48
+ * mounted entry or one a navigate() wrote, history still holds the state
49
+ * written there, and another page is on screen, its page is restored
50
+ * from the history cache, with the handle values it had, as production's
51
+ * restore is; otherwise the tree keeps its location. A stale entry's
52
+ * revalidation, a restore that fetches, a server action's state, a
47
53
  * redirect's and an intercept's are e2e territory.
48
54
  * What it DOES cover: client hooks that read NavigationProvider /
49
55
  * OutletContext — useParams, useReverse, useHref, useMount, useNavigation,
@@ -361,8 +367,37 @@ export interface TestRouterHandle {
361
367
  * `handles`). They arrive on the response's handle stream, so `useHandle`
362
368
  * readers take them with the page's commit: while React holds the page,
363
369
  * readers keep the values of the page being left.
370
+ *
371
+ * `options.streamUntil` gives the navigation a response stream, as a real
372
+ * response has: it opens in a task after the call, before the commit (the
373
+ * response arrives, and `useNavigation().pendingUrl` clears), and stays open
374
+ * until the promise settles (a page that streams a tail past its commit:
375
+ * `isStreaming` reads true until then). Without it the navigation has no
376
+ * stream. A navigation that a newer one or a back/forward aborts before its
377
+ * response arrives opens none and commits nothing; one aborted after its
378
+ * response arrived stops counting as streaming at the abort, as in
379
+ * production, where its response streams on and is ignored.
380
+ *
381
+ * @example
382
+ * const tail = deferred();
383
+ * await router.navigate("/products/2", { streamUntil: tail.promise });
384
+ * // useNavigation(): idle, isStreaming true
385
+ * await act(async () => tail.resolve());
386
+ * // useNavigation(): idle, isStreaming false
387
+ *
388
+ * A navigation started while React holds a page goes inside
389
+ * `await act(async () => ...)`. Its first update makes React retry the held
390
+ * page, which suspends again; a synchronous act() scope drops that retry
391
+ * and React renders no later update of the same priority.
392
+ *
393
+ * @example
394
+ * await act(async () => {
395
+ * await router.navigate("/products/3", { transition: false });
396
+ * });
364
397
  */
365
- navigate(url: string, options?: Pick<RenderRouteOptions, "loaders" | "handles"> & Pick<NavigateOptions, "state" | "replace" | "transition">): Promise<void>;
398
+ navigate(url: string, options?: Pick<RenderRouteOptions, "loaders" | "handles"> & Pick<NavigateOptions, "state" | "replace" | "transition"> & {
399
+ streamUntil?: Promise<unknown>;
400
+ }): Promise<void>;
366
401
  /**
367
402
  * Re-render the current location, as router.refresh() does: a spec's
368
403
  * transition({ when }) decides it with kind "revalidate" (`to` is `from`).
@@ -81,7 +81,13 @@ export interface ServeShellRequestOptions<TEnv = any> {
81
81
  * and segments take an action's revalidation defaults; it renders live, as
82
82
  * an action does, so neither the route cache nor the document cache answers
83
83
  * or stores it, and a `ppr` route's `replayStatus` is
84
- * `{ outcome: "BYPASS", reason: "stale" }`.
84
+ * `{ outcome: "BYPASS", reason: "stale" }`. `boundary` names the error
85
+ * segment of a thrown action's boundary the page at `from` shows
86
+ * (`_rsc_boundary`), as the follow-up an earlier action owes that page
87
+ * sends it, with `stale: true` and no `segments`: the response renders
88
+ * every segment above the boundary and nothing at or below it, claims the
89
+ * boundary in `matched` and sends no segment for it. The server reads it
90
+ * only beside `stale`.
85
91
  */
86
92
  partial?: true | {
87
93
  from?: string;
@@ -91,6 +97,7 @@ export interface ServeShellRequestOptions<TEnv = any> {
91
97
  fill?: boolean;
92
98
  interceptSource?: string;
93
99
  stale?: boolean;
100
+ boundary?: string;
94
101
  };
95
102
  /**
96
103
  * POST this form as a submit before hydration: the no-JS request the
@@ -130,9 +130,12 @@ export interface CacheOptions<TEnv = unknown> {
130
130
  */
131
131
  condition?: (ctx: import("../server/request-context.js").RequestContext<TEnv>) => boolean;
132
132
  /**
133
- * Custom cache key function - FULL OVERRIDE.
134
- * Bypasses default key generation AND store's keyGenerator. The result is
135
- * stored namespaced (`key:` plus its URI encoding), so no value it returns
133
+ * Custom cache key function. Replaces the URL part of the default key
134
+ * (host, path, params, search) AND bypasses the store's keyGenerator. The
135
+ * request kind stays: a document request, a navigation and each intercept
136
+ * navigation keep their own record under one result, so the result decides
137
+ * which requests of one kind share a record. It is stored namespaced
138
+ * (`key:` plus its URI encoding, then the kind), so no value it returns
136
139
  * names another route's record; a nested cache() keys its records within
137
140
  * this partition.
138
141
  *
@@ -67,11 +67,38 @@ export interface OnErrorContext<TEnv = any> {
67
67
  actionId?: string;
68
68
  /** Environment/bindings (platform context) */
69
69
  env?: TEnv;
70
- /** Duration from request start to error (milliseconds) */
70
+ /**
71
+ * Duration from request start to error (milliseconds). For a `background`
72
+ * error it counts from the start of the request that started the work, so
73
+ * it includes that response and any wait before the work ran.
74
+ */
71
75
  duration?: number;
72
- /** Whether this is a partial/navigation request */
76
+ /**
77
+ * Whether this is a partial/navigation request, on an error the segment
78
+ * walk catches (a handler that throws, a streamed `loading()` handler that
79
+ * rejects, a DSL loader that rejects): `true` for a navigation, unset for a
80
+ * document. A `cache()` record's refresh or proactive write reports the
81
+ * request that started it; a PPR shell capture renders a document. The
82
+ * `routing` phase reports `false`.
83
+ */
73
84
  isPartial?: boolean;
74
- /** Whether an error boundary caught the error */
85
+ /**
86
+ * `true` when the error came from work whose output goes to a cache and
87
+ * never to the response of the request that started it: a stale `cache()`
88
+ * record's refresh, the write of a navigation that kept a layout mounted, a
89
+ * stale document cache entry's re-run, a PPR shell capture, or a stale
90
+ * `"use cache"` function's or cached loader's refresh, the work's own
91
+ * failure included. `request` and `url` are the starting request's (a
92
+ * shell capture's handler errors name the page it captures). A
93
+ * `router.prerender()` warm's own render is its request's: unset, while a
94
+ * shell capture it makes is `true`. Unset for every other error.
95
+ */
96
+ background?: boolean;
97
+ /**
98
+ * Whether an error boundary caught the error and its fallback reached the
99
+ * response. `false` on a `background` error: the failed render is never
100
+ * stored, so no visitor sees the fallback.
101
+ */
75
102
  handledByBoundary?: boolean;
76
103
  /** Stack trace (if available) */
77
104
  stack?: string;
@@ -342,7 +342,7 @@ export type InternalHandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch exte
342
342
  _reverseScope?: import("../server/context.js").ReverseScope;
343
343
  /**
344
344
  * @internal The on-demand overlay holds a "removed" marker for this request
345
- * (tryPrerenderLookup, cache-lookup.ts); gateOnDemandProducer reads it. On
345
+ * (readPrerenderSource, cache-lookup.ts); gateOnDemandProducer reads it. On
346
346
  * this context, not the request's: withCacheLookup documents that the
347
347
  * request ALS can be lost mid-pipeline on workerd.
348
348
  */
@@ -390,6 +390,14 @@ export type InternalHandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch exte
390
390
  * request is a fill. See router/segment-resolution/prefetch-deferral.ts.
391
391
  */
392
392
  _prefetchDeferral?: import("../router/segment-resolution/prefetch-deferral.js").PrefetchDeferral;
393
+ /**
394
+ * @internal DSL loaders registered and not started, by `$$id`: a prefetch
395
+ * deferred them, or a pass that skips loaders (`skipLoaders`) did not run
396
+ * them. A reader's ctx.use() starts one through its registration
397
+ * (registerDeferredLoader, startDeferredLoader in
398
+ * router/segment-resolution/prefetch-deferral.ts).
399
+ */
400
+ _deferredLoaders?: Map<string, import("../router/segment-resolution/prefetch-deferral.js").DeferredLoader>;
393
401
  /**
394
402
  * @internal Whether a loader was started in this request: a run of it (a
395
403
  * handler's or another loader's ctx.use()) or its cache() binding. A
@@ -151,7 +151,7 @@ export interface ResolvedSegment {
151
151
  loaderData?: any;
152
152
  /**
153
153
  * True when this loader was awaited before first flush
154
- * (loader(Def, { ssr: false })). Stamped by resolveLoaders (fresh.ts) on
154
+ * (loader(Def, { ssr: false })). Stamped by resolveOwnerLoaders on
155
155
  * document AND shell-capture renders — capture bakes flagged loaders and
156
156
  * awaits the same lane. Feeds segment-system's settled-value delivery and
157
157
  * the dev SSR suspension warning (ssr-suspension-warning.ts).