@rangojs/router 0.20.0 → 0.22.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 (331) hide show
  1. package/dist/bin/rango.js +39 -15
  2. package/dist/types/browser/event-controller.d.ts +49 -0
  3. package/dist/types/browser/history-state.d.ts +16 -4
  4. package/dist/types/browser/navigation-store.d.ts +9 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +7 -0
  6. package/dist/types/browser/partial-update.d.ts +2 -1
  7. package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
  8. package/dist/types/browser/rango-state.d.ts +3 -1
  9. package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
  10. package/dist/types/browser/react/context.d.ts +25 -0
  11. package/dist/types/browser/react/location-state-shared.d.ts +84 -10
  12. package/dist/types/browser/react/location-state.d.ts +7 -2
  13. package/dist/types/browser/rsc-router.d.ts +13 -2
  14. package/dist/types/browser/types.d.ts +10 -0
  15. package/dist/types/build/generate-manifest.d.ts +2 -0
  16. package/dist/types/cache/background-task.d.ts +22 -0
  17. package/dist/types/cache/cache-key-utils.d.ts +50 -5
  18. package/dist/types/cache/cache-policy.d.ts +17 -0
  19. package/dist/types/cache/cache-scope.d.ts +5 -6
  20. package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
  21. package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
  22. package/dist/types/cache/document-cache.d.ts +8 -5
  23. package/dist/types/cache/handle-snapshot.d.ts +59 -50
  24. package/dist/types/cache/index.d.ts +3 -1
  25. package/dist/types/cache/invalidation-order.d.ts +14 -0
  26. package/dist/types/cache/memory-segment-store.d.ts +33 -1
  27. package/dist/types/cache/shell-snapshot.d.ts +29 -4
  28. package/dist/types/cache/store-scope.d.ts +22 -0
  29. package/dist/types/cache/tag-invalidation.d.ts +7 -6
  30. package/dist/types/cache/types.d.ts +84 -24
  31. package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
  32. package/dist/types/client-urls/navigation.d.ts +7 -1
  33. package/dist/types/client-urls/optimistic-location.d.ts +10 -4
  34. package/dist/types/errors.d.ts +6 -0
  35. package/dist/types/handles/deferred-resolution.d.ts +18 -1
  36. package/dist/types/internal-suspense-audit.d.ts +1 -0
  37. package/dist/types/loader-store.d.ts +4 -8
  38. package/dist/types/outlet-provider.d.ts +2 -1
  39. package/dist/types/prerender/build-shell-capture.d.ts +8 -6
  40. package/dist/types/prerender/cloudflare.d.ts +49 -0
  41. package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
  42. package/dist/types/prerender/index.d.ts +12 -0
  43. package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
  44. package/dist/types/prerender/on-demand.d.ts +272 -0
  45. package/dist/types/prerender/producer-guard.d.ts +33 -0
  46. package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
  47. package/dist/types/prerender/warm-request.d.ts +65 -0
  48. package/dist/types/prerender/warm.d.ts +65 -0
  49. package/dist/types/prerender/writable-store.d.ts +170 -0
  50. package/dist/types/prerender.d.ts +27 -0
  51. package/dist/types/reverse.d.ts +1 -1
  52. package/dist/types/route-content-wrapper.d.ts +3 -1
  53. package/dist/types/router/error-handling.d.ts +2 -0
  54. package/dist/types/router/handler-context.d.ts +1 -1
  55. package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
  56. package/dist/types/router/navigation-snapshot.d.ts +8 -1
  57. package/dist/types/router/pattern-matching.d.ts +2 -0
  58. package/dist/types/router/prefetch-default.d.ts +4 -4
  59. package/dist/types/router/prerender-match.d.ts +23 -1
  60. package/dist/types/router/route-trie-builder.d.ts +8 -1
  61. package/dist/types/router/router-context.d.ts +1 -0
  62. package/dist/types/router/router-interfaces.d.ts +32 -1
  63. package/dist/types/router/router-options.d.ts +39 -5
  64. package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
  65. package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
  66. package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
  67. package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
  68. package/dist/types/router/trie-matching.d.ts +2 -0
  69. package/dist/types/router-versions.d.ts +39 -0
  70. package/dist/types/rsc/handler-context.d.ts +5 -0
  71. package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
  72. package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
  73. package/dist/types/rsc/shell-capture.d.ts +14 -1
  74. package/dist/types/rsc/shell-serve.d.ts +2 -2
  75. package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
  76. package/dist/types/rsc/types.d.ts +12 -6
  77. package/dist/types/segment-boundary-content.d.ts +17 -0
  78. package/dist/types/segment-loader-promise.d.ts +2 -6
  79. package/dist/types/server/build-version-table.d.ts +53 -0
  80. package/dist/types/server/context.d.ts +12 -4
  81. package/dist/types/server/handle-store.d.ts +89 -46
  82. package/dist/types/server/request-context.d.ts +84 -9
  83. package/dist/types/suspense-audit-react.d.ts +26 -0
  84. package/dist/types/suspense-audit.d.ts +157 -0
  85. package/dist/types/testing/action-form.d.ts +34 -0
  86. package/dist/types/testing/build-versions.d.ts +32 -0
  87. package/dist/types/testing/dom.entry.d.ts +1 -1
  88. package/dist/types/testing/flight.entry.d.ts +3 -1
  89. package/dist/types/testing/index.d.ts +6 -0
  90. package/dist/types/testing/internal/seed-vars.d.ts +7 -2
  91. package/dist/types/testing/internal/server-modules.d.ts +8 -0
  92. package/dist/types/testing/location-state-key.d.ts +5 -1
  93. package/dist/types/testing/render-route.d.ts +77 -6
  94. package/dist/types/testing/serve-shell-request.d.ts +55 -4
  95. package/dist/types/testing/shell-status.d.ts +14 -6
  96. package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
  97. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  98. package/dist/types/thenable-status.d.ts +6 -0
  99. package/dist/types/types/handler-context.d.ts +15 -5
  100. package/dist/types/types/route-entry.d.ts +5 -0
  101. package/dist/types/urls/path-helper.d.ts +18 -0
  102. package/dist/types/vite/discovery/build-versions.d.ts +393 -0
  103. package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
  104. package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
  105. package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
  106. package/dist/types/vite/discovery/state.d.ts +25 -0
  107. package/dist/types/vite/encryption-key.d.ts +18 -0
  108. package/dist/types/vite/inject-client-debug.d.ts +6 -25
  109. package/dist/types/vite/plugin-types.d.ts +27 -0
  110. package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
  111. package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
  112. package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
  113. package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
  114. package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
  115. package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
  116. package/dist/types/vite/router-discovery.d.ts +6 -0
  117. package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
  118. package/dist/types/vite/utils/client-chunks.d.ts +2 -0
  119. package/dist/types/vite/utils/compare-strings.d.ts +7 -0
  120. package/dist/types/vite/utils/package-resolution.d.ts +8 -0
  121. package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
  122. package/dist/vite/index.js +1707 -931
  123. package/package.json +12 -3
  124. package/skills/cache-guide/SKILL.md +102 -37
  125. package/skills/caching/SKILL.md +56 -9
  126. package/skills/catalog.json +1 -1
  127. package/skills/client-urls/SKILL.md +16 -0
  128. package/skills/cloudflare/SKILL.md +133 -1
  129. package/skills/comparison/references/framework-comparison.md +17 -13
  130. package/skills/deployment-caching/SKILL.md +33 -12
  131. package/skills/document-cache/SKILL.md +16 -14
  132. package/skills/hooks/SKILL.md +25 -0
  133. package/skills/hooks/handle-and-actions.md +5 -0
  134. package/skills/hooks/navigation.md +38 -0
  135. package/skills/hooks/state.md +213 -11
  136. package/skills/hooks/urls.md +40 -1
  137. package/skills/host-router/SKILL.md +31 -0
  138. package/skills/intercept/SKILL.md +6 -0
  139. package/skills/loader/SKILL.md +25 -5
  140. package/skills/middleware/SKILL.md +2 -0
  141. package/skills/migrate-nextjs/SKILL.md +82 -9
  142. package/skills/ppr/SKILL.md +150 -48
  143. package/skills/prerender/SKILL.md +651 -10
  144. package/skills/rango/SKILL.md +9 -7
  145. package/skills/response-routes/SKILL.md +5 -5
  146. package/skills/route/SKILL.md +29 -0
  147. package/skills/router-setup/SKILL.md +15 -1
  148. package/skills/testing/SKILL.md +32 -27
  149. package/skills/testing/cache-prerender.md +18 -17
  150. package/skills/testing/client-components.md +193 -8
  151. package/skills/testing/handles.md +2 -0
  152. package/skills/testing/loader.md +1 -1
  153. package/skills/testing/middleware.md +1 -1
  154. package/skills/testing/render-handler.md +18 -18
  155. package/skills/testing/serve-shell-request.md +167 -22
  156. package/skills/testing/server-actions.md +17 -17
  157. package/skills/testing/server-tree.md +1 -1
  158. package/skills/typesafety/generated-files-and-cli.md +1 -1
  159. package/skills/use-cache/SKILL.md +25 -10
  160. package/skills/vercel/SKILL.md +5 -3
  161. package/skills/view-transitions/SKILL.md +9 -4
  162. package/src/bin/rango.ts +1 -1
  163. package/src/browser/event-controller.ts +119 -2
  164. package/src/browser/history-state.ts +39 -17
  165. package/src/browser/link-interceptor.ts +2 -2
  166. package/src/browser/navigation-bridge.ts +104 -41
  167. package/src/browser/navigation-store.ts +26 -0
  168. package/src/browser/navigation-transaction.ts +24 -12
  169. package/src/browser/network-error-handler.ts +2 -0
  170. package/src/browser/partial-update.ts +58 -14
  171. package/src/browser/prefetch/default-strategy.ts +22 -42
  172. package/src/browser/rango-state.ts +3 -1
  173. package/src/browser/react/Link.tsx +37 -43
  174. package/src/browser/react/NavigationProvider.tsx +85 -1
  175. package/src/browser/react/context.ts +30 -0
  176. package/src/browser/react/location-state-shared.ts +200 -34
  177. package/src/browser/react/location-state.ts +28 -77
  178. package/src/browser/react/use-action.ts +4 -1
  179. package/src/browser/react/use-handle.ts +3 -0
  180. package/src/browser/react/use-link-status.ts +4 -3
  181. package/src/browser/react/use-navigation.ts +4 -1
  182. package/src/browser/react/use-params.ts +4 -1
  183. package/src/browser/react/use-pathname.ts +4 -1
  184. package/src/browser/react/use-search-params.ts +5 -3
  185. package/src/browser/react/use-segments.ts +36 -54
  186. package/src/browser/rsc-router.tsx +93 -31
  187. package/src/browser/segment-reconciler.ts +3 -3
  188. package/src/browser/server-action-bridge.ts +43 -7
  189. package/src/browser/types.ts +11 -0
  190. package/src/build/generate-manifest.ts +17 -0
  191. package/src/build/merge-full-manifests.ts +5 -0
  192. package/src/build/route-trie.ts +1 -0
  193. package/src/cache/background-task.ts +61 -0
  194. package/src/cache/cache-key-utils.ts +91 -12
  195. package/src/cache/cache-policy.ts +11 -2
  196. package/src/cache/cache-runtime.ts +23 -23
  197. package/src/cache/cache-scope.ts +48 -36
  198. package/src/cache/cf/cf-cache-store.ts +91 -66
  199. package/src/cache/cf/cf-cache-types.ts +12 -4
  200. package/src/cache/document-cache.ts +35 -14
  201. package/src/cache/handle-snapshot.ts +118 -86
  202. package/src/cache/index.ts +5 -0
  203. package/src/cache/invalidation-order.ts +53 -0
  204. package/src/cache/memory-segment-store.ts +52 -1
  205. package/src/cache/shell-snapshot.ts +52 -5
  206. package/src/cache/store-scope.ts +36 -0
  207. package/src/cache/tag-invalidation.ts +7 -5
  208. package/src/cache/types.ts +90 -24
  209. package/src/cache/vercel/vercel-cache-store.ts +68 -26
  210. package/src/client-urls/client-root.tsx +1 -0
  211. package/src/client-urls/navigation.ts +10 -0
  212. package/src/client-urls/optimistic-location.ts +10 -4
  213. package/src/client.tsx +40 -3
  214. package/src/errors.ts +13 -6
  215. package/src/handles/deferred-resolution.ts +36 -0
  216. package/src/internal-suspense-audit.ts +12 -0
  217. package/src/loader-store.ts +4 -9
  218. package/src/outlet-provider.tsx +25 -1
  219. package/src/prerender/build-shell-capture.ts +11 -9
  220. package/src/prerender/cloudflare.ts +130 -0
  221. package/src/prerender/create-prerender-trigger.ts +780 -0
  222. package/src/prerender/index.ts +39 -0
  223. package/src/prerender/memory-prerender-store.ts +115 -0
  224. package/src/prerender/on-demand.ts +339 -0
  225. package/src/prerender/producer-guard.ts +66 -0
  226. package/src/prerender/shell-manifest-key.ts +12 -17
  227. package/src/prerender/warm-request.ts +154 -0
  228. package/src/prerender/warm.ts +193 -0
  229. package/src/prerender/writable-store.ts +278 -0
  230. package/src/prerender.ts +29 -0
  231. package/src/reverse.ts +1 -1
  232. package/src/route-content-wrapper.tsx +107 -13
  233. package/src/router/error-handling.ts +12 -12
  234. package/src/router/find-match.ts +1 -0
  235. package/src/router/handler-context.ts +2 -0
  236. package/src/router/intercept-resolution.ts +15 -8
  237. package/src/router/loader-resolution.ts +2 -10
  238. package/src/router/manifest.ts +2 -0
  239. package/src/router/match-middleware/background-revalidation.ts +2 -0
  240. package/src/router/match-middleware/cache-lookup.ts +239 -54
  241. package/src/router/navigation-snapshot.ts +25 -6
  242. package/src/router/pattern-matching.ts +14 -0
  243. package/src/router/prefetch-default.ts +4 -4
  244. package/src/router/prerender-match.ts +460 -352
  245. package/src/router/request-classification.ts +15 -12
  246. package/src/router/route-trie-builder.ts +9 -0
  247. package/src/router/router-context.ts +1 -0
  248. package/src/router/router-interfaces.ts +35 -1
  249. package/src/router/router-options.ts +45 -5
  250. package/src/router/segment-resolution/fresh.ts +20 -19
  251. package/src/router/segment-resolution/loader-cache.ts +110 -77
  252. package/src/router/segment-resolution/revalidation.ts +34 -24
  253. package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
  254. package/src/router/trie-matching.ts +3 -0
  255. package/src/router-versions.ts +60 -0
  256. package/src/router.ts +107 -1
  257. package/src/rsc/full-payload.ts +6 -2
  258. package/src/rsc/handler-context.ts +5 -0
  259. package/src/rsc/handler.ts +64 -7
  260. package/src/rsc/progressive-enhancement.ts +5 -1
  261. package/src/rsc/response-cache-serve.ts +10 -4
  262. package/src/rsc/rsc-rendering.ts +65 -12
  263. package/src/rsc/shell-build-manifest.ts +17 -12
  264. package/src/rsc/shell-capture-constants.ts +39 -7
  265. package/src/rsc/shell-capture.ts +144 -45
  266. package/src/rsc/shell-serve.ts +12 -6
  267. package/src/rsc/ssr-module-loader.ts +26 -0
  268. package/src/rsc/types.ts +12 -6
  269. package/src/segment-boundary-content.ts +25 -0
  270. package/src/segment-loader-promise.ts +28 -38
  271. package/src/segment-system.tsx +117 -57
  272. package/src/server/build-version-table.ts +130 -0
  273. package/src/server/context.ts +40 -17
  274. package/src/server/cookie-store.ts +5 -0
  275. package/src/server/handle-store.ts +357 -127
  276. package/src/server/request-context.ts +149 -12
  277. package/src/ssr/ssr-root.tsx +32 -13
  278. package/src/suspense-audit-react.tsx +98 -0
  279. package/src/suspense-audit.ts +1030 -0
  280. package/src/testing/action-form.ts +66 -0
  281. package/src/testing/build-versions.ts +64 -0
  282. package/src/testing/dispatch.ts +6 -0
  283. package/src/testing/dom.entry.ts +1 -0
  284. package/src/testing/flight-runtime.d.ts +27 -0
  285. package/src/testing/flight.entry.ts +4 -0
  286. package/src/testing/index.ts +22 -0
  287. package/src/testing/internal/context.ts +2 -1
  288. package/src/testing/internal/seed-vars.ts +14 -2
  289. package/src/testing/internal/server-modules.ts +32 -0
  290. package/src/testing/location-state-key.ts +18 -8
  291. package/src/testing/render-handler.ts +2 -1
  292. package/src/testing/render-route.tsx +293 -46
  293. package/src/testing/serve-shell-request.ts +262 -37
  294. package/src/testing/shell-status.ts +17 -6
  295. package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
  296. package/src/testing/vitest-stubs/version.ts +4 -1
  297. package/src/thenable-status.ts +10 -0
  298. package/src/types/handler-context.ts +15 -5
  299. package/src/types/route-entry.ts +6 -0
  300. package/src/urls/path-helper.ts +69 -9
  301. package/src/use-loader.tsx +57 -30
  302. package/src/vite/discovery/build-versions.ts +1281 -0
  303. package/src/vite/discovery/bundle-postprocess.ts +4 -0
  304. package/src/vite/discovery/discover-routers.ts +15 -0
  305. package/src/vite/discovery/installed-packages.ts +159 -0
  306. package/src/vite/discovery/prerender-collection.ts +38 -1
  307. package/src/vite/discovery/router-versions-phase.ts +336 -0
  308. package/src/vite/discovery/shell-prerender-phase.ts +33 -43
  309. package/src/vite/discovery/state.ts +36 -1
  310. package/src/vite/discovery/virtual-module-codegen.ts +7 -2
  311. package/src/vite/encryption-key.ts +101 -9
  312. package/src/vite/inject-client-debug.ts +42 -20
  313. package/src/vite/plugin-types.ts +28 -0
  314. package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
  315. package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
  316. package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
  317. package/src/vite/plugins/expose-internal-ids.ts +12 -3
  318. package/src/vite/plugins/stable-rsc-output.ts +147 -0
  319. package/src/vite/plugins/version-plugin.ts +19 -24
  320. package/src/vite/plugins/version.d.ts +17 -2
  321. package/src/vite/plugins/virtual-entries.ts +39 -6
  322. package/src/vite/rango.ts +28 -3
  323. package/src/vite/router-discovery.ts +96 -13
  324. package/src/vite/utils/bundle-analysis.ts +39 -7
  325. package/src/vite/utils/client-chunks.ts +5 -1
  326. package/src/vite/utils/compare-strings.ts +9 -0
  327. package/src/vite/utils/package-resolution.ts +9 -0
  328. package/src/vite/utils/prerender-utils.ts +4 -1
  329. package/src/vite/utils/shared-utils.ts +1 -1
  330. package/dist/types/segment-content-promise.d.ts +0 -13
  331. package/src/segment-content-promise.ts +0 -67
@@ -17,6 +17,25 @@ export type HandleData = Record<string, Record<string, unknown[]>>;
17
17
  * Reads data directly from the store for each segment in order.
18
18
  */
19
19
  export declare function buildHandleSnapshot(handleStore: HandleStore, segmentOrder: string[]): HandleData;
20
+ /**
21
+ * What a restored record is to one loader's handle pushes on this request
22
+ * (loader-cache.ts loaderPins; docs/design/handle-push-ownership.md). Two
23
+ * answers let the record's copies stand, two make them placeholders, and in
24
+ * each pair one also speaks for the loader's other pushes:
25
+ * - "pin": the request serves the loader's value from the pin stored with
26
+ * the record, and the record lists every settled push of that run. Its
27
+ * copies stand, and any other settled push of the loader is dropped.
28
+ * - "copies": its copies stand and nothing else is known: a dependency of
29
+ * pinned loaders, or a pin written before captures recorded every push.
30
+ * - "hole": the route runs the loader on this request (it registers it and
31
+ * the record does not pin it). Its copies are placeholders and a push made
32
+ * in its body is its own, with or without copies.
33
+ * - "placeholders": its copies are placeholders and nothing else is known: a
34
+ * dependency the route does not register while a pin is missing (the
35
+ * record does not name the loader that ran it). Without copies its push
36
+ * counts for the loader that awaits it.
37
+ */
38
+ export type RecordAuthority = "pin" | "copies" | "hole" | "placeholders";
20
39
  /**
21
40
  * HandleStore tracks pending handler promises and stores handle data.
22
41
  *
@@ -81,69 +100,86 @@ export interface HandleStore {
81
100
  */
82
101
  push(handleName: string, segmentId: string, data: unknown, loaderPush?: boolean, owner?: string): void;
83
102
  /**
84
- * push() a loader-cache HIT's replayed value, recorded from `loaderId`'s
85
- * body (loader-cache.ts replayLoaderHandles). If that loader then runs live
86
- * in this request, its first push removes every value replayed for it and
87
- * takes the first one's position (later live pushes follow it), so the
88
- * handle output stays live without a duplicate. A push counts as that
89
- * loader's when it is made in its body, or in a body it entered that has
90
- * no replayed values of its own (the capture credits a dependency's push
91
- * under a live-lane loader to that loader); a hole's run that ends without
92
- * one drops them (settleLoaderRun).
103
+ * push() a cached unit's copy of a value `loaderId`'s body pushed
104
+ * (handle-snapshot.ts appendHandles: a loader-cache or "use cache" HIT). If
105
+ * that loader then runs live in this request, its first push removes every
106
+ * copy pushed for it (replays and placeholders) and takes the first one's
107
+ * position, and the pushes of that run follow in push order, a dependency's
108
+ * included, so the handle output stays live without a duplicate. A push
109
+ * counts as that loader's when it is made in its body, or in a body it
110
+ * entered that has no copies of its own (the capture credits a dependency's
111
+ * push under a live-lane loader to that loader). A run that ends without a
112
+ * push leaves a replay in place, unless the loader is a hole
113
+ * (settleLoaderRun).
93
114
  */
94
115
  pushReplayed(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
95
116
  /**
96
- * push() a document HIT's copy of `loaderId`'s settled push, restored from
97
- * the shell's doc record (handle-snapshot.ts restoreHandles). The record is
98
- * authoritative for that loader's settled pushes: the prelude was rendered
99
- * from it, and a run of the loader on the HIT reads the store, not the
100
- * capture's values. So from then on this request drops every settled,
101
- * thenable-free push the loader makes (live, or replayed from a cache
102
- * entry, anywhere inside its body), and keeps the ones holding a thenable
103
- * (holdsThenable: what the record could not keep, `runs`), placed among the
104
- * restored copies in the loader's push order. Only bake-lane owners are
105
- * restored this way (withCacheLookup): a live-lane loader is a hole.
117
+ * push() a record's copy of `loaderId`'s push as a placeholder
118
+ * (handle-snapshot.ts restoreHandles): the record does not supply that
119
+ * loader's value on this request, so its own source decides its pushes. A
120
+ * live run replaces it as it does a replay; a run that ends without a push
121
+ * drops it (settleLoaderRun); a cached unit that claims the loader delivers
122
+ * in its place (replacePlaceholders).
123
+ */
124
+ pushPlaceholder(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
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.
106
132
  */
107
133
  pushRestored(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
108
134
  /**
109
- * The loaders the route runs on the live lane (liveLaneLoaderIds), from a
110
- * PPR shell record's restore (handle-snapshot.ts restoreHandles): the
111
- * holes. A push counts for a restored loader when that loader is the
112
- * replayed one or the innermost enclosing loader body that restored
113
- * copies; the walk out through enclosing bodies stops at a hole's body,
114
- * and a replay of a hole's push counts for none. So a restored loader
115
- * never takes a push made inside a hole it awaited, while a body inside the
116
- * hole that restored copies of its own (a dependency the capture ran under
117
- * a bake-lane loader) still takes its pushes.
135
+ * What the record this request restored is to each loader (RecordAuthority;
136
+ * CacheScope.lookupRouteDetailed sets it on a hit). A "pin" loader counts
137
+ * as restored with or without copies. A hole is a "hole" loader or one with
138
+ * placeholders: the walk out through enclosing loader bodies that finds the
139
+ * loader a push counts for stops at its body, so a pinned loader never
140
+ * takes a push made inside a hole it awaited.
118
141
  */
119
- markLiveLane(loaderIds: ReadonlySet<string>): void;
142
+ setRecordAuthority(authority: (loaderId: string) => RecordAuthority): void;
120
143
  /**
121
144
  * `loaderId`'s run in this request settled (resolved or rejected), its
122
- * pushes made (loader-resolution.ts createLoaderExecutor). When the loader
123
- * is a hole (markLiveLane), values replayed for it that no push of the run
124
- * replaced are dropped: the run's output decides, so a hole that throws or
125
- * skips its push shows none rather than the capture's. Any other loader's
126
- * replayed values stay: a bake-lane loader's record is authoritative for
127
- * its settled pushes, as its pin is for its data. Restored copies are not
128
- * replays and stand.
145
+ * pushes made (loader-resolution.ts createLoaderExecutor). Its placeholders
146
+ * that no push of the run replaced are dropped: the run's output decides,
147
+ * so a loader that throws or skips its push shows none rather than the
148
+ * record's. A hole's replays go with them. Any other loader's replays stay
149
+ * (a dependency another entry's HIT replayed), and so do restored copies.
129
150
  */
130
151
  settleLoaderRun(loaderId: string): void;
131
152
  /**
132
- * A hole's own cache() HIT (loader-cache.ts replayLoaderHandles, once it
133
- * claims the hole): the values replayed for hole `loaderId` before (its
134
- * shell copies, which restoreHandles leaves unclaimed, those of the
135
- * dependencies credited to it included) give way to the pushes the entry
136
- * recorded, none when it recorded none, so they match the entry's data.
137
- * `deliver` makes the pushReplayed calls, which take the removed values'
138
- * place in each array. Any other loader, or a hole with nothing replayed,
139
- * delivers as a plain replay.
153
+ * A cached unit's HIT delivering the pushes it recorded for `loaderIds`,
154
+ * the loaders it claimed (appendHandles). Their placeholders give way to
155
+ * what `deliver` pushes for them, nothing when it pushes nothing, so the
156
+ * page shows the pushes of the run that produced the unit's value. The
157
+ * pushReplayed calls `deliver` makes take the removed values' place in each
158
+ * array, in order. Without placeholders it is a plain replay.
140
159
  */
141
- redeliverReplays(loaderId: string, deliver: () => void): void;
160
+ replacePlaceholders(loaderIds: readonly string[], deliver: () => void): void;
142
161
  /**
143
162
  * Get all collected handle data after all handlers have settled.
144
163
  * Waits for `settled` (handler lane), then returns the data at that point.
145
164
  */
146
165
  getData(): Promise<HandleData>;
166
+ /**
167
+ * Fix the document lane at the store's current state. From then on
168
+ * `stream("settled")` yields this state and nothing newer, and
169
+ * `streamLate()` delivers every change made after it, whether or not it
170
+ * beat the handler barrier. The first call wins. It must run before the
171
+ * document stream is first read: a stream that started on the live state
172
+ * stays on it (reported through `onError` in development).
173
+ *
174
+ * A PPR shell HIT calls it once its record is replayed and before a loader
175
+ * runs (rsc-rendering.ts serveShellHit). The prelude was rendered from the
176
+ * record's handle data (resolvedHandleStream `recordedOnly`), so that is
177
+ * what the client must hydrate with. What the request's loaders then push,
178
+ * replace or drop is theirs, not the shell's: in the document snapshot it
179
+ * rendered elements the prelude never had, or left out ones it has (issue
180
+ * #1035), and it got there or not by a race with the lane's first read.
181
+ */
182
+ freezeDocumentSnapshot(): void;
147
183
  /**
148
184
  * Get an async iterator that yields handle data on each push.
149
185
  * Completes at the chosen settlement barrier: "fullySettled" (default —
@@ -152,6 +188,9 @@ export interface HandleStore {
152
188
  * blocking positions and must not wait on loader bodies).
153
189
  * Each yield contains the full accumulated state (not just the delta).
154
190
  * Safe for concurrent consumers (per-consumer version cursor).
191
+ * The "settled" lane of a frozen store (freezeDocumentSnapshot) yields the
192
+ * frozen state once, at once, and ends. That yield is the store's own
193
+ * frozen object: a consumer must not write to it.
155
194
  */
156
195
  stream(until?: "settled" | "fullySettled"): AsyncGenerator<HandleData, void, unknown>;
157
196
  /**
@@ -160,7 +199,9 @@ export interface HandleStore {
160
199
  * fullySettled. Returns without yielding when the auxiliary lane is empty
161
200
  * by the time `settled` resolves. The client consumes this post-hydration
162
201
  * (rsc-router.tsx) and merges via the same application path as nav-lane
163
- * progressive handle updates.
202
+ * progressive handle updates. On a frozen store (freezeDocumentSnapshot)
203
+ * it starts from the frozen state instead: a change made before the
204
+ * handler barrier is late too.
164
205
  */
165
206
  streamLate(): AsyncGenerator<HandleData, void, unknown>;
166
207
  /**
@@ -177,6 +218,8 @@ export interface HandleStore {
177
218
  * value are omitted; undefined when none has one.
178
219
  */
179
220
  getRecordOwners(segmentId: string): Record<string, (string | null)[]> | undefined;
221
+ /** The segment ids for which getRecordOwners returns an entry. */
222
+ getOwnedSegmentIds(): string[];
180
223
  /**
181
224
  * Replay cached handle data back into the store (for cache hits).
182
225
  * Used to restore handle data when serving cached segments.
@@ -19,7 +19,8 @@ import type { Handle } from "../handle.js";
19
19
  import { type ContextVar } from "../context-var.js";
20
20
  import { type HandleStore, type HandleData } from "./handle-store.js";
21
21
  import { type MetricsStore } from "./context.js";
22
- import type { SegmentCacheStore } from "../cache/types.js";
22
+ import type { SegmentCacheStore, ShellSnapshotHandlesValue } from "../cache/types.js";
23
+ import type { RouterVersions } from "../router-versions.js";
23
24
  import type { Theme, ResolvedThemeConfig } from "../theme/types.js";
24
25
  import type { ExecutionContext, RequestScope } from "../types/request-scope.js";
25
26
  import type { TransitionWhenRecord } from "../router/transition-when.js";
@@ -203,6 +204,25 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
203
204
  _pprReplayPostMatchReason?: "prerender-store" | "intercept";
204
205
  /** @internal Cache store for segment caching (optional, used by CacheScope) */
205
206
  _cacheStore?: SegmentCacheStore;
207
+ /**
208
+ * @internal Env-scoped writable prerender store (the durable overlay) plus the
209
+ * deployment identity for build-scoped keys, resolved per request from the
210
+ * `prerender` router option. Read by the serve-path overlay lookup before the
211
+ * bundled build manifest. Absent when no prerender store is configured.
212
+ */
213
+ _prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
214
+ /**
215
+ * @internal Set only on the requestless on-demand producer's context. When
216
+ * present, the standalone request-scoped READS — `cookies()`, `headers()`,
217
+ * `invalidateClientCache()`, `keepClientCache()` — throw a
218
+ * PrerenderPersonalizationError so a personalized render is skipped rather than
219
+ * baked into a shared payload. Response MUTATIONS on the producer context
220
+ * (`ctx.setStatus`/`header`/`setCookie`) stay silent no-op stubs, matching
221
+ * build-time prerender (the design's "throw or skip" contract permits skip):
222
+ * they write to a discarded synthetic response, so there is nothing to leak.
223
+ * Never set on the live request path.
224
+ */
225
+ _onDemandProducer?: true;
206
226
  /**
207
227
  * @internal Compiled `cache.searchParams` filter for default cache-key
208
228
  * generation (undefined = "all", the byte-stable unfiltered format). Set
@@ -271,6 +291,20 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
271
291
  * cache miss.
272
292
  */
273
293
  _shellForcedMiss?: true;
294
+ /**
295
+ * @internal This request is a router.prerender() warm
296
+ * (prerender/warm-request.ts). In `replace` mode every runtime cache read
297
+ * misses (isWarmReplace); the layers report into the record. A capture's
298
+ * derived context inherits it through the prototype.
299
+ */
300
+ _prerenderWarm?: import("../prerender/warm-request.js").PrerenderWarmRecord;
301
+ /**
302
+ * @internal Runs a callback in the async context this request entered the
303
+ * handler with (captureRequestEntryContext). router.prerender() dispatches
304
+ * a warm through it when called from inside a request. Absent where the
305
+ * runtime has no AsyncLocalStorage.snapshot.
306
+ */
307
+ _runAtRequestEntry?: <T>(fn: () => T) => T;
274
308
  /**
275
309
  * @internal The freshness window of the route cache() records this
276
310
  * request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
@@ -283,7 +317,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
283
317
  _routeRecordWindow?: RouteRecordWindow;
284
318
  /**
285
319
  * @internal Loader-family snapshot seed for a shell HIT's tail render:
286
- * segment-key -> the capture's elided container (already Flight-deserialized
320
+ * loader id -> the capture's elided container (already Flight-deserialized
287
321
  * by serveShellHit) plus its capture-computed hole bit. resolveLoaderData
288
322
  * overlays it onto the fresh run's container (recorded paths pinned,
289
323
  * hole-marker paths keep the fresh nested promises) so the payload's baked
@@ -291,7 +325,9 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
291
325
  * and does not run the loader. Two owners: serveShellHit sets it on the
292
326
  * HIT tail's derived context, and matchPartialWithPprReplay sets it on the
293
327
  * request context of a PPR partial replay once its doc record hits, and
294
- * restores the previous value after the match.
328
+ * restores the previous value after the match. Read through servedPins
329
+ * (loader-cache.ts) only: it also decides which of the record's
330
+ * loader-owned handle pushes stand (loaderPins).
295
331
  */
296
332
  _shellLoaderSeed?: Map<string, import("../cache/shell-snapshot.js").ShellLoaderSeedEntry>;
297
333
  /**
@@ -348,9 +384,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
348
384
  * scope replaces any route-derived cache() scope for the tail's match
349
385
  * (resolveShellImplicitCacheScope), and a lookup that does not hit throws
350
386
  * ShellRecordUnavailableError instead of resolving segments
351
- * (withCacheLookup): a HIT never runs a handler. The record's
352
- * loader-owned handle pushes restore as authoritative
353
- * (HandleStore.pushRestored): the prelude rendered them.
387
+ * (withCacheLookup): a HIT never runs a handler.
354
388
  */
355
389
  docTail?: true;
356
390
  /**
@@ -360,6 +394,8 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
360
394
  * host) and miss the record.
361
395
  */
362
396
  fixedDocKey?: string;
397
+ /** @internal The snapshot's `handles` record (ShellSnapshotHandlesValue). */
398
+ prerenderHandles?: ShellSnapshotHandlesValue;
363
399
  /**
364
400
  * @internal Set ONLY by matchPartialWithPprReplay on the navigation-replay
365
401
  * serve path. Its presence arms the explicit-scope composition in
@@ -671,6 +707,17 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
671
707
  * deriveShellCaptureContext gives the capture its own.
672
708
  */
673
709
  _renderErrors?: unknown[];
710
+ /**
711
+ * @internal Rejections of streamed (loading()) handlers that were recovered
712
+ * into a declared errorBoundary()/notFoundBoundary() fallback, by segment id.
713
+ * The recovered promise resolves, so Flight reports nothing; cacheRoute
714
+ * (cache-scope.ts) refuses a write only when one of ITS segments is listed,
715
+ * the granularity a Flight error row has. The same errors are also pushed to
716
+ * `_renderErrors` for the document cache and PPR shell capture. A render
717
+ * under a derived context (shell capture, SWR re-render) owns its own map.
718
+ * Allocated on the first recovery.
719
+ */
720
+ _recoveredHandlerErrors?: Map<string, unknown>;
674
721
  /**
675
722
  * @internal Report a non-fatal background error through the router's
676
723
  * onError callback. Wired by the RSC handler / router during request
@@ -708,6 +755,14 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
708
755
  /** @internal Owning router id; scopes the search-schema/root-scope registry
709
756
  * lookups per router (route-map-builder.ts) */
710
757
  _routerId?: string;
758
+ /**
759
+ * @internal Cache versions of the router serving this request. The cache
760
+ * factory builds a store per request without knowing the router, so a store
761
+ * reads its key versions from here, lazily, the same way CFCacheStore
762
+ * resolves its base URL (getCacheVersions, server/build-version-table.ts).
763
+ * Unset on a context no router created; a store then uses the build version.
764
+ */
765
+ _versions?: RouterVersions;
711
766
  /**
712
767
  * @internal RouteSnapshot from classifyRequest, reused by match/matchPartial
713
768
  * to avoid a second resolveRoute call. Cleared on HMR invalidation.
@@ -748,7 +803,7 @@ export interface RouteRecordWindow {
748
803
  * This is the type exported to library consumers. Internal code should
749
804
  * use the full RequestContext interface directly.
750
805
  */
751
- export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_locationState" | "_routeName" | "_prevRouteKey" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
806
+ 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" | "_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">;
752
807
  /**
753
808
  * Marker for a waitUntil-scheduled fn whose task promise must NOT enter
754
809
  * _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
@@ -757,6 +812,15 @@ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, str
757
812
  * @internal
758
813
  */
759
814
  export declare const UNTRACKED_BACKGROUND_TASK: unique symbol;
815
+ /**
816
+ * Capture the current async context (RequestContext._runAtRequestEntry), taken
817
+ * on handler entry before any router scope, so a nested dispatch (a
818
+ * router.prerender() warm called from a handler, loader or action) does not
819
+ * inherit the caller's route-definition, loader and cache-scope state. Per
820
+ * request: workerd refuses a snapshot outside the request that created it.
821
+ * See docs/design/prerender-every-route.md.
822
+ */
823
+ export declare function captureRequestEntryContext(): (<T>(fn: () => T) => T) | undefined;
760
824
  /**
761
825
  * Run a function within a request context
762
826
  * Used by the RSC handler to provide context to server actions
@@ -804,6 +868,12 @@ export interface CreateRequestContextOptions<TEnv> {
804
868
  initialResponse?: Response;
805
869
  /** Optional cache store for segment caching (used by CacheScope) */
806
870
  cacheStore?: SegmentCacheStore;
871
+ /**
872
+ * Optional env-scoped writable prerender store + deployment identity (the
873
+ * durable overlay), resolved per request by the RSC handler from the
874
+ * `prerender` router option.
875
+ */
876
+ prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
807
877
  /**
808
878
  * Compiled `cache.searchParams` filter from the resolved handler cache
809
879
  * config (handler.ts). Stored as _searchParamsFilter.
@@ -824,8 +894,13 @@ export interface CreateRequestContextOptions<TEnv> {
824
894
  themeConfig?: ResolvedThemeConfig | null;
825
895
  /** Resolved rango state cookie name, for the server seat of invalidateClientCache(). */
826
896
  stateCookieName?: string;
827
- /** Build version, used as the prefix of a server-rotated rango state value. */
828
- version?: string;
897
+ /**
898
+ * The versions of the router serving this request (resolveRouterVersions).
899
+ * Stored as `_versions` for the cache stores; `document` is also the prefix
900
+ * of a server-rotated rango state value, which the browser compares with the
901
+ * payload's `metadata.version`.
902
+ */
903
+ versions?: RouterVersions;
829
904
  }
830
905
  /**
831
906
  * Create a full request context with all methods implemented
@@ -0,0 +1,26 @@
1
+ import { type ReactNode } from "react";
2
+ import { type BoundaryAudit } from "./suspense-audit.js";
3
+ /**
4
+ * One boundary: what each render hands it, what each commit carries, and its
5
+ * mount. Called above the Suspense, which commits while the content waits.
6
+ * `streams` and `nodes` are what else its content waits for (I3 only).
7
+ */
8
+ export declare function useBoundaryAudit(boundary: string, segmentId: string, value: unknown, streams?: Record<string, unknown>, nodes?: unknown): BoundaryAudit;
9
+ /** The boundary's content is on screen. */
10
+ export declare function useRevealAudit(rec: BoundaryAudit): void;
11
+ /**
12
+ * One `useLoader` read of a per-loader stream (I1, I2 at the read site). A
13
+ * read that suspends while mounting keeps no record: only a reader on screen
14
+ * is audited.
15
+ */
16
+ export declare function useReadAudit(loaderId: string, stream: unknown): void;
17
+ /** Wraps a boundary's fallback: mounted means the fallback is on screen. */
18
+ export declare function AuditedFallback({ audit, children, }: {
19
+ audit: BoundaryAudit;
20
+ children: ReactNode;
21
+ }): ReactNode;
22
+ /** Wraps a segment's outlet children: the segment's mount (I4). */
23
+ export declare function AuditedOutlet({ segmentId, children, }: {
24
+ segmentId: string;
25
+ children: ReactNode;
26
+ }): ReactNode;
@@ -0,0 +1,157 @@
1
+ export type SuspenseAuditKind = "swap" | "untracked" | "idle-fallback" | "resuspended" | "remount" | "drift" | "uncaused" | "mutated";
2
+ /** What may hand React a tree (I6). */
3
+ export type TreeUpdateCause = "navigation" | "popstate" | "stale-revalidation" | "action" | "error" | "hmr";
4
+ export interface SuspenseAuditEvent {
5
+ /** I1 swap, I2 untracked, I3 idle-fallback and resuspended, I4 remount, I5 drift, I6 uncaused, I7 mutated. */
6
+ kind: SuspenseAuditKind;
7
+ /** `content:<segment id>`, `loaders:<outlet key>`, `outlet:<segment id>`, `read:<loader id>`, `segment:<segment id>`. */
8
+ boundary: string;
9
+ detail: string;
10
+ url: string;
11
+ at: number;
12
+ }
13
+ export interface SuspenseAuditReport {
14
+ swaps: number;
15
+ untracked: number;
16
+ idleFallbacks: number;
17
+ resuspended: number;
18
+ remounts: number;
19
+ drifts: number;
20
+ uncaused: number;
21
+ mutations: number;
22
+ /**
23
+ * Not a violation: fallbacks the router cannot attribute. Nothing it handed
24
+ * the boundary was a promise React read, so the content's own suspension
25
+ * put the fallback up: an app's use(), a React.lazy, a client reference.
26
+ */
27
+ unattributedFallbacks: number;
28
+ /** Not a violation: tree updates React was handed, by cause ("none" without one). */
29
+ treeUpdates: Record<string, number>;
30
+ /**
31
+ * Not a violation: the distinct thenables each boundary or read was handed.
32
+ * One per value it waited for; two for one navigation is a gate replaced
33
+ * by the real promise.
34
+ */
35
+ readonly handed: Record<string, number>;
36
+ /**
37
+ * Not a violation: fallbacks shown over content on screen while what the
38
+ * boundary waits for was pending. An urgent commit does that by design.
39
+ */
40
+ shownWhilePending: number;
41
+ /** Mounts per boundary since the document loaded. */
42
+ readonly mounts: Record<string, number>;
43
+ /** The last events, oldest first. */
44
+ events: SuspenseAuditEvent[];
45
+ reset(): void;
46
+ }
47
+ /** One boundary, or one `useLoader` read. Lives as long as its fiber. */
48
+ export interface BoundaryAudit {
49
+ boundary: string;
50
+ /** Segment id, for the place in the tree. */
51
+ segmentId: string;
52
+ /** The React key the segment was mounted under (I4 identity). */
53
+ key: string;
54
+ /** 0 until the boundary is on screen. */
55
+ mountId: number;
56
+ /** Last value a render ran with, and the URL it ran under. */
57
+ seen: unknown;
58
+ hasSeen: boolean;
59
+ seenUrl: string;
60
+ /** Last value a commit carried. */
61
+ committed: unknown;
62
+ hasCommitted: boolean;
63
+ /** What else the boundary's content waits for: per-loader streams, nodes. */
64
+ streams: Record<string, unknown> | undefined;
65
+ nodes: unknown;
66
+ /** The content has been on screen. */
67
+ revealed: boolean;
68
+ /** The fallback's effect was cleaned up in this task (auditFallback). */
69
+ fallbackGone: boolean;
70
+ }
71
+ export declare function createBoundaryAudit(boundary: string, segmentId: string): BoundaryAudit;
72
+ /**
73
+ * Render phase: the value this render hands the boundary.
74
+ *
75
+ * I1: a boundary on screen was handed a thenable that is still pending, and
76
+ * is handed another one that is not already settled, for the same URL. React
77
+ * starts waiting again. A settled replacement is read at once, and another
78
+ * URL is another navigation: both are exempt.
79
+ * I2: a boundary whose content has been on screen is handed a native promise
80
+ * React has not read, and React finds it settled when it reads it. A render
81
+ * that cannot wait suspends on it and commits the fallback over the content,
82
+ * which React keeps up for 300 ms. Judged from the status React leaves on
83
+ * the promise when it reads it in the same task.
84
+ */
85
+ export declare function auditHandover(rec: BoundaryAudit, value: unknown): void;
86
+ /** Commit phase: what the boundary on screen now reads. */
87
+ export declare function auditCommit(rec: BoundaryAudit, value: unknown, streams?: Record<string, unknown>, nodes?: unknown): void;
88
+ export declare function auditReveal(rec: BoundaryAudit): void;
89
+ /** One `useLoader` read on screen: it has a mount and reveals with it. */
90
+ export declare function auditRead(rec: BoundaryAudit, stream: unknown): void;
91
+ /**
92
+ * How the audit learns that a payload is still streaming: the event
93
+ * controller, set at boot (browser/rsc-router.tsx). Not read from
94
+ * NavigationStoreContext in AuditedFallback: see the header.
95
+ */
96
+ export declare function setSuspenseAuditStreamProbe(probe: () => boolean): void;
97
+ /**
98
+ * I3: the boundary's fallback is on screen with nothing to wait for: nothing
99
+ * the router handed the boundary is pending, no payload is streaming and no
100
+ * client reference is loading. `idle-fallback` on a boundary new to the page,
101
+ * `resuspended` when the fallback replaced content that had been on screen.
102
+ *
103
+ * Reported only when the router owns the fallback: React suspended on a
104
+ * promise the router handed unread that was already settled (`needless`).
105
+ * Any other fallback is the content's own (an app's use(), a React.lazy, a
106
+ * client reference) and is counted as `unattributedFallbacks`, not reported,
107
+ * also when the boundary holds a promise React has read.
108
+ *
109
+ * A fallback over content on screen while something is pending is counted
110
+ * (`shownWhilePending`) and not reported: an urgent commit does that by
111
+ * design (transition({ when }) gated off, #995), and so does dev while a
112
+ * client reference loads.
113
+ */
114
+ export declare function auditFallback(rec: BoundaryAudit): () => void;
115
+ /** One renderSegments call, collected while it builds. */
116
+ export interface TreeAudit {
117
+ /** Segment ids, leaf first while building, root first once finished. */
118
+ order: string[];
119
+ keys: Map<string, string>;
120
+ types: Map<string, string>;
121
+ chains: Map<string, string[]>;
122
+ /** Segments this tree remounts by the documented rules. */
123
+ replaced: Set<string>;
124
+ /** The segment objects the tree is built from (I7), until it is held. */
125
+ segments: object[];
126
+ }
127
+ export declare function startTreeAudit(): TreeAudit | undefined;
128
+ /** The element renderSegments built for one segment, leaf first. */
129
+ export declare function auditSegmentElement(tree: TreeAudit | undefined, id: string, type: string, key: string, element: unknown, outletTransition: boolean, slots: readonly string[], segments: readonly object[]): void;
130
+ /**
131
+ * A finished tree. The first is the document's, which React holds from
132
+ * hydration; any later one is held when an emit hands its root to React
133
+ * (auditTreeUpdate).
134
+ */
135
+ export declare function finishTreeAudit(tree: TreeAudit | undefined, root: unknown): void;
136
+ /**
137
+ * I4: a boundary that stays on the page under the same React key is
138
+ * unmounted and mounted again. A different key is the documented remount.
139
+ */
140
+ export declare function auditMount(rec: BoundaryAudit): void;
141
+ export declare function auditUnmount(rec: BoundaryAudit): void;
142
+ /**
143
+ * I6: the cause of the tree update the caller emits next, in the same task.
144
+ * It does not outlive the task: an emit after an await names its cause again,
145
+ * or a cause left behind would cover an emitter that names none.
146
+ */
147
+ export declare function auditTreeCause(cause: TreeUpdateCause): void;
148
+ /**
149
+ * I6: a tree update reached React (the store.onUpdate subscriber in
150
+ * browser/react/NavigationProvider.tsx), with the root it hands React. Only a
151
+ * navigation, a back/forward, its stale revalidation, an action, an error and
152
+ * HMR hand React a tree; anything else updates in place through a store its
153
+ * readers subscribe to, or through a pending promise read with use().
154
+ */
155
+ export declare function auditTreeUpdate(root?: unknown): void;
156
+ /** Forget every tree and mount seen so far. For tests of the audit itself. */
157
+ export declare function forgetSuspenseAudit(): void;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * createActionForm: the FormData a browser posts when a form is submitted
3
+ * before hydration (no JavaScript), for a server action.
4
+ *
5
+ * React's server render writes hidden fields on the form so the POST names its
6
+ * action and carries the bound state; decodeAction / decodeFormState read them
7
+ * back. A test cannot render those fields (react-dom/server does not load under
8
+ * the react-server condition), so this builds the same wire format and
9
+ * registers the action where the plugin-rsc stub's decodeAction resolves it,
10
+ * tagged as a server reference like a built "use server" export so the bound
11
+ * action keeps its `$$id` (onError's actionId, the action phase label).
12
+ * Post the result with `serveShellRequest(router, url, { form })`.
13
+ */
14
+ /** Options for {@link createActionForm}. */
15
+ export interface CreateActionFormOptions {
16
+ /**
17
+ * The action's reference id, `<module id>#<export name>`, as the build gives
18
+ * a "use server" export. Any unique string of that shape in a test.
19
+ */
20
+ id: string;
21
+ /**
22
+ * A `useActionState` form (default): the action runs as `(prevState, formData)`
23
+ * and the POST carries the state key. false: a plain `<form action={fn}>`
24
+ * ($ACTION_ID_), the action runs as `(formData)`.
25
+ */
26
+ useActionState?: boolean;
27
+ /** The form's own fields, as the person filled them. */
28
+ fields?: Record<string, string>;
29
+ }
30
+ /**
31
+ * Build a no-JS form POST body for `action` and register it so a handler
32
+ * decodes it back to `action`.
33
+ */
34
+ export declare function createActionForm(action: (...args: any[]) => unknown, options: CreateActionFormOptions): FormData;
@@ -0,0 +1,32 @@
1
+ import { type RouterVersions } from "../router-versions.js";
2
+ export type { RouterVersions };
3
+ /**
4
+ * The versions a simulated build ships.
5
+ *
6
+ * - `data` and `document`: the versions of every router the test does not list
7
+ * under `routers` (the build's whole-build pair).
8
+ * - `routers`: versions per router id (`router.id`), as a host-router build
9
+ * computes them.
10
+ */
11
+ export interface BuildVersions extends RouterVersions {
12
+ routers?: Record<string, RouterVersions>;
13
+ }
14
+ /**
15
+ * Install the cache versions of a simulated build, or remove them with no
16
+ * argument (routers serve unversioned again, the default in tests).
17
+ *
18
+ * A router that sets `createRouter({ version })` keeps that value for both
19
+ * versions, exactly as in production.
20
+ *
21
+ * @example A deploy that changes the client only keeps cached data
22
+ * ```ts
23
+ * setBuildVersions({ data: "d1", document: "h1" });
24
+ * await serveShellRequest(router, "/product/1", { cacheStore });
25
+ * setBuildVersions({ data: "d1", document: "h2" });
26
+ * const { shellStatus } = await serveShellRequest(router, "/product/1", {
27
+ * cacheStore,
28
+ * });
29
+ * // shellStatus is "MISS": the stored HTML was keyed by document version h1.
30
+ * ```
31
+ */
32
+ export declare function setBuildVersions(versions?: BuildVersions): void;
@@ -12,4 +12,4 @@
12
12
  * (`happy-dom` or `jsdom`).
13
13
  */
14
14
  export { renderRoute } from "./render-route.js";
15
- export type { RenderRouteSpec, RenderRouteOptions, TestRouterHandle, RenderRouteResult, HandleDataSeed, } from "./render-route.js";
15
+ export type { RenderRouteSpec, RenderRouteOptions, TestRouterHandle, RenderRouteResult, RenderRouteHydrateResult, HandleDataSeed, } from "./render-route.js";