@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
package/dist/bin/rango.js CHANGED
@@ -1571,6 +1571,11 @@ function mergeFullManifests(manifests) {
1571
1571
  manifest.passthroughRoutes,
1572
1572
  overwrittenRoutes
1573
1573
  ),
1574
+ onDemandRoutes: mergeRouteList(
1575
+ merged.onDemandRoutes,
1576
+ manifest.onDemandRoutes,
1577
+ overwrittenRoutes
1578
+ ),
1574
1579
  responseTypeRoutes: mergeRouteRecord(
1575
1580
  merged.responseTypeRoutes,
1576
1581
  manifest.responseTypeRoutes,
@@ -1599,14 +1604,33 @@ var init_merge_full_manifests = __esm({
1599
1604
  }
1600
1605
  });
1601
1606
 
1607
+ // src/router-versions.ts
1608
+ var DEFAULT_ROUTER_VERSIONS_KEY;
1609
+ var init_router_versions = __esm({
1610
+ "src/router-versions.ts"() {
1611
+ "use strict";
1612
+ DEFAULT_ROUTER_VERSIONS_KEY = "*";
1613
+ }
1614
+ });
1615
+
1602
1616
  // src/vite/plugins/virtual-entries.ts
1603
1617
  function getVirtualVersionContent(version) {
1604
- return `export const VERSION = ${JSON.stringify(version)};`;
1605
- }
1606
- var VIRTUAL_ENTRY_BROWSER, VIRTUAL_IDS;
1618
+ return [
1619
+ `export const VERSION = ${JSON.stringify(version)};`,
1620
+ `export const ROUTER_VERSIONS = undefined;`
1621
+ ].join("\n");
1622
+ }
1623
+ function getVirtualBuildVersionContent() {
1624
+ return [
1625
+ `export const ROUTER_VERSIONS = ${ROUTER_VERSIONS_PLACEHOLDER};`,
1626
+ `export const VERSION = ROUTER_VERSIONS[${JSON.stringify(DEFAULT_ROUTER_VERSIONS_KEY)}][1];`
1627
+ ].join("\n");
1628
+ }
1629
+ var VIRTUAL_ENTRY_BROWSER, VIRTUAL_IDS, ROUTER_VERSIONS_PLACEHOLDER;
1607
1630
  var init_virtual_entries = __esm({
1608
1631
  "src/vite/plugins/virtual-entries.ts"() {
1609
1632
  "use strict";
1633
+ init_router_versions();
1610
1634
  VIRTUAL_ENTRY_BROWSER = `
1611
1635
  import {
1612
1636
  createFromReadableStream,
@@ -1634,6 +1658,12 @@ async function initializeApp() {
1634
1658
  // is the default; createRouter({ strictMode: false }) ships the opt-out in the
1635
1659
  // payload metadata. StrictMode emits no DOM, so toggling never changes markup.
1636
1660
  const { strictMode, initialPayload } = await initBrowserApp({ rscStream, deps });
1661
+ // Set only on a document a no-JS useActionState POST rendered: React needs
1662
+ // the server's form state to hydrate the hook without resetting it. A state
1663
+ // Flight could not carry rejects: hydrate without it, as before.
1664
+ const formState = await Promise.resolve(initialPayload.formState).catch(
1665
+ () => undefined
1666
+ );
1637
1667
 
1638
1668
  if (import.meta.hot) {
1639
1669
  const { startDevDiscoveryHandshake } = await import(
@@ -1648,7 +1678,8 @@ async function initializeApp() {
1648
1678
  const app = createElement(Rango);
1649
1679
  hydrateRoot(
1650
1680
  document,
1651
- strictMode === false ? app : createElement(StrictMode, null, app)
1681
+ strictMode === false ? app : createElement(StrictMode, null, app),
1682
+ formState ? { formState } : undefined
1652
1683
  );
1653
1684
  }
1654
1685
 
@@ -1660,6 +1691,7 @@ initializeApp().catch(console.error);
1660
1691
  rsc: "virtual:rsc-router/entry.rsc.js",
1661
1692
  version: "@rangojs/router:version"
1662
1693
  };
1694
+ ROUTER_VERSIONS_PLACEHOLDER = "__RANGO_ROUTER_VERSIONS__";
1663
1695
  }
1664
1696
  });
1665
1697
 
@@ -1772,8 +1804,7 @@ function getClientModuleSignature(source) {
1772
1804
  };
1773
1805
  }
1774
1806
  function createVersionPlugin() {
1775
- const buildVersion = Date.now().toString(16);
1776
- let currentVersion = buildVersion;
1807
+ let currentVersion = Date.now().toString(16);
1777
1808
  let isDev = false;
1778
1809
  let server = null;
1779
1810
  let resolvedCacheDir;
@@ -1793,13 +1824,6 @@ function createVersionPlugin() {
1793
1824
  return {
1794
1825
  name: "@rangojs/router:version",
1795
1826
  enforce: "pre",
1796
- // The build-time shell capture phase (producer B, #699) stamps entries
1797
- // with THIS instance's version — the value folded into the shipped worker
1798
- // — never the discovery temp server's own version-plugin value (a
1799
- // different Date.now() stamp that would fail the serve-side gate).
1800
- api: {
1801
- getBuildVersion: () => currentVersion
1802
- },
1803
1827
  configResolved(config) {
1804
1828
  isDev = config.command === "serve";
1805
1829
  resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
@@ -1821,7 +1845,7 @@ function createVersionPlugin() {
1821
1845
  },
1822
1846
  load(id) {
1823
1847
  if (id === "\0" + VIRTUAL_IDS.version) {
1824
- return getVirtualVersionContent(currentVersion);
1848
+ return isDev ? getVirtualVersionContent(currentVersion) : getVirtualBuildVersionContent();
1825
1849
  }
1826
1850
  return null;
1827
1851
  },
@@ -2150,7 +2174,7 @@ if (command === "generate") {
2150
2174
  Modes:
2151
2175
  (default) Static parser with error on unresolvable includes
2152
2176
  --runtime Vite-based runtime discovery (100% coverage)
2153
- Requires vite and @vitejs/plugin-rsc
2177
+ Requires vite
2154
2178
  --static Static parser, accept partial output with warnings
2155
2179
 
2156
2180
  Options:
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { NavigationLocation, NavigateOptionsInternal, TrackedActionState, InflightAction, RscMetadata, HandleData, StreamingToken } from "./types.js";
3
+ import { type LocationStateSnapshot } from "./react/location-state-shared.js";
3
4
  /**
4
5
  * Phase of a navigation operation
5
6
  */
@@ -101,6 +102,15 @@ export interface HandleState {
101
102
  segmentOrder: string[];
102
103
  routeSegmentIds: string[];
103
104
  }
105
+ /**
106
+ * What the document's HTML was rendered with, kept for the hydration window
107
+ * (EventController.lockHydration).
108
+ */
109
+ export interface HydrationSnapshot {
110
+ state: DerivedNavigationState;
111
+ params: Record<string, string>;
112
+ handles: HandleState;
113
+ }
104
114
  /**
105
115
  * Result from starting a navigation
106
116
  * Implements Disposable for use with `using` keyword
@@ -196,6 +206,31 @@ export interface EventController {
196
206
  */
197
207
  resolvedIds?: string[]): void;
198
208
  getHandleState(): HandleState;
209
+ /**
210
+ * Open the hydration window. Until releaseHydrationLock(), getHandleState()
211
+ * returns the state the document's HTML was rendered with, and handle writes
212
+ * (setHandleData, setRouteSegmentIds) wait in order. initBrowserApp opens it
213
+ * before hydrateRoot, once the document's handle snapshot is applied: a hook
214
+ * reading the handle state when its boundary hydrates, however late, reads
215
+ * what SSR rendered (issue #1035).
216
+ */
217
+ lockHydration(): void;
218
+ /**
219
+ * While the hydration window is open, the state the document's HTML was
220
+ * rendered with; undefined once it closes. A router hook's first render
221
+ * reads it: a component hydrating in a boundary that streamed in late
222
+ * renders what SSR rendered, even after a navigation or an action started.
223
+ * The hook's effect then catches up with the live state, and its
224
+ * subscription stays live, so pending UI is not held back.
225
+ */
226
+ getHydrationSnapshot(): HydrationSnapshot | undefined;
227
+ /**
228
+ * Close the hydration window: apply the writes that waited, in order, and
229
+ * notify handle subscribers. NavigationProvider calls it after the commit
230
+ * that made React hydrate every boundary still dehydrated (its barrier).
231
+ * Idempotent.
232
+ */
233
+ releaseHydrationLock(): void;
199
234
  /**
200
235
  * Update ONLY `routeSegmentIds` (what `useSegments` reads) from `matched`,
201
236
  * leaving `data` and `segmentOrder` (what `useHandle` collects over) untouched.
@@ -206,6 +241,20 @@ export interface EventController {
206
241
  setRouteSegmentIds(matched: string[]): void;
207
242
  setParams(params: Record<string, string>): void;
208
243
  getParams(): Record<string, string>;
244
+ /**
245
+ * Record the committed history entry's location state from `entryState`:
246
+ * the state object the commit pushed, restored or merged into the entry,
247
+ * so the entry and its readers have one source. Notifies nobody:
248
+ * NavigationProvider takes the snapshot with the entry's payload
249
+ * (LocationStateContext). `treeless` marks a commit no payload follows (a
250
+ * shallow navigation, a commit that keeps every segment, an action's
251
+ * state): the provider takes it with this commit's state notification, in
252
+ * the batch of the location.
253
+ */
254
+ commitLocationState(entryState: unknown, treeless?: boolean): void;
255
+ getLocationState(): LocationStateSnapshot;
256
+ /** True once after a `treeless` commit. */
257
+ takeTreelessLocationState(): boolean;
209
258
  getCurrentNavigation(): NavigationEntry | null;
210
259
  getInflightActions(): Map<string, ActionEntry>;
211
260
  /** Whether any concurrent actions have occurred (shared across all handles) */
@@ -37,8 +37,20 @@ export declare const SHELL_MISS_MARKER: string;
37
37
  */
38
38
  export declare function stripShellMissMarker(): void;
39
39
  /**
40
- * Merge server-set location state into the current history entry.
41
- * Replaces the current history state and dispatches notification event
42
- * so useLocationState hooks re-read from history.state.
40
+ * Remove the `clearOnReload` slots of the entry a document load starts on:
41
+ * the server rendered this document without them. One pass before hydration
42
+ * (initBrowserApp; renderRoute's `hydrate` mode), so no reader needs to know
43
+ * the page began as a document load, and a slot nobody reads is removed too.
44
+ * No server-set state exists yet to lose: a document response carries none
45
+ * (rsc-rendering.ts attaches it to partial payloads only).
46
+ *
47
+ * A slot is recognised by its key alone (the `~r` suffix): at start-up the
48
+ * module that defines it may not be loaded.
43
49
  */
44
- export declare function mergeLocationState(locationState: Record<string, unknown>): void;
50
+ export declare function clearLocationStateOnDocumentLoad(): void;
51
+ /**
52
+ * Merge server-set location state into the current history entry and return
53
+ * the entry state written. Readers see it when the caller commits it
54
+ * (EventController.commitLocationState).
55
+ */
56
+ export declare function mergeLocationState(locationState: Record<string, unknown>): Record<string, unknown>;
@@ -1,4 +1,5 @@
1
1
  import type { NavigationStore, ResolvedSegment, HandleData } from "./types.js";
2
+ import type { EventController } from "./event-controller.js";
2
3
  /**
3
4
  * Clone the handleData CONTAINERS (the handle-name map and each segment map) so
4
5
  * a cache entry is decoupled from the live map that eventController mutates — it
@@ -11,6 +12,14 @@ import type { NavigationStore, ResolvedSegment, HandleData } from "./types.js";
11
12
  * non-serializable bucket contents (React elements, functions, etc.).
12
13
  */
13
14
  export declare function cloneHandleData(handleData: HandleData): HandleData;
15
+ /**
16
+ * Handle data to write into the history cache for the page on screen. During
17
+ * the hydration window getHandleState() is the document snapshot while late
18
+ * pushes sit queued in the controller (they are already in the cache entry,
19
+ * written by rsc-router), so writing the snapshot back would drop them; the
20
+ * entry's own data is the live view then.
21
+ */
22
+ export declare function liveHandleDataForCache(eventController: Pick<EventController, "getHandleState" | "getHydrationSnapshot">, store: Pick<NavigationStore, "getCachedSegments">, historyKey: string): HandleData;
14
23
  /**
15
24
  * Options for generating a history key
16
25
  */
@@ -36,6 +36,11 @@ interface CommitOptions {
36
36
  * partial updater reuses it instead of deciding again.
37
37
  */
38
38
  transitionGatedOff?: boolean;
39
+ /**
40
+ * No payload follows this commit: every segment is kept and the tree on
41
+ * screen stays (EventController.commitLocationState).
42
+ */
43
+ treeless?: boolean;
39
44
  }
40
45
  /**
41
46
  * Options that can override the pre-configured commit settings
@@ -57,6 +62,8 @@ interface BoundCommitOverrides {
57
62
  serverState?: Record<string, unknown>;
58
63
  /** The committed route's name (payload metadata), remembered per history entry. */
59
64
  routeName?: string;
65
+ /** No payload follows this commit (CommitOptions.treeless). */
66
+ treeless?: boolean;
60
67
  }
61
68
  /**
62
69
  * Bound transaction with pre-configured commit options (without segmentIds/segments)
@@ -3,6 +3,7 @@ import type { ReactNode } from "react";
3
3
  import type { RenderSegmentsOptions } from "../segment-system.js";
4
4
  import type { BoundTransaction } from "./navigation-transaction.js";
5
5
  import type { NavigationUpdate } from "./types.js";
6
+ import type { LoaderStore } from "../loader-store.js";
6
7
  import { type TransitionWhenActionInput } from "./transition-when.js";
7
8
  /**
8
9
  * Hold/animate decision for a commit: a non-intercept segment carries a
@@ -18,7 +19,7 @@ export declare function shouldStartViewTransition(segments: readonly ResolvedSeg
18
19
  * directly: nothing is held there, a reader of a pending stream suspends to
19
20
  * its fallback. Also used by renderRoute's navigate() (testing/render-route.tsx).
20
21
  */
21
- export declare function commitInTransition(onUpdate: UpdateSubscriber, segments: readonly ResolvedSegment[], update: NavigationUpdate, transitionTypes: readonly string[]): void;
22
+ export declare function commitInTransition(loaders: LoaderStore, onUpdate: UpdateSubscriber, segments: readonly ResolvedSegment[], update: NavigationUpdate, transitionTypes: readonly string[]): void;
22
23
  /**
23
24
  * Configuration for creating a partial updater
24
25
  */
@@ -2,30 +2,26 @@
2
2
  * Router-wide default prefetch strategy (client seat).
3
3
  *
4
4
  * The server resolves `createRouter({ defaultPrefetch })` once at router init
5
- * (router/prefetch-default.ts) and ships it in initial payload metadata; the
6
- * browser entry applies it here before hydration — same lifecycle as
7
- * `initPrefetchCache` / `setPrefetchConcurrency`. Every `<Link>` without an
8
- * explicit `prefetch` prop and every eligible intercepted plain anchor that has
9
- * not opted out with `data-prefetch="false"` or `data-prefetch="none"` uses it.
10
- * Containers use the same `false`/`none` vocabulary via
11
- * `data-prefetch-scope`.
12
- *
13
- * The module initial value must equal the server resolver's environment default:
14
- * `"none"` in development and `"viewport"` in production. During SSR this
15
- * module is never initialized from metadata, so keeping both seats aligned also
16
- * gives metadata-less payloads the documented behavior.
5
+ * (router/prefetch-default.ts) and ships it in initial payload metadata. The
6
+ * router store carries it to its readers: `<Link>` reads
7
+ * `NavigationStoreContext.defaultPrefetch`, and delegated plain anchors get it
8
+ * from the navigation bridge. Every `<Link>` without an explicit `prefetch`
9
+ * prop and every eligible intercepted plain anchor that has not opted out with
10
+ * `data-prefetch="false"` or `data-prefetch="none"` uses it. Containers use the
11
+ * same `false`/`none` vocabulary via `data-prefetch-scope`.
17
12
  */
18
13
  import type { PrefetchStrategy } from "../../router/prefetch-default.js";
19
- /** Reset module state between tests that replace browser media globals. */
20
- export declare function resetAdaptiveStrategyForTesting(): void;
21
14
  /**
22
- * Apply the server-resolved default strategy. Called once at browser app init
23
- * from payload metadata; also used by tests to reset state.
15
+ * The default for a payload without `defaultPrefetch`: the server resolver's
16
+ * environment default (`"none"` in development, `"viewport"` in production),
17
+ * mirrored without pulling router-layer code into the client bundle. NODE_ENV
18
+ * is folded by the app build.
19
+ */
20
+ export declare const ENVIRONMENT_DEFAULT_PREFETCH: PrefetchStrategy;
21
+ /**
22
+ * Resolve adaptive to the strategy for the current input capability. Called
23
+ * when a prefetch is armed or triggered, never during render.
24
24
  */
25
- export declare function setDefaultPrefetchStrategy(strategy: PrefetchStrategy): void;
26
- /** Current default strategy for Links and delegated plain anchors. */
27
- export declare function getDefaultPrefetchStrategy(): PrefetchStrategy;
28
- /** Resolve adaptive to the strategy for the current input capability. */
29
25
  export declare function resolveAdaptiveStrategy(strategy: PrefetchStrategy): PrefetchStrategy;
30
26
  /** Subscribe to changes in the input capability used by adaptive prefetch. */
31
27
  export declare function subscribeToAdaptiveStrategyChange(listener: () => void): () => void;
@@ -7,7 +7,9 @@
7
7
  * cache keys responses by (URL, X-Rango-State value).
8
8
  *
9
9
  * Value format: `{buildVersion}:{invalidationTimestamp}`
10
- * - Build version changes on deploy, busting all cached prefetches at boot.
10
+ * - Build version: the router's document version. It changes when a deploy
11
+ * changes the router's server code or the client assets, busting all cached
12
+ * prefetches at boot; a deploy that changes neither keeps them.
11
13
  * - Timestamp rotates on invalidation (server action, invalidateClientCache).
12
14
  *
13
15
  * Storage is a session cookie named by the server-resolved name passed to
@@ -63,6 +63,19 @@ export interface NavigationProviderProps {
63
63
  * it to seed a nonce so components calling useNonce() can be exercised.
64
64
  */
65
65
  nonce?: string;
66
+ /**
67
+ * The document this provider hydrates (initBrowserApp; renderRoute with
68
+ * `hydrate: true`), whose store EventController.lockHydration locked.
69
+ * `settled` resolves once the stream has ended and React has revealed every
70
+ * boundary. Until then location state is `undefined`, as SSR rendered it;
71
+ * then one transition gives the entry's state and changes
72
+ * HydrationBarrierContext, and the store is released after that commit. A
73
+ * navigation committed earlier releases the store before its update.
74
+ * Absent for a provider mounted on the client.
75
+ */
76
+ hydration?: {
77
+ settled: Promise<void>;
78
+ };
66
79
  }
67
80
  /**
68
81
  * Navigation provider component
@@ -85,4 +98,4 @@ export interface NavigationProviderProps {
85
98
  * />
86
99
  * ```
87
100
  */
88
- export declare function NavigationProvider({ store, eventController, initialPayload, bridge, themeConfig, initialTheme, warmupEnabled, version, basename, appShellRef, nonce, }: NavigationProviderProps): ReactNode;
101
+ export declare function NavigationProvider({ store, eventController, initialPayload, bridge, themeConfig, initialTheme, warmupEnabled, version, basename, appShellRef, nonce, hydration, }: NavigationProviderProps): ReactNode;
@@ -2,6 +2,7 @@ import { type Context } from "react";
2
2
  import type { NavigationStore, NavigateOptionsInternal } from "../types.js";
3
3
  import type { EventController } from "../event-controller.js";
4
4
  import type { PrefetchStrategy } from "../../router/prefetch-default.js";
5
+ import type { LocationStateSnapshot } from "./location-state-shared.js";
5
6
  /**
6
7
  * Navigation context value provided by NavigationProvider
7
8
  *
@@ -47,6 +48,12 @@ export interface NavigationStoreContextValue {
47
48
  basename: string | undefined;
48
49
  /** Router default from this instance's initial payload. */
49
50
  defaultPrefetch?: PrefetchStrategy;
51
+ /**
52
+ * The document's origin, fixed for its lifetime. Link compares absolute
53
+ * hrefs against it (data-external) and useLinkStatus resolves link targets
54
+ * with it.
55
+ */
56
+ origin: string | undefined;
50
57
  }
51
58
  /**
52
59
  * React context for navigation store
@@ -55,3 +62,21 @@ export interface NavigationStoreContextValue {
55
62
  * Use useNavigation hook for reactive state access.
56
63
  */
57
64
  export declare const NavigationStoreContext: Context<NavigationStoreContextValue | null>;
65
+ /**
66
+ * The location state of the history entry whose tree is on screen, for
67
+ * useLocationState. NavigationProvider holds it as React state next to the
68
+ * payload and sets both in one update, so a render sees an entry's state
69
+ * exactly when it sees that entry's tree: a transition React holds renders
70
+ * the destination's value, an urgent render of the content still on screen
71
+ * (a reader mounting there included) the value of the entry being left
72
+ * (#1029). Undefined on the server and outside a provider.
73
+ */
74
+ export declare const LocationStateContext: Context<LocationStateSnapshot>;
75
+ /**
76
+ * Read by no component. NavigationProvider changes its value in a transition so
77
+ * that React hydrates every boundary still dehydrated beneath it before that
78
+ * commit: React hydrates a dehydrated boundary first when a provider above it
79
+ * changes, and nothing re-renders for a value nobody reads. See
80
+ * NavigationProviderProps.hydration.
81
+ */
82
+ export declare const HydrationBarrierContext: Context<number>;
@@ -9,12 +9,82 @@ export interface LocationStateEntry {
9
9
  readonly __rsc_ls_value: unknown;
10
10
  readonly __rsc_ls_lazy?: boolean;
11
11
  }
12
+ /** Prefix of every typed location-state slot in `history.state`. */
13
+ export declare const LOCATION_STATE_KEY_PREFIX: string;
14
+ export declare function isLocationStateKey(key: string): boolean;
15
+ /**
16
+ * `clearOnReload` is part of a slot's KEY (`<key>~r`); the value is always
17
+ * stored raw. Slots outlive deploys, so nothing that reads one may depend on a
18
+ * stored format: a definition without the option reads the plain key and never
19
+ * sees such a slot.
20
+ *
21
+ * An injected key ends in `#<ExportName>` (expose-id-utils.ts makeStubId; only
22
+ * identifier exports are keyed) and "~" cannot occur in an identifier, so no
23
+ * file or export name produces a suffix. withLocationStateKey rejects it.
24
+ */
25
+ export declare const LOCATION_STATE_KEY_SUFFIX_SEPARATOR: string;
26
+ export declare const CLEAR_ON_RELOAD_KEY_SUFFIX: string;
27
+ /**
28
+ * @internal The version the document loaded under (rsc-router.tsx
29
+ * initBrowserApp). Deliberately not getAppVersion(): a dev HMR bump moves that
30
+ * one inside a running session (bridge.updateVersion), and the state that
31
+ * session wrote must stay readable until the next document load.
32
+ */
33
+ export declare function setLocationStateVersion(version: string | undefined): void;
34
+ /**
35
+ * The state of a `{ state }` snapshot when its location state may be read:
36
+ * an object recorded under the client's version. Without a snapshot, the
37
+ * current entry (`window.history` is a `{ state }`), and nothing on the
38
+ * server.
39
+ */
40
+ export declare function readableLocationState(location?: {
41
+ readonly state: unknown;
42
+ } | undefined): Record<string, unknown> | undefined;
43
+ /**
44
+ * One history entry's location state as useLocationState readers receive it:
45
+ * its typed slots and plain `state`, or undefined when it holds none.
46
+ */
47
+ export type LocationStateSnapshot = Readonly<Record<string, unknown>> | undefined;
48
+ /**
49
+ * The snapshot of `entryState`: the state object a commit pushes, restores or
50
+ * merges into its history entry. Only state recorded under the client's
51
+ * version is in it (readableLocationState).
52
+ *
53
+ * The snapshot is a React context value, so identity decides who re-renders.
54
+ * It is `previous` itself when every slot holds the value `previous` holds:
55
+ * an entry without state after another, a primitive carried over, or the
56
+ * object a reader got from `previous` passed back by the navigation. Any
57
+ * other value is new, equal content included: a link clicked twice announces
58
+ * its state twice (a flash message, a scroll target). A new value is a
59
+ * structured clone, as history.state holds it, so a reader never shares an
60
+ * object with the caller of the navigation.
61
+ */
62
+ export declare function locationStateSnapshot(entryState: unknown, previous?: LocationStateSnapshot): LocationStateSnapshot;
63
+ /**
64
+ * Record the client's version on a state object that carries location state
65
+ * and no record yet. A client without a version (a renderRoute tree) writes
66
+ * none.
67
+ */
68
+ export declare function stampLocationState(state: Record<string, unknown>): void;
69
+ /**
70
+ * `entryState` plus `additions`, recorded under the client's version. The
71
+ * record is per entry, so location state another version left there is dropped
72
+ * first, with its record: under the new one it would be readable again. Router
73
+ * bookkeeping (idx, scroll key, intercept) is kept.
74
+ */
75
+ export declare function addLocationState(entryState: unknown, additions?: Record<string, unknown>): Record<string, unknown>;
12
76
  /**
13
77
  * Options for createLocationState
14
78
  */
15
79
  export interface LocationStateOptions {
16
80
  /** When true, the state is cleared from history after first read (flash message pattern) */
17
81
  flash?: boolean;
82
+ /**
83
+ * When true, the state does not survive a document load of its entry (a
84
+ * refresh, a back/forward that loads the document): the server rendered
85
+ * without it. Not together with `flash`.
86
+ */
87
+ clearOnReload?: boolean;
18
88
  }
19
89
  type LocationStateUnsafeFn = (...args: never[]) => unknown;
20
90
  type LocationStateUnsafeCtor = abstract new (...args: never[]) => unknown;
@@ -116,13 +186,16 @@ export interface LocationStateDefinition<TArgs extends unknown[], TState> {
116
186
  (...args: TArgs): LocationStateEntry;
117
187
  /**
118
188
  * Injected by Vite plugin - do not set manually. Unit tests without the
119
- * plugin use withLocationStateKey() from @rangojs/router/testing.
189
+ * plugin use withLocationStateKey() from @rangojs/router/testing. Reads back
190
+ * as the slot's key in `history.state`: the injected key plus the
191
+ * `clearOnReload` suffix.
120
192
  */
121
193
  __rsc_ls_key: string;
122
194
  /** Whether this state auto-clears after first read */
123
195
  readonly __rsc_ls_flash: boolean;
124
196
  /**
125
- * Read the current value from history.state.
197
+ * Read the current value from history.state. State the entry holds from
198
+ * another version of the app (an older build) reads as undefined.
126
199
  *
127
200
  * Returns undefined during SSR (no `window`). To stay hydration-safe, do
128
201
  * NOT call read() inline during the initial render — the server returns
@@ -145,13 +218,14 @@ export interface LocationStateDefinition<TArgs extends unknown[], TState> {
145
218
  /**
146
219
  * Statically write the value into the current history entry under this
147
220
  * definition's key, preserving any other keys already on history.state
148
- * (e.g. router bookkeeping, other LocationState slots).
221
+ * (e.g. router bookkeeping, other LocationState slots). Location state
222
+ * another version of the app left on the entry is dropped.
149
223
  *
150
- * This is the non-reactive counterpart to read(): it does not dispatch any
151
- * event, so components reading via useLocationState() will NOT re-render
152
- * until the next navigation/popstate. Use it when you only need the value
153
- * to be there on the next read() or on the next mount (including after
154
- * back/forward and hard refresh of the same entry).
224
+ * This is the non-reactive counterpart to read(): it changes the history
225
+ * entry and nothing a useLocationState() reader shows, whether the reader
226
+ * is mounted now or mounts later. read() returns the value at once; a
227
+ * reader gets it when the entry is next restored: back/forward to it, or
228
+ * (unless the definition sets `clearOnReload`) a hard refresh of it.
155
229
  *
156
230
  * Client-only: throws when called on the server (no history available).
157
231
  */
@@ -161,8 +235,8 @@ export interface LocationStateDefinition<TArgs extends unknown[], TState> {
161
235
  * leaving any other keys on history.state untouched. Idempotent: removing
162
236
  * a slot that isn't present is a no-op.
163
237
  *
164
- * Same non-reactive semantics as write(): no event is dispatched, so
165
- * useLocationState() readers will NOT re-render until the next navigation.
238
+ * Same non-reactive semantics as write(): useLocationState() readers keep
239
+ * the value until the entry is next restored.
166
240
  *
167
241
  * Client-only: throws when called on the server (no history available).
168
242
  */
@@ -1,10 +1,15 @@
1
1
  import { type LocationStateDefinition } from "./location-state-shared.js";
2
2
  export { createLocationState, isLocationStateEntry, resolveLocationStateEntries, type LocationStateEntry, type LocationStateDefinition, type LocationStateOptions, } from "./location-state-shared.js";
3
3
  /**
4
- * Hook to read location state from history.state
4
+ * Hook to read the location state of the history entry on screen
5
+ *
6
+ * A reader sees an entry's state together with that entry's tree: on a
7
+ * navigation the value changes in the React commit that brings the
8
+ * destination, so content a pending navigation keeps on screen keeps the
9
+ * state of the entry being left, for a reader that mounts there too (#1029).
5
10
  *
6
11
  * Behavior depends on the definition:
7
- * - Normal state: persists across navigations, reactive to popstate
12
+ * - Normal state: persists across navigations and back/forward
8
13
  * - Flash state (created with { flash: true }): read once, cleared after paint
9
14
  *
10
15
  * Overloaded:
@@ -95,6 +95,12 @@ export interface BrowserAppContext {
95
95
  * prefetch TTL are document-lifetime too (see AppShell).
96
96
  */
97
97
  appShellRef?: import("./app-shell.js").AppShellRef;
98
+ /**
99
+ * Resolves when the document's stream has ended and every Suspense boundary
100
+ * in it has been revealed. NavigationProvider closes the hydration window
101
+ * then (NavigationProviderProps.hydration).
102
+ */
103
+ documentRevealed: Promise<void>;
98
104
  }
99
105
  /**
100
106
  * Initialize the browser app. Must be called before rendering Rango.
@@ -131,13 +137,18 @@ export interface RangoProps {
131
137
  * import * as rscBrowser from "@vitejs/plugin-rsc/browser";
132
138
  *
133
139
  * async function main() {
134
- * await initBrowserApp({ rscStream, deps: rscBrowser });
140
+ * const { initialPayload } = await initBrowserApp({ rscStream, deps: rscBrowser });
141
+ * // Rejects when the action's state is not Flight-serializable.
142
+ * const formState = await Promise.resolve(initialPayload.formState).catch(
143
+ * () => undefined,
144
+ * );
135
145
  *
136
146
  * hydrateRoot(
137
147
  * document,
138
148
  * <React.StrictMode>
139
149
  * <Rango />
140
- * </React.StrictMode>
150
+ * </React.StrictMode>,
151
+ * formState ? { formState } : undefined
141
152
  * );
142
153
  * }
143
154
  * main();
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode, ComponentType } from "react";
2
+ import type { ReactFormState } from "react-dom/client";
2
3
  import type { ResolvedSegment, SlotState } from "../types.js";
3
4
  import type { ResolvedThemeConfig, Theme } from "../theme/types.js";
4
5
  import type { RenderSegmentsOptions } from "../segment-system.js";
@@ -9,6 +10,11 @@ import type { RenderSegmentsOptions } from "../segment-system.js";
9
10
  export interface RscPayload<TMetadata = RscMetadata> {
10
11
  metadata?: TMetadata;
11
12
  returnValue?: ActionResult;
13
+ /**
14
+ * Form state of a PE POST document, for hydrateRoot's `formState` option.
15
+ * Rejects when the action's state is not Flight-serializable.
16
+ */
17
+ formState?: Promise<ReactFormState>;
12
18
  }
13
19
  /**
14
20
  * Handle data structure: handleName -> segmentId -> entries[]
@@ -406,6 +412,8 @@ export interface NavigateOptionsInternal extends Omit<NavigateOptions, "state">
406
412
  state?: unknown;
407
413
  /** Skip segment cache (used by redirect-with-state to force re-render) */
408
414
  _skipCache?: boolean;
415
+ /** Server redirects already followed by this navigation chain (0 for a user navigation) */
416
+ _redirectHops?: number;
409
417
  }
410
418
  /**
411
419
  * Options for useRouter push/replace methods.
@@ -476,6 +484,8 @@ export type StateListener = () => void;
476
484
  * EventController owns the public navigation lifecycle exposed by hooks.
477
485
  */
478
486
  export interface NavigationStore {
487
+ /** Client loader data for useLoader / useFetchLoader (loader-store.ts). */
488
+ readonly loaders: import("../loader-store.js").LoaderStore;
479
489
  getSegmentState(): SegmentState;
480
490
  setPath(path: string): void;
481
491
  setCurrentUrl(url: string): void;
@@ -37,6 +37,8 @@ export interface GeneratedManifest {
37
37
  prerenderRoutes?: string[];
38
38
  /** Route names wrapped with Passthrough() (live handler for runtime fallback) */
39
39
  passthroughRoutes?: string[];
40
+ /** Route names opted into on-demand prerender (Prerender(..., { onDemand })) */
41
+ onDemandRoutes?: string[];
40
42
  /** Route name → response type for non-RSC routes */
41
43
  responseTypeRoutes?: Record<string, string>;
42
44
  /** Route name -> search schema descriptor for typed URL helpers */