@rangojs/router 0.24.4 → 0.26.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 (301) hide show
  1. package/README.md +1 -0
  2. package/dist/bin/rango.js +363 -39
  3. package/dist/testing/vitest.js +37 -4
  4. package/dist/types/browser/event-controller.d.ts +24 -5
  5. package/dist/types/browser/intercept-utils.d.ts +5 -2
  6. package/dist/types/browser/merge-segment-loaders.d.ts +0 -23
  7. package/dist/types/browser/navigation-transaction.d.ts +5 -5
  8. package/dist/types/browser/partial-update.d.ts +21 -13
  9. package/dist/types/browser/prefetch/cache.d.ts +8 -0
  10. package/dist/types/browser/rango-marker.d.ts +7 -0
  11. package/dist/types/browser/react/filter-segment-order.d.ts +10 -0
  12. package/dist/types/browser/react/use-handle.d.ts +20 -0
  13. package/dist/types/browser/react/use-href.d.ts +6 -0
  14. package/dist/types/browser/react/use-router.d.ts +6 -1
  15. package/dist/types/browser/response-adapter.d.ts +5 -3
  16. package/dist/types/browser/scroll-restoration.d.ts +9 -3
  17. package/dist/types/browser/segment-reconciler.d.ts +10 -13
  18. package/dist/types/browser/types.d.ts +38 -8
  19. package/dist/types/build/route-types/per-module-writer.d.ts +12 -0
  20. package/dist/types/cache/cf/cf-cache-store.d.ts +0 -2
  21. package/dist/types/cache/cf/cf-cache-types.d.ts +0 -16
  22. package/dist/types/cache/cf/cf-shell-frame.d.ts +2 -0
  23. package/dist/types/cache/handle-snapshot.d.ts +2 -2
  24. package/dist/types/cache/types.d.ts +16 -6
  25. package/dist/types/cache/vercel/vercel-cache-store.d.ts +1 -15
  26. package/dist/types/client-urls/client-urls.d.ts +6 -2
  27. package/dist/types/client-urls/revalidate-registry.d.ts +1 -1
  28. package/dist/types/client-urls/server-projection.d.ts +9 -5
  29. package/dist/types/client-urls/types.d.ts +29 -16
  30. package/dist/types/client.d.ts +2 -2
  31. package/dist/types/client.rsc.d.ts +2 -2
  32. package/dist/types/decode-loader-results.d.ts +28 -7
  33. package/dist/types/handles/deferred-resolution.d.ts +3 -2
  34. package/dist/types/handles/meta.d.ts +5 -0
  35. package/dist/types/href-client.d.ts +3 -1
  36. package/dist/types/index.rsc.d.ts +1 -1
  37. package/dist/types/loader-redirect.d.ts +2 -3
  38. package/dist/types/outlet-context.d.ts +7 -6
  39. package/dist/types/prefetch-markers.d.ts +14 -5
  40. package/dist/types/prerender/build-shell-capture.d.ts +1 -2
  41. package/dist/types/prerender/writable-store.d.ts +2 -3
  42. package/dist/types/route-content-wrapper.d.ts +17 -14
  43. package/dist/types/route-definition/helpers-types.d.ts +7 -2
  44. package/dist/types/route-definition/resolve-handler-use.d.ts +6 -1
  45. package/dist/types/route-definition/rewrite.d.ts +48 -5
  46. package/dist/types/route-types.d.ts +2 -2
  47. package/dist/types/router/handler-context.d.ts +14 -2
  48. package/dist/types/router/intercept-resolution.d.ts +19 -46
  49. package/dist/types/router/lazy-includes.d.ts +7 -0
  50. package/dist/types/router/match-middleware/intercept-resolution.d.ts +2 -2
  51. package/dist/types/router/middleware.d.ts +0 -16
  52. package/dist/types/router/navigation-snapshot.d.ts +2 -0
  53. package/dist/types/router/prefetch-cache-ttl.d.ts +8 -11
  54. package/dist/types/router/revalidation.d.ts +8 -1
  55. package/dist/types/router/router-context.d.ts +4 -16
  56. package/dist/types/router/router-interfaces.d.ts +0 -11
  57. package/dist/types/router/router-options.d.ts +4 -27
  58. package/dist/types/router/segment-resolution/mask-nested.d.ts +5 -3
  59. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +31 -8
  60. package/dist/types/router/segment-resolution/revalidation.d.ts +38 -4
  61. package/dist/types/router/segment-resolution.d.ts +1 -1
  62. package/dist/types/router/segment-wrappers.d.ts +3 -5
  63. package/dist/types/router/substitute-pattern-params.d.ts +3 -2
  64. package/dist/types/router/tracing.d.ts +2 -2
  65. package/dist/types/router-versions.d.ts +8 -6
  66. package/dist/types/rsc/full-payload.d.ts +14 -2
  67. package/dist/types/rsc/helpers.d.ts +8 -0
  68. package/dist/types/rsc/manifest-init.d.ts +20 -0
  69. package/dist/types/rsc/prefetch-render-error.d.ts +22 -0
  70. package/dist/types/rsc/progressive-enhancement.d.ts +20 -0
  71. package/dist/types/rsc/rewrite-passes.d.ts +12 -2
  72. package/dist/types/rsc/server-action.d.ts +6 -0
  73. package/dist/types/rsc/shell-capture-constants.d.ts +14 -4
  74. package/dist/types/rsc/shell-capture.d.ts +23 -2
  75. package/dist/types/rsc/types.d.ts +5 -8
  76. package/dist/types/segment-system.d.ts +15 -0
  77. package/dist/types/server/build-version-table.d.ts +10 -13
  78. package/dist/types/server/context.d.ts +90 -6
  79. package/dist/types/server/handle-store.d.ts +17 -6
  80. package/dist/types/server/request-context.d.ts +45 -7
  81. package/dist/types/server/request-headers.d.ts +12 -0
  82. package/dist/types/server/rewrite-trail.d.ts +8 -1
  83. package/dist/types/testing/build-versions.d.ts +0 -3
  84. package/dist/types/testing/e2e/index.d.ts +1 -1
  85. package/dist/types/testing/flight.entry.d.ts +1 -1
  86. package/dist/types/testing/index.d.ts +1 -1
  87. package/dist/types/testing/internal/client-urls-projection.d.ts +4 -3
  88. package/dist/types/testing/internal/seed-vars.d.ts +4 -4
  89. package/dist/types/testing/render-route.d.ts +21 -11
  90. package/dist/types/testing/run-loader.d.ts +7 -0
  91. package/dist/types/testing/run-middleware.d.ts +7 -0
  92. package/dist/types/testing/run-revalidate.d.ts +5 -4
  93. package/dist/types/testing/serve-shell-request.d.ts +42 -5
  94. package/dist/types/testing/shell-status.d.ts +17 -0
  95. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  96. package/dist/types/testing/vitest.d.ts +10 -1
  97. package/dist/types/thenable-status.d.ts +0 -6
  98. package/dist/types/types/handler-context.d.ts +12 -1
  99. package/dist/types/types/loader-types.d.ts +10 -4
  100. package/dist/types/types/route-entry.d.ts +2 -1
  101. package/dist/types/urls/path-helper-types.d.ts +4 -2
  102. package/dist/types/vite/discovery/client-urls-projection.d.ts +55 -5
  103. package/dist/types/vite/discovery/state.d.ts +20 -0
  104. package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +28 -16
  105. package/dist/types/vite/plugins/hoist/source.d.ts +8 -7
  106. package/dist/types/vite/plugins/virtual-entries.d.ts +6 -0
  107. package/dist/types/vite/utils/prerender-utils.d.ts +7 -0
  108. package/dist/vite/index.js +6819 -6555
  109. package/package.json +1 -1
  110. package/skills/app-structure/SKILL.md +255 -0
  111. package/skills/app-structure/content-site.md +333 -0
  112. package/skills/app-structure/e-commerce.md +435 -0
  113. package/skills/app-structure/large-app.md +885 -0
  114. package/skills/app-structure/multi-app.md +280 -0
  115. package/skills/breadcrumbs/SKILL.md +6 -1
  116. package/skills/cache-guide/SKILL.md +4 -8
  117. package/skills/caching/SKILL.md +6 -6
  118. package/skills/catalog.json +12 -0
  119. package/skills/client-urls/SKILL.md +185 -32
  120. package/skills/comparison/references/framework-comparison.md +1 -1
  121. package/skills/composability/SKILL.md +10 -8
  122. package/skills/handler-use/SKILL.md +48 -9
  123. package/skills/hooks/handle-and-actions.md +104 -0
  124. package/skills/hooks/navigation.md +24 -10
  125. package/skills/hooks/urls.md +1 -1
  126. package/skills/host-router/SKILL.md +1 -1
  127. package/skills/i18n/SKILL.md +2 -1
  128. package/skills/intercept/SKILL.md +60 -29
  129. package/skills/layout/SKILL.md +6 -3
  130. package/skills/links/SKILL.md +151 -17
  131. package/skills/loader/SKILL.md +42 -19
  132. package/skills/middleware/SKILL.md +111 -15
  133. package/skills/observability/SKILL.md +11 -0
  134. package/skills/parallel/SKILL.md +5 -5
  135. package/skills/ppr/SKILL.md +103 -52
  136. package/skills/prerender/SKILL.md +4 -5
  137. package/skills/rango/SKILL.md +3 -0
  138. package/skills/response-routes/SKILL.md +4 -1
  139. package/skills/router-setup/SKILL.md +0 -2
  140. package/skills/scripts/SKILL.md +12 -1
  141. package/skills/server-actions/SKILL.md +60 -20
  142. package/skills/testing/SKILL.md +1 -0
  143. package/skills/testing/client-components.md +13 -10
  144. package/skills/testing/loader.md +25 -24
  145. package/skills/testing/middleware.md +11 -11
  146. package/skills/testing/render-handler.md +17 -17
  147. package/skills/testing/response-routes.md +4 -1
  148. package/skills/testing/serve-shell-request.md +86 -22
  149. package/skills/testing/server-actions.md +16 -16
  150. package/skills/ux-architecture/SKILL.md +980 -0
  151. package/skills/vercel/SKILL.md +1 -1
  152. package/skills/view-transitions/SKILL.md +43 -10
  153. package/src/__augment-tests__/augmented.check.ts +28 -0
  154. package/src/browser/event-controller.ts +44 -18
  155. package/src/browser/intercept-utils.ts +3 -2
  156. package/src/browser/merge-segment-loaders.ts +0 -85
  157. package/src/browser/navigation-bridge.ts +112 -84
  158. package/src/browser/navigation-client.ts +20 -15
  159. package/src/browser/navigation-store.ts +4 -2
  160. package/src/browser/navigation-transaction.ts +9 -8
  161. package/src/browser/partial-update.ts +90 -32
  162. package/src/browser/prefetch/cache.ts +8 -0
  163. package/src/browser/prefetch/fetch.ts +13 -3
  164. package/src/browser/rango-marker.ts +13 -0
  165. package/src/browser/react/NavigationProvider.tsx +25 -7
  166. package/src/browser/react/filter-segment-order.ts +13 -0
  167. package/src/browser/react/use-action.ts +9 -15
  168. package/src/browser/react/use-handle.ts +63 -71
  169. package/src/browser/react/use-href.tsx +24 -5
  170. package/src/browser/react/use-link-status.ts +1 -1
  171. package/src/browser/react/use-navigation.ts +30 -40
  172. package/src/browser/react/use-router.ts +37 -6
  173. package/src/browser/react/use-segments.ts +8 -12
  174. package/src/browser/response-adapter.ts +11 -5
  175. package/src/browser/rsc-router.tsx +3 -1
  176. package/src/browser/scroll-restoration.ts +34 -20
  177. package/src/browser/segment-reconciler.ts +11 -29
  178. package/src/browser/server-action-bridge.ts +52 -16
  179. package/src/browser/types.ts +40 -8
  180. package/src/build/generate-manifest.ts +12 -1
  181. package/src/build/route-types/codegen.ts +6 -2
  182. package/src/build/route-types/per-module-writer.ts +94 -61
  183. package/src/cache/cache-runtime.ts +9 -0
  184. package/src/cache/cache-scope.ts +2 -1
  185. package/src/cache/cf/cf-cache-store.ts +6 -7
  186. package/src/cache/cf/cf-cache-types.ts +0 -17
  187. package/src/cache/cf/cf-shell-frame.ts +3 -0
  188. package/src/cache/handle-snapshot.ts +2 -2
  189. package/src/cache/types.ts +16 -6
  190. package/src/cache/vercel/vercel-cache-store.ts +8 -19
  191. package/src/client-urls/client-urls.ts +202 -153
  192. package/src/client-urls/revalidate-registry.ts +12 -3
  193. package/src/client-urls/server-projection.ts +137 -66
  194. package/src/client-urls/types.ts +30 -15
  195. package/src/client.rsc.tsx +11 -1
  196. package/src/client.tsx +9 -1
  197. package/src/decode-loader-results.ts +64 -31
  198. package/src/handles/deferred-resolution.ts +3 -2
  199. package/src/handles/meta.ts +5 -0
  200. package/src/href-client.ts +3 -1
  201. package/src/index.rsc.ts +1 -0
  202. package/src/index.ts +12 -4
  203. package/src/loader-redirect.tsx +2 -3
  204. package/src/outlet-context.ts +7 -6
  205. package/src/prefetch-markers.ts +15 -5
  206. package/src/prerender/build-shell-capture.ts +1 -2
  207. package/src/prerender/writable-store.ts +2 -3
  208. package/src/reverse.ts +3 -3
  209. package/src/route-content-wrapper.tsx +19 -17
  210. package/src/route-definition/dsl-helpers.ts +41 -21
  211. package/src/route-definition/helpers-types.ts +7 -2
  212. package/src/route-definition/resolve-handler-use.ts +23 -10
  213. package/src/route-definition/rewrite.ts +86 -19
  214. package/src/route-types.ts +1 -2
  215. package/src/router/find-match.ts +37 -1
  216. package/src/router/handler-context.ts +85 -40
  217. package/src/router/intercept-resolution.ts +161 -307
  218. package/src/router/lazy-includes.ts +43 -27
  219. package/src/router/loader-resolution.ts +21 -1
  220. package/src/router/manifest.ts +15 -10
  221. package/src/router/match-api.ts +11 -1
  222. package/src/router/match-middleware/background-revalidation.ts +2 -4
  223. package/src/router/match-middleware/cache-lookup.ts +16 -20
  224. package/src/router/match-middleware/intercept-resolution.ts +41 -60
  225. package/src/router/match-result.ts +31 -2
  226. package/src/router/middleware.ts +6 -147
  227. package/src/router/navigation-snapshot.ts +38 -2
  228. package/src/router/prefetch-cache-ttl.ts +10 -18
  229. package/src/router/prerender-match.ts +2 -1
  230. package/src/router/revalidation.ts +24 -3
  231. package/src/router/router-context.ts +5 -18
  232. package/src/router/router-interfaces.ts +0 -13
  233. package/src/router/router-options.ts +4 -28
  234. package/src/router/segment-resolution/fresh.ts +6 -2
  235. package/src/router/segment-resolution/helpers.ts +7 -1
  236. package/src/router/segment-resolution/loader-cache.ts +4 -3
  237. package/src/router/segment-resolution/mask-nested.ts +5 -3
  238. package/src/router/segment-resolution/prefetch-deferral.ts +62 -12
  239. package/src/router/segment-resolution/revalidation.ts +75 -35
  240. package/src/router/segment-resolution.ts +0 -1
  241. package/src/router/segment-wrappers.ts +8 -13
  242. package/src/router/substitute-pattern-params.ts +3 -2
  243. package/src/router/tracing.ts +2 -2
  244. package/src/router-versions.ts +7 -7
  245. package/src/router.ts +5 -17
  246. package/src/rsc/full-payload.ts +26 -4
  247. package/src/rsc/handler.ts +86 -48
  248. package/src/rsc/helpers.ts +13 -0
  249. package/src/rsc/manifest-init.ts +56 -3
  250. package/src/rsc/prefetch-render-error.ts +38 -0
  251. package/src/rsc/progressive-enhancement.ts +161 -211
  252. package/src/rsc/rewrite-passes.ts +56 -9
  253. package/src/rsc/rsc-rendering.ts +79 -23
  254. package/src/rsc/server-action.ts +25 -2
  255. package/src/rsc/shell-capture-constants.ts +26 -3
  256. package/src/rsc/shell-capture.ts +137 -51
  257. package/src/rsc/types.ts +5 -9
  258. package/src/segment-system.tsx +125 -119
  259. package/src/server/build-version-table.ts +12 -24
  260. package/src/server/context.ts +160 -7
  261. package/src/server/handle-store.ts +80 -12
  262. package/src/server/request-context.ts +46 -6
  263. package/src/server/request-headers.ts +32 -0
  264. package/src/server/rewrite-trail.ts +55 -9
  265. package/src/ssr/ssr-root.tsx +6 -10
  266. package/src/testing/build-versions.ts +0 -3
  267. package/src/testing/dispatch.ts +5 -8
  268. package/src/testing/e2e/index.ts +1 -0
  269. package/src/testing/flight.entry.ts +1 -0
  270. package/src/testing/index.ts +1 -0
  271. package/src/testing/internal/client-urls-projection.ts +31 -11
  272. package/src/testing/internal/seed-vars.ts +4 -4
  273. package/src/testing/render-route.tsx +83 -40
  274. package/src/testing/run-loader.ts +26 -2
  275. package/src/testing/run-middleware.ts +10 -0
  276. package/src/testing/run-revalidate.ts +13 -6
  277. package/src/testing/serve-shell-request.ts +79 -9
  278. package/src/testing/shell-status.ts +40 -0
  279. package/src/testing/vitest-stubs/version.ts +1 -0
  280. package/src/testing/vitest.ts +74 -7
  281. package/src/thenable-status.ts +0 -11
  282. package/src/types/handler-context.ts +12 -1
  283. package/src/types/loader-types.ts +10 -4
  284. package/src/types/route-entry.ts +2 -1
  285. package/src/urls/include-helper.ts +38 -11
  286. package/src/urls/path-helper-types.ts +4 -2
  287. package/src/vite/discovery/client-urls-projection.ts +205 -16
  288. package/src/vite/discovery/discover-routers.ts +2 -2
  289. package/src/vite/discovery/prerender-collection.ts +2 -6
  290. package/src/vite/discovery/shell-prerender-phase.ts +1 -5
  291. package/src/vite/discovery/state.ts +26 -0
  292. package/src/vite/plugins/client-urls-revalidate-hoist.ts +190 -77
  293. package/src/vite/plugins/expose-internal-ids.ts +46 -40
  294. package/src/vite/plugins/hoist/source.ts +8 -7
  295. package/src/vite/plugins/transition-when-hoist.ts +1 -0
  296. package/src/vite/plugins/version-plugin.ts +7 -0
  297. package/src/vite/plugins/version.d.ts +7 -0
  298. package/src/vite/plugins/virtual-entries.ts +20 -0
  299. package/src/vite/rango.ts +4 -1
  300. package/src/vite/router-discovery.ts +39 -7
  301. package/src/vite/utils/prerender-utils.ts +17 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A prefetch whose render reported an error is not kept (#1170).
3
+ *
4
+ * WHY: its 200 left with the headers before a streamed part failed, so the
5
+ * client stored the error boundary as a healthy prefetch, served it to a
6
+ * click and respawned it. The status cannot change any more, and the body
7
+ * cannot end with an error: workerd delivers an errored body as a clean end,
8
+ * and in Chromium the error drops the rows a click that adopted the prefetch
9
+ * has not decoded yet (a Flight "network error" in place of the page).
10
+ *
11
+ * So the body ends cleanly with one more row, PREFETCH_FAILED_ROW, which the
12
+ * Flight decoder skips and teeWithCompletion (browser/response-adapter.ts)
13
+ * reads as a stream that did not end cleanly: the client evicts the prefetch
14
+ * and never respawns it. Prefetch responses carry no Cache-Control, so the
15
+ * browser HTTP cache keeps none of it either.
16
+ *
17
+ * The errors are the render's `_renderErrors`: a Flight error row, a streamed
18
+ * handler recovered into its boundary, a loader that threw (redirect() and
19
+ * notFound() are not errors). Each is recorded before Flight writes the row
20
+ * that carries it, so the list is complete once Flight closes the stream.
21
+ */
22
+ export declare function markPrefetchOnRenderError(response: Response, renderErrors: readonly unknown[]): Response;
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { getRequestContext } from "../server/request-context.js";
9
9
  import type { MiddlewareFn } from "../router/middleware.js";
10
+ import type { ReactFormState } from "./types.js";
11
+ import type { MatchResult } from "../types.js";
10
12
  import type { HandlerContext } from "./handler-context.js";
11
13
  export interface PeRouteMiddlewareInfo {
12
14
  routeMiddleware?: Array<{
@@ -17,3 +19,21 @@ export interface PeRouteMiddlewareInfo {
17
19
  routeReverse?: (name: string, params?: Record<string, string>, search?: Record<string, unknown>) => string;
18
20
  }
19
21
  export declare function handleProgressiveEnhancement<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, isAction: boolean, handleStore: ReturnType<typeof getRequestContext>["_handleStore"], nonce: string | undefined, routeMwInfo?: PeRouteMiddlewareInfo): Promise<Response | null>;
22
+ /** What a no-JS form post's action left for the re-render (`_actionRan`). */
23
+ export interface FormActionOutcome {
24
+ reactFormState: ReactFormState | null;
25
+ directActionId: string | null;
26
+ /** The action threw, or the form body did not parse. */
27
+ failure?: PeFailure;
28
+ }
29
+ /**
30
+ * A failed no-JS form post and the error boundary matched for it. The boundary
31
+ * renders in place of the page, inside route middleware as the JS path renders
32
+ * its own (server-action.ts `errorBoundary`). With none, the page re-renders
33
+ * with 500, the JS path's status for the same boundaryless error.
34
+ */
35
+ export interface PeFailure {
36
+ error: unknown;
37
+ actionId: string | null | undefined;
38
+ boundary: MatchResult | null;
39
+ }
@@ -32,8 +32,18 @@ export interface RewritePass {
32
32
  /**
33
33
  * Move the request context to `rewrite`'s target for the next pass: check
34
34
  * that this request can be rewritten, resolve the target, count the hop,
35
- * then rebase the context. Throws the site error for a mutation or a loader
36
- * fetch, a resolution error, and RewriteLoopError.
35
+ * then rebase the context. Throws the site error for a loader fetch, a
36
+ * refused mutation or one whose body middleware read before its action ran,
37
+ * a resolution error, and RewriteLoopError.
38
+ *
39
+ * A mutation moves too (#1145). Before its action ran (a rewrite from global
40
+ * middleware) it moves with its body, and the target's pass runs the action
41
+ * after the target's global middleware, as a direct post there would. After
42
+ * it ran (route middleware wraps only the re-render), the target's pass
43
+ * re-renders from `reqCtx._actionRan`. `disallowMutations()` refuses the
44
+ * first, so a lock never runs a mutation; the second is already committed,
45
+ * and refusing it reports an error for a write that happened, so the caller
46
+ * retries it.
37
47
  */
38
48
  export declare function applyRewrite(rewrite: Rewrite, passRequest: Request, reqCtx: RequestContext<any>, routeMap: Record<string, string>, basename: string | undefined): RewritePass;
39
49
  /** The response to a rewrite loop. */
@@ -53,6 +53,12 @@ export interface ActionContinuation {
53
53
  * or an ActionContinuation for the revalidation phase.
54
54
  */
55
55
  export declare function executeServerAction<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, actionId: string, handleStore: ReturnType<typeof getRequestContext>["_handleStore"]): Promise<Response | ActionContinuation>;
56
+ /**
57
+ * The continuation for a rewrite pass after the action ran (#1145): a failed
58
+ * action's error boundary is re-matched on the target, since the one pass 1
59
+ * matched (or missed) is the rewriting route's.
60
+ */
61
+ export declare function continuationForRewritePass<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, continuation: ActionContinuation): Promise<ActionContinuation>;
56
62
  /**
57
63
  * Phase 2: Revalidate after action.
58
64
  *
@@ -41,7 +41,7 @@ export declare const PPR_REPLAY_STATUS_HEADER: string;
41
41
  * producer (rsc-rendering.ts) and the parser (testing/shell-status.ts): a
42
42
  * reason the parser does not list parses as null.
43
43
  */
44
- export declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit"];
44
+ export declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit", "rewritten"];
45
45
  /** One of {@link PPR_REPLAY_BYPASS_REASONS}. */
46
46
  export type PprReplayBypassReason = (typeof PPR_REPLAY_BYPASS_REASONS)[number];
47
47
  /**
@@ -84,6 +84,15 @@ export declare function buildShellKey(routerId: string, url: URL, filter?: Searc
84
84
  * replayed to gold's navigations. Encoded, it holds no `:` or `|`.
85
85
  */
86
86
  export declare function partitionShellKey(key: string, partition: string): string;
87
+ /**
88
+ * The shell key of a `rewrite(...).shell("visitor")` request: the visitor's
89
+ * URL, partitioned by `rw:` + the target's path and search (both searches
90
+ * filtered and sorted, shellSearchSeed). The visitor's URL keeps two public
91
+ * URLs of one target apart; the target keeps a conditional rewrite (an A/B
92
+ * arm, a lock) apart from the URL's own shell. The route's own partition
93
+ * composes after it.
94
+ */
95
+ export declare function visitorShellKey(routerId: string, visitor: URL, target: URL, filter?: SearchParamsFilter): string;
87
96
  /**
88
97
  * The navigation-only entry beside a document shell key (a cold partial
89
98
  * request's capture, rsc-rendering.ts). A suffix after the (encoded)
@@ -139,9 +148,10 @@ export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
139
148
  * (ShellCaptureDebugEvent.refusal, `caches.refusal` on a `router.prerender()`
140
149
  * result): `identity` (a request-scoped read: cookies(), headers(), the
141
150
  * theme, a `{ cache: false }` variable), `dynamic` (`ctx.dynamic()`),
142
- * `loader` (a `{ ssr: false }` loader rejected, or settled with
143
- * redirect()/notFound()), `no-record` (no doc record: the route's cache()
144
- * refused the write, or the handler output failed), `handles` (a pushed
151
+ * `loader` (a `{ ssr: false }` loader rejected, settled with
152
+ * redirect()/notFound(), or a promise it pushed rejected),
153
+ * `no-record` (no doc record: the route's cache() refused the write, or the
154
+ * handler output failed), `handles` (a pushed
145
155
  * handle value did not finish encoding), `size` (over the store's value
146
156
  * limit), `record-expired` (the route cache() record the capture wrote ran
147
157
  * out first), `invalidated` (a tag of the shell was invalidated after the
@@ -330,6 +330,13 @@ export interface ShellCaptureDescriptor {
330
330
  debugSink?: (event: ShellCaptureDebugEvent) => void;
331
331
  /** Store the snapshot for navigation replay, never the captured HTML prelude. */
332
332
  navigationOnly?: true;
333
+ /**
334
+ * Set for a shell keyed by the visitor's URL (`rewrite(...).shell("visitor")`,
335
+ * visitorShellKey): the capture renders the visitor's location
336
+ * (`RequestContext._shellCaptureForVisitor`) and stores it as
337
+ * ShellCacheEntry.pathname.
338
+ */
339
+ pathname?: string;
333
340
  /**
334
341
  * lastStoredCaptureSeq(key) when a document request read the store and
335
342
  * missed. The request schedules its capture only after rendering the MISS,
@@ -495,8 +502,9 @@ export type CaptureRecordOutcome = {
495
502
  * component showed one value in the prelude and another on every HIT.
496
503
  *
497
504
  * Order, all bounded by the one capture deadline (`ppr.captureTimeout`):
498
- * top-level handle promises, the handler pushes' nested promises, and the
499
- * bake-lane loader containers settle first (the record encodes the handles
505
+ * top-level handle promises (a bake-lane loader's pushed promises among
506
+ * them, #1182), the handler pushes' nested promises, and the bake-lane
507
+ * loader containers settle first (the record encodes the handles
500
508
  * a HIT restores, and its handle encode has its own 5s timeout that must
501
509
  * never be the one that fires); then the capture's onResponse callbacks fire
502
510
  * with a synthetic 200 (the implicit doc scope's cacheRoute, an explicit
@@ -522,6 +530,19 @@ export interface CaptureContextDerivation {
522
530
  * record encodes its handles, so that encode never races a pending value.
523
531
  */
524
532
  handlerPushesSettled: () => Promise<void>;
533
+ /**
534
+ * Every promise a bake-lane loader body pushed (#1182), in push order.
535
+ * The record-first step waits for them (they are in the recorded cut) and
536
+ * names the loader and the handle of one that rejects or misses the
537
+ * deadline.
538
+ */
539
+ loaderPromisePushes: readonly LoaderPromisePush[];
540
+ }
541
+ /** A promise a bake-lane loader pushed at capture, owned by that loader. */
542
+ export interface LoaderPromisePush {
543
+ loaderId: string;
544
+ handleName: string;
545
+ state: "pending" | "fulfilled" | "rejected";
525
546
  }
526
547
  /**
527
548
  * Derive the capture request context from a base context. Producer A passes
@@ -16,6 +16,11 @@ import type { ResolvedThemeConfig, Theme } from "../theme/types.js";
16
16
  export interface RscPayload {
17
17
  metadata?: {
18
18
  pathname: string;
19
+ /**
20
+ * Path and search of the URL the route rendered for, when middleware
21
+ * rewrote the request there (full-payload.ts payloadLocation).
22
+ */
23
+ rewriteTarget?: string;
19
24
  segments: ResolvedSegment[];
20
25
  /** Router instance ID. When this changes between navigations, the client
21
26
  * discards cached segments and does a full tree replacement (app switch). */
@@ -328,14 +333,6 @@ export interface CreateRSCHandlerOptions<TEnv = unknown, TRoutes extends Record<
328
333
  * ```
329
334
  */
330
335
  cache?: HandlerCacheConfig | ((env: TEnv) => HandlerCacheConfig);
331
- /**
332
- * Version override for this handler. Same meaning as
333
- * `createRouter({ version })`, which it takes precedence over: this exact
334
- * value is used for both of the router's versions.
335
- *
336
- * @default createRouter({ version }), else the router's build versions
337
- */
338
- version?: string;
339
336
  /**
340
337
  * Nonce provider for Content Security Policy (CSP).
341
338
  *
@@ -1,6 +1,21 @@
1
1
  import { type ReactNode, type ComponentType } from "react";
2
2
  import type { ResolvedSegment, RootLayoutProps } from "./types.js";
3
3
  export declare function restoreParallelLoaderMarkers(segments: ResolvedSegment[]): ResolvedSegment[];
4
+ /**
5
+ * An intercept's loaders arrive as loader segments of its slot
6
+ * (`${slot.id}D${i}.${$$id}`, router/intercept-resolution.ts). Folded back
7
+ * onto the slot before the tree walk, as one aggregate the slot's
8
+ * LoaderBoundary reads (client.tsx renderSlotContent): walked as loaders they
9
+ * would attach to the slot's parent, whose subtree (the page under the modal)
10
+ * would change shape and remount. Any other loader segment passes through; a
11
+ * list with nothing to fold is returned as it is, synchronously.
12
+ * The slot is a new object (rule 6, suspense-contract.md); its aggregate is
13
+ * memoized on the loaders' data (rule 1). Settled before the commit when
14
+ * nothing in it is deferred and the slot has no loading() or the lane settles
15
+ * loaders (forceAwait, action): a modal with no loading() commits whole, as
16
+ * when the server awaited its loaders.
17
+ */
18
+ export declare function foldInterceptLoaders(segments: ResolvedSegment[], settleLoaders: boolean): ResolvedSegment[] | Promise<ResolvedSegment[]>;
4
19
  /**
5
20
  * Options for renderSegments
6
21
  */
@@ -2,21 +2,18 @@ import { type RouterVersions, type RouterVersionsTable } from "../router-version
2
2
  /**
3
3
  * The versions a router serves with, in order:
4
4
  *
5
- * 1. `override`, a consumer-set `version` (createRouter or createRSCHandler):
6
- * that exact value for both.
7
- * 2. The router's entry in the build table, else the whole-build entry.
8
- * 3. `VERSION` for both: the dev stamp, bumped on every RSC module edit.
5
+ * 1. The router's entry in the build table, else the whole-build entry.
6
+ * 2. `VERSION` for both: the dev stamp, bumped on every RSC module edit.
9
7
  */
10
- export declare function resolveRouterVersions(routerId: string | undefined, override?: string): RouterVersions;
8
+ export declare function resolveRouterVersions(routerId: string | undefined): RouterVersions;
11
9
  /**
12
10
  * The version an on-demand prerender overlay key carries: the router's data
13
11
  * version, because the overlay stores segment data, as the segment cache does
14
12
  * (a client-only deploy keeps both). The write side (`router.prerender`,
15
- * router.ts) and the read side (rsc/handler.ts) both call this with
16
- * `createRouter({ version })`, the only override the trigger can see, so they
17
- * cannot disagree; a `createRSCHandler({ version })` does not move it.
13
+ * router.ts) and the read side (rsc/handler.ts) both call this, so they
14
+ * cannot disagree.
18
15
  */
19
- export declare function resolvePrerenderVersion(routerId: string | undefined, routerVersion: string | undefined): string;
16
+ export declare function resolvePrerenderVersion(routerId: string | undefined): string;
20
17
  /**
21
18
  * The versions of the router serving the current request, for a cache store
22
19
  * building a key. A store operation with no request context (a detached task
@@ -40,11 +37,11 @@ export declare function getCacheVersions(): RouterVersions;
40
37
  export type KeyVersion = keyof RouterVersions | null;
41
38
  /**
42
39
  * The `v/{version}/` prefix of a persistent store key, or "" for an
43
- * unversioned one. A store-level `version` is used for every versioned kind;
44
- * otherwise the version is the serving router's, read per operation because
45
- * the cache factory builds the store before the request context exists.
40
+ * unversioned one. The version is the serving router's, read per operation
41
+ * because the cache factory builds the store before the request context
42
+ * exists.
46
43
  */
47
- export declare function versionKeyPrefix(storeVersion: string | undefined, kind: KeyVersion): string;
44
+ export declare function versionKeyPrefix(kind: KeyVersion): string;
48
45
  /**
49
46
  * @internal Install a table, or restore the build's with `undefined`. A
50
47
  * request handler resolves its router's versions once, when it is created, so
@@ -61,6 +61,12 @@ export type EntryPropCommon = {
61
61
  cache?: EntryCacheConfig;
62
62
  /** URL prefix from include() scope, used for MountContext on client */
63
63
  mountPath?: string;
64
+ /**
65
+ * Include scope the entry's handler and loaders resolve `ctx.reverse(".name")`
66
+ * in. Structural entries only (layout, cache, parallel, wrapping
67
+ * middleware); a route resolves from its own name. See ReverseScope.
68
+ */
69
+ reverseScope?: ReverseScope;
64
70
  /** clientUrls() group key (PathOptions.clientGroup); route entries only. */
65
71
  clientGroup?: string;
66
72
  };
@@ -91,6 +97,11 @@ export type EntryPropRender = {
91
97
  * on both DSL evaluations, whatever `ssr` did to `loading`.
92
98
  */
93
99
  loadingPrefetch?: false;
100
+ /**
101
+ * loading(fallback, { ssr: false }), on both DSL evaluations; a document
102
+ * then sets `loading` to false (applyDocumentModeLoading).
103
+ */
104
+ loadingSsr?: false;
94
105
  transition?: TransitionConfig;
95
106
  };
96
107
  /**
@@ -111,7 +122,8 @@ export type LoaderEntry = {
111
122
  * Resolved at DSL-evaluation time from ctx.isSSR — entries are cached
112
123
  * per-isSSR (router/manifest.ts cache key), so the flag is already
113
124
  * request-mode-correct when resolveLoaders (fresh.ts) reads it and never
114
- * appears on navigation-lane entries.
125
+ * appears on navigation-lane entries. Set by documentModeLoader, which
126
+ * getDocumentModeEntry also applies to a lazy include's captured ancestors.
115
127
  */
116
128
  awaitBeforeFlush?: true;
117
129
  /**
@@ -129,6 +141,13 @@ export type LoaderEntry = {
129
141
  * (router/segment-resolution/prefetch-deferral.ts).
130
142
  */
131
143
  prefetch?: false;
144
+ /**
145
+ * The declaring layout's / parallel's / cache()'s include scope, for the
146
+ * loader body's `ctx.reverse(".name")` (its DSL kickoff carries it,
147
+ * runInsideLoaderScope). Unset on a route's loaders: they resolve from the
148
+ * route's name.
149
+ */
150
+ reverseScope?: ReverseScope;
132
151
  };
133
152
  /**
134
153
  * Segments state for intercept context
@@ -192,7 +211,6 @@ export type InterceptEntry = {
192
211
  slotName: `@${string}`;
193
212
  routeName: string;
194
213
  handler: ReactNode | Handler<any, any, any>;
195
- middleware: MiddlewareFn<any, any>[];
196
214
  loader: LoaderEntry[];
197
215
  loading?: ReactNode | false;
198
216
  transition?: TransitionConfig;
@@ -267,10 +285,21 @@ export type EntryData = ({
267
285
  /** Cache entries create cache boundaries and render like layouts (with Outlet) */
268
286
  handler: ReactNode | Handler<any, any, any>;
269
287
  } & EntryPropCommon & EntryPropDatas & EntryPropSegments & EntryPropRender);
288
+ /**
289
+ * Where an include()'s handler runs in the route tree. Hidden include-scope
290
+ * names (`$prefix_*`) derive from it, never from counter state, so build
291
+ * discovery and runtime expansion name every include the same (#1104).
292
+ */
293
+ export interface IncludeScopePosition {
294
+ /** Sibling indexes of the enclosing includes, "_"-joined ("" at a mount root). */
295
+ scopePath?: string;
296
+ /** The scopePath tail since the nearest include that added a name segment. */
297
+ hiddenScopePath?: string;
298
+ }
270
299
  /**
271
300
  * Tracked include info for build-time manifest generation
272
301
  */
273
- export interface TrackedInclude {
302
+ export interface TrackedInclude extends IncludeScopePosition {
274
303
  prefix: string;
275
304
  fullPrefix: string;
276
305
  namePrefix?: string;
@@ -290,7 +319,7 @@ export type CachedHeaderScope = {
290
319
  /**
291
320
  * Context stored in AsyncLocalStorage
292
321
  */
293
- interface HelperContext {
322
+ interface HelperContext extends IncludeScopePosition {
294
323
  manifest: Map<string, EntryData>;
295
324
  namespace: string;
296
325
  parent: EntryData | null;
@@ -302,7 +331,8 @@ interface HelperContext {
302
331
  * different routers don't clobber each other (route-map-builder.ts). */
303
332
  routerId?: string;
304
333
  metrics?: MetricsStore;
305
- /** True when rendering for SSR (document requests) */
334
+ /** True when rendering for SSR (document requests). DSL decisions on it
335
+ * go through the document-mode helpers (documentModeLoader). */
306
336
  isSSR?: boolean;
307
337
  /** URL patterns map for path() routes (route name -> pattern) */
308
338
  patterns?: Map<string, string>;
@@ -399,6 +429,37 @@ export declare function getNamePrefix(): string | undefined;
399
429
  * Returns true at root or inside { name: "" } includes, false inside named includes.
400
430
  */
401
431
  export declare function getRootScoped(): boolean;
432
+ /**
433
+ * The include scope a segment's dot-local `ctx.reverse(".name")` resolves in.
434
+ *
435
+ * One handler ctx serves every segment of a request and is built from the
436
+ * matched route's name (match-api.ts), so a parent module's layout resolved
437
+ * `.settings` from the matched CHILD module's prefix first: on
438
+ * `/acme/web/issues` the account layout's `.settings` hit the project
439
+ * module's route. Structural entries (layout, cache, parallel, wrapping
440
+ * middleware) and the loaders they declare capture the scope where the DSL
441
+ * defined them. Their handler gets a ctx whose `reverse` carries it
442
+ * (withReverseScope, router/handler-context.ts), and their loaders' DSL
443
+ * kickoff carries it in the loader scope (runInsideLoaderScope) for the
444
+ * loader ctx the executor builds. Global names and mount-param autofill do
445
+ * not change.
446
+ */
447
+ export interface ReverseScope {
448
+ /** Include name prefix ("account.project"); undefined outside named includes. */
449
+ readonly prefix: string | undefined;
450
+ /** getRootScoped() where the segment was defined: bare-name fallback allowed. */
451
+ readonly rootScoped: boolean;
452
+ }
453
+ /** The ReverseScope of the DSL position being evaluated. */
454
+ export declare function getReverseScope(): ReverseScope;
455
+ /**
456
+ * A createReverseFunction result (router/handler-context.ts). The internal
457
+ * 4th argument resolves dot names in a segment's ReverseScope instead of the
458
+ * route's name.
459
+ */
460
+ export type ScopableReverse = (name: string, hrefParams?: Record<string, string>, search?: Record<string, unknown>, segmentScope?: ReverseScope) => string;
461
+ /** `reverse` with dot names resolved in `scope`, if any. */
462
+ export declare function scopeReverse(reverse: ScopableReverse, scope: ReverseScope | undefined): ScopableReverse;
402
463
  /**
403
464
  * Stamp build-time scope identity onto a Static() definition at mount time.
404
465
  * The bake collector (prerender-collection.ts) renders defs OUTSIDE any
@@ -425,6 +486,23 @@ export type { HelperContext };
425
486
  * parent pointer, handler) stays shared, which is correct and cheap.
426
487
  */
427
488
  export declare function getIsolatedLazyParent(captured: EntryData | null | undefined): EntryData | null;
489
+ /** loader(Def, { ssr: false }): a document awaits it before the first flush. */
490
+ export declare function documentModeLoader(entry: LoaderEntry): LoaderEntry;
491
+ /** loading(fallback, { ssr: false }): a document renders no fallback. */
492
+ export declare function applyDocumentModeLoading(entry: EntryPropRender): void;
493
+ /**
494
+ * `entry`, its ancestors, orphan layouts and parallels as a document (isSSR)
495
+ * DSL evaluation builds them, from an evaluation without isSSR.
496
+ *
497
+ * include() captures its parent chain on router.ts routes() or
498
+ * lazy-includes.ts runExpansion, neither of which has isSSR, and loadManifest
499
+ * reuses it for every request. Handed to a document as is, every ancestor
500
+ * outside the include kept its navigation-mode decisions (#1179). Intercepts
501
+ * stay as they are: a document never resolves one.
502
+ *
503
+ * Memoized per entry, so an ancestor several includes share maps to one copy.
504
+ */
505
+ export declare function getDocumentModeEntry(entry: EntryData): EntryData;
428
506
  export declare function getParallelEntries(parallels: ParallelEntries | EntryData[] | undefined): ParallelEntryData[];
429
507
  export declare function getParallelSlotEntries(parallels: ParallelEntries | EntryData[] | undefined): Array<{
430
508
  slot: `@${string}`;
@@ -689,7 +767,13 @@ export declare function assertCachedHeaderWriteAllowed(surface: string, surfaceP
689
767
  * are bypassed because loaders are always fresh (never cached) and
690
768
  * their side effects (setCookie, header, etc.) are safe.
691
769
  */
692
- export declare function runInsideLoaderScope<T>(fn: () => T, loaderId?: string): T;
770
+ export declare function runInsideLoaderScope<T>(fn: () => T, loaderId?: string, reverseScope?: ReverseScope): T;
771
+ /**
772
+ * The ReverseScope of the DSL loader kickoff around this call: a loader the
773
+ * kickoff starts, and one its body starts with ctx.use(), resolve dot names
774
+ * in it. A handler's ctx.use(Loader) runs outside any kickoff: none.
775
+ */
776
+ export declare function getLoaderReverseScope(): ReverseScope | undefined;
693
777
  /**
694
778
  * The loader whose run a handle push here belongs to, for the browser's
695
779
  * merge of a partial response (handles/pushed-by.ts): the DSL loader
@@ -123,12 +123,14 @@ export interface HandleStore {
123
123
  */
124
124
  pushPlaceholder(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
125
125
  /**
126
- * push() a record's copy of `loaderId`'s settled push that stands
127
- * (restoreHandles): the record supplies the loader's value too. From then
128
- * on this request drops every settled, thenable-free push the loader makes
129
- * (live, or replayed from a cache entry, anywhere inside its body), and
130
- * keeps the ones holding a thenable (holdsThenable: what the record could
131
- * not keep), placed among the restored copies in the loader's push order.
126
+ * push() a record's copy of `loaderId`'s push that stands (restoreHandles):
127
+ * the record supplies the loader's value too. From then on this request
128
+ * drops every thenable-free push the loader makes (live, or replayed from
129
+ * a cache entry, anywhere inside its body), and keeps the ones holding a
130
+ * thenable (holdsThenable: what the record could not keep), placed among
131
+ * the restored copies in the loader's push order. A top-level promise is
132
+ * judged by its settled value, as the capture judged it (#1182): dropped
133
+ * when it settles thenable-free or rejects, else kept once it settles.
132
134
  */
133
135
  pushRestored(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
134
136
  /**
@@ -140,6 +142,15 @@ export interface HandleStore {
140
142
  * takes a push made inside a hole it awaited.
141
143
  */
142
144
  setRecordAuthority(authority: (loaderId: string) => RecordAuthority): void;
145
+ /**
146
+ * Capture only (shell-capture.ts deriveShellCaptureContext): the slot
147
+ * holding `value` becomes a DSL-loader push without an owner, so the
148
+ * record and the prelude leave it out (getDataForSegment's
149
+ * `excludeLoaderPushes`). The capture owns a bake-lane loader's promise
150
+ * when it is pushed, and calls this once the promise settled to a value
151
+ * that holds one (#1182).
152
+ */
153
+ unrecordPush(handleName: string, segmentId: string, value: unknown): void;
143
154
  /**
144
155
  * `loaderId`'s run in this request settled (resolved or rejected), its
145
156
  * pushes made (loader-resolution.ts createLoaderExecutor). Its placeholders
@@ -13,7 +13,7 @@ import { parseCookiesFromHeader } from "./cookie-parse.js";
13
13
  import type { CacheErrorCategory } from "../cache/cache-error.js";
14
14
  import type { CookieOptions } from "../router/middleware.js";
15
15
  import type { LoaderDefinition } from "../types.js";
16
- import type { ScopedReverseFunction } from "../reverse.js";
16
+ import type { AutofillAwareReverseFunction } from "../types/handler-context.js";
17
17
  import type { DefaultEnv, DefaultReverseRouteMap, DefaultRouteName } from "../types/global-namespace.js";
18
18
  import type { Handle } from "../handle.js";
19
19
  import { type ContextVar } from "../context-var.js";
@@ -28,6 +28,8 @@ import type { ResolvedTracing } from "../router/tracing.js";
28
28
  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
+ import type { ActionContinuation } from "../rsc/server-action.js";
32
+ import type { FormActionOutcome } from "../rsc/progressive-enhancement.js";
31
33
  import { type ExecutionStart } from "../cache/invalidation-order.js";
32
34
  export interface RenderForegroundCursor {
33
35
  mode: RenderMode;
@@ -243,6 +245,12 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
243
245
  * locally and passes it to scheduleShellCapture directly.
244
246
  */
245
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;
246
254
  /**
247
255
  * @internal Bake-lane loader containers collected DURING a shell capture:
248
256
  * segment-key -> the loader's (pre-wrap) result promise. Populated by
@@ -256,9 +264,10 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
256
264
  _shellCaptureLoaderRecords?: Map<string, Promise<unknown>>;
257
265
  /**
258
266
  * @internal Set on a capture's derived context when a loader pushed a
259
- * value the record cannot keep (a deferred push, masked nested promises,
260
- * or a push outside a loader body): the loader records then carry
261
- * `runs: 1`, so a HIT still runs their bodies for those pushes.
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.
262
271
  */
263
272
  _shellCaptureUnrecordedLoaderPush?: true;
264
273
  /**
@@ -635,12 +644,25 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
635
644
  * Generate URLs from route names.
636
645
  * Uses the global route map. After route matching, scoped (`.name`) resolution
637
646
  * works within the matched include() scope.
638
- */
639
- reverse: ScopedReverseFunction<Record<string, string>, DefaultReverseRouteMap>;
647
+ *
648
+ * Params are optional in the type because the fill depends on the phase.
649
+ * After the route match (route middleware, handlers, loaders, server actions)
650
+ * missing params come from the matched route's params; explicit params win.
651
+ * In global middleware before `next()` nothing is matched and the fill is
652
+ * empty, so a route with a required param throws `Missing param "<name>" for
653
+ * route "<route>"` at runtime (a param-less route still resolves).
654
+ */
655
+ reverse: AutofillAwareReverseFunction<Record<string, string>, DefaultReverseRouteMap>;
640
656
  /** @internal Route name from route matching, used for scoped reverse resolution */
641
657
  _routeName?: string;
642
658
  /** @internal Previous route key (from the navigation source), used for revalidation */
643
659
  _prevRouteKey?: string;
660
+ /**
661
+ * @internal Leaving a rewritten page, the visitor's URL moved
662
+ * (router/match-api.ts): the default revalidation counts it as a search
663
+ * change, since the render may read `ctx.rewrittenFrom`.
664
+ */
665
+ _visitorMoved?: boolean;
644
666
  /**
645
667
  * @internal True while the post-action revalidation render is running (set by
646
668
  * revalidateAfterAction). The "use cache" runtime reads this to prefer
@@ -650,6 +672,22 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
650
672
  * revalidating in the background. A plain navigation (flag unset) keeps SWR.
651
673
  */
652
674
  _inActionRevalidation?: boolean;
675
+ /**
676
+ * @internal The outcome of the action this request ran (a JS server
677
+ * action's continuation, a no-JS form post's form state), set before route
678
+ * middleware wraps the re-render. While it is unset, applyRewrite
679
+ * (rsc/rewrite-passes.ts) moves a mutation with its body, so the action
680
+ * runs on the target's pass, or refuses it (`disallowMutations()`, or a
681
+ * body middleware read); once set, the request moves to the target, whose
682
+ * pass re-renders from it instead of running the action again (#1145).
683
+ */
684
+ _actionRan?: {
685
+ kind: "action";
686
+ continuation: ActionContinuation;
687
+ } | {
688
+ kind: "form";
689
+ outcome: FormActionOutcome;
690
+ };
653
691
  /**
654
692
  * @internal Render barrier for experimental `rendered()` API.
655
693
  * Resolves when all non-loader segments have settled and handle data
@@ -823,7 +861,7 @@ export interface RouteRecordWindow {
823
861
  * This is the type exported to library consumers. Internal code should
824
862
  * use the full RequestContext interface directly.
825
863
  */
826
- 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" | "_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" | "_inActionRevalidation" | "_reportedErrors" | "_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">;
864
+ 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" | "_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">;
827
865
  /**
828
866
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
829
867
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -18,6 +18,18 @@
18
18
  * fill); the rest follow the rule so a new call site cannot drift into one.
19
19
  */
20
20
  export declare function requestHeaders(request: Request): Headers;
21
+ /**
22
+ * A copy of `request`'s headers for a bodyless mirror of it (the PE
23
+ * re-render, route middleware around it, a rewrite pass after an action),
24
+ * without the body-framing ones and `content-type`, so a body check gated on
25
+ * the content-type passes over a request that has no body.
26
+ */
27
+ export declare function bodylessHeaders(request: Request): Headers;
28
+ /**
29
+ * A bodyless mirror of `request` at `url`: `method`, its
30
+ * {@link bodylessHeaders}, the signal and workerd's `cf`.
31
+ */
32
+ export declare function bodylessRequest(url: string | URL, request: Request, method: string): Request;
21
33
  /**
22
34
  * Shadow `request.headers` with an own, non-enumerable getter that calls
23
35
  * `beforeRead` and returns the request's own Headers (stable per request, so