@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
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import type { ReactNode } from "react";
3
- import { Component, Suspense, use } from "react";
4
- import { OutletProvider } from "./outlet-provider.js";
2
+ import type { ComponentProps, ReactElement, ReactNode } from "react";
3
+ import { Component, Suspense, use, useMemo } from "react";
4
+ import { AuditedOutletProvider, OutletProvider } from "./outlet-provider.js";
5
5
  import type { ResolvedSegment } from "./types.js";
6
6
  import {
7
7
  decodeLoaderResults,
@@ -10,6 +10,12 @@ import {
10
10
  LOADER_REDIRECT,
11
11
  } from "./decode-loader-results.js";
12
12
  import { LoaderRedirect } from "./loader-redirect.js";
13
+ import type { BoundaryAudit } from "./suspense-audit.js";
14
+ import {
15
+ AuditedFallback,
16
+ useBoundaryAudit,
17
+ useRevealAudit,
18
+ } from "./suspense-audit-react.js";
13
19
 
14
20
  /**
15
21
  * Router-owned error boundary for read-site loader errors. segment-system
@@ -97,8 +103,8 @@ export function RouteContentWrapper({
97
103
  fallback,
98
104
  segmentId,
99
105
  }: {
100
- // Normally a pending promise (use() suspends -> fallback). forceAwait paths
101
- // pass an already-resolved node so Suspender renders it without suspending.
106
+ // A pending promise suspends (use()) and shows the fallback; a node renders
107
+ // without suspending (see getBoundaryContent).
102
108
  content: Promise<ReactNode> | ReactNode;
103
109
  fallback?: ReactNode;
104
110
  segmentId?: string;
@@ -113,19 +119,62 @@ export function RouteContentWrapper({
113
119
  );
114
120
  }
115
121
 
122
+ // Dev only (suspense-audit.ts): RouteContentWrapper's Suspense, keys and
123
+ // content, with the audit's hooks in components of their own.
124
+ //
125
+ // Chosen where the element is created, inside a NODE_ENV test, so a build
126
+ // folds to the product component and nothing else. Two other ways leave
127
+ // bytes in cloudflare-basic's router chunk, both measured: a dev branch
128
+ // inside the product component (React Compiler runs before NODE_ENV is
129
+ // folded and keeps the branch's memo slots, +76 B gzip), and one
130
+ // `export const X = dev ? Audited : Product` per module (the alias statement
131
+ // survives minification, +27 B gzip for three).
132
+ //
133
+ // Line comments on purpose, here and on the other dev-only declarations: the
134
+ // server bundles are not minified and keep a JSDoc block even when the
135
+ // declaration under it is removed.
136
+ export function AuditedRouteContent({
137
+ content,
138
+ fallback,
139
+ segmentId,
140
+ }: ComponentProps<typeof RouteContentWrapper>): ReactNode {
141
+ const audit = useBoundaryAudit(
142
+ `content:${segmentId}`,
143
+ segmentId ?? "",
144
+ content,
145
+ );
146
+ return (
147
+ <Suspense
148
+ fallback={
149
+ <AuditedFallback audit={audit}>{fallback ?? null}</AuditedFallback>
150
+ }
151
+ key={segmentId ? "route-content-suspense-" + segmentId : undefined}
152
+ >
153
+ <AuditedSuspender content={content} audit={audit} key={segmentId} />
154
+ </Suspense>
155
+ );
156
+ }
157
+
158
+ function AuditedSuspender({
159
+ content,
160
+ audit,
161
+ }: {
162
+ content: Promise<ReactNode> | ReactNode;
163
+ audit: BoundaryAudit;
164
+ }): ReactNode {
165
+ useRevealAudit(audit);
166
+ return Suspender({ content });
167
+ }
168
+
116
169
  const Suspender = ({
117
170
  content,
118
171
  }: {
119
172
  content: Promise<ReactNode> | ReactNode;
120
173
  }): ReactNode => {
121
- // Normally content is a pending promise -> use() suspends and the wrapping
122
- // Suspense shows the loading() fallback. forceAwait paths (popstate,
123
- // stale-revalidation, fully-prefetched nav) instead pass the ALREADY-RESOLVED
124
- // node so first render does not suspend for a microtask and flash the loading()
125
- // fallback on a NORMAL (non-transition) commit. The wrapper tree
126
- // (RouteContentWrapper > Suspense > Suspender) is identical either way, so this
127
- // preserves tree structure (see docs/tree-structure.md) — only whether use()
128
- // suspends differs, exactly like LoaderResolver's resolved-data branch.
174
+ // A pending promise suspends here and the wrapping Suspense shows the
175
+ // loading() fallback; a node renders without suspending. The wrapper tree
176
+ // (RouteContentWrapper > Suspense > Suspender) is identical either way (see
177
+ // docs/tree-structure.md), like LoaderResolver's resolved-data branch.
129
178
  return content instanceof Promise ? use(content) : content;
130
179
  };
131
180
 
@@ -191,6 +240,51 @@ export function LoaderBoundary({
191
240
  );
192
241
  }
193
242
 
243
+ // Dev only (suspense-audit.ts): LoaderBoundary, as AuditedRouteContent.
244
+ export function AuditedLoaderBoundary({
245
+ fallback,
246
+ children,
247
+ ...resolver
248
+ }: LoaderBoundaryProps): ReactNode {
249
+ const nodes = useMemo(
250
+ () => [children, resolver.outletContent],
251
+ [children, resolver.outletContent],
252
+ );
253
+ const audit = useBoundaryAudit(
254
+ `loaders:${resolver.outletKey}`,
255
+ resolver.segment.id,
256
+ resolver.loaderDataPromise,
257
+ resolver.loaderStreams,
258
+ nodes,
259
+ );
260
+ return (
261
+ <Suspense
262
+ fallback={
263
+ <AuditedFallback audit={audit}>{fallback ?? null}</AuditedFallback>
264
+ }
265
+ key={`loader-boundary-${resolver.outletKey}`}
266
+ >
267
+ <AuditedLoaderResolver audit={audit} {...resolver}>
268
+ {children}
269
+ </AuditedLoaderResolver>
270
+ </Suspense>
271
+ );
272
+ }
273
+
274
+ function AuditedLoaderResolver({
275
+ audit,
276
+ ...props
277
+ }: Omit<LoaderBoundaryProps, "fallback"> & {
278
+ audit: BoundaryAudit;
279
+ }): ReactNode {
280
+ useRevealAudit(audit);
281
+ // The resolver's OutletProvider, as its audited component.
282
+ const outlet = LoaderResolver(props) as ReactElement<
283
+ ComponentProps<typeof OutletProvider>
284
+ >;
285
+ return <AuditedOutletProvider {...outlet.props} key={outlet.key} />;
286
+ }
287
+
194
288
  /**
195
289
  * Internal component that resolves loader promises and renders OutletProvider
196
290
  *
@@ -271,6 +271,17 @@ export function createErrorInfo(
271
271
  };
272
272
  }
273
273
 
274
+ /** Invoke an errorBoundary() fallback that may be a handler or a plain node. */
275
+ export function renderErrorFallback(
276
+ fallback: ReactNode | ErrorBoundaryHandler,
277
+ errorInfo: ErrorInfo,
278
+ ): ReactNode {
279
+ if (typeof fallback === "function") {
280
+ return fallback({ error: errorInfo } satisfies ErrorBoundaryFallbackProps);
281
+ }
282
+ return fallback;
283
+ }
284
+
274
285
  /**
275
286
  * Create an error segment with the fallback component
276
287
  * Renders the fallback with error info and reset function
@@ -281,23 +292,12 @@ export function createErrorSegment(
281
292
  entry: EntryData,
282
293
  params: Record<string, string>,
283
294
  ): ResolvedSegment {
284
- let component: ReactNode;
285
-
286
- if (typeof fallback === "function") {
287
- const props: ErrorBoundaryFallbackProps = {
288
- error: errorInfo,
289
- };
290
- component = fallback(props);
291
- } else {
292
- component = fallback;
293
- }
294
-
295
295
  return {
296
296
  id: entry.shortCode,
297
297
  namespace: entry.id,
298
298
  type: "error",
299
299
  index: 0,
300
- component,
300
+ component: renderErrorFallback(fallback, errorInfo),
301
301
  params,
302
302
  error: errorInfo,
303
303
  };
@@ -159,6 +159,7 @@ export function createFindMatch<TEnv = any>(
159
159
  redirectTo: trieResult.redirectTo,
160
160
  ...(trieResult.pr ? { pr: true } : {}),
161
161
  ...(trieResult.pt ? { pt: true } : {}),
162
+ ...(trieResult.od ? { od: true } : {}),
162
163
  ...(trieResult.responseType
163
164
  ? { responseType: trieResult.responseType }
164
165
  : {}),
@@ -383,6 +383,7 @@ export function createPrerenderContext<TEnv>(
383
383
  isPassthroughRoute?: boolean,
384
384
  buildEnv?: TEnv,
385
385
  devMode?: boolean,
386
+ onDemand?: boolean,
386
387
  ): InternalHandlerContext<any, TEnv> {
387
388
  const syntheticUrl = new URL(`http://prerender${pathname}`);
388
389
  const variables = buildVars ?? {};
@@ -401,6 +402,7 @@ export function createPrerenderContext<TEnv>(
401
402
  // gate. dynamic() only reaches the shell axis on a live request or capture.
402
403
  dynamic: () => {},
403
404
  dev: devMode ?? false,
405
+ onDemand: onDemand ?? false,
404
406
  get request(): Request {
405
407
  return throwUnavailable("request");
406
408
  },
@@ -27,6 +27,7 @@ import {
27
27
  buildLoaderErrorContext,
28
28
  } from "./segment-resolution.js";
29
29
  import { catchSegmentError } from "./segment-resolution/helpers.js";
30
+ import { trackStreamedHandler } from "./segment-resolution/streamed-handler-boundary.js";
30
31
  import { findInOrphans } from "./error-handling.js";
31
32
  import { resolveLoaderData } from "./segment-resolution/loader-cache.js";
32
33
  import type { SegmentResolutionDeps } from "./types.js";
@@ -390,14 +391,20 @@ export async function resolveInterceptEntry<TEnv>(
390
391
 
391
392
  let component: ReactNode;
392
393
  let loaderDataPromise: Promise<any[]> | any[] | undefined;
393
- // A streamed (loading()) handler resolves after the 200 has started, so its
394
- // rejection stays with the client; track it like route handlers do
395
- // (onError report, handle-store completion).
396
- const trackStreamedHandler = (promise: Promise<unknown>): ReactNode =>
397
- deps.trackHandler(promise, {
394
+ // A streamed (loading()) handler resolves after the 200 has started: tracked
395
+ // like route handlers (onError report, handle-store completion) and
396
+ // recovered into the declared boundary, except on the skipMiddleware
397
+ // background re-render, which must reject so a failure is never cached.
398
+ const streamedComponent = (promise: Promise<unknown>): ReactNode =>
399
+ trackStreamedHandler(deps, promise, {
400
+ boundaryEntry: parentEntry,
398
401
  segmentId: `${parentEntry.shortCode}.${interceptEntry.slotName}`,
399
402
  segmentType: "parallel",
400
- }) as ReactNode;
403
+ context,
404
+ routeKey: interceptEntry.routeName,
405
+ params,
406
+ recover: !options?.skipMiddleware,
407
+ });
401
408
 
402
409
  if (interceptEntry.loading && loaderPromises.length > 0) {
403
410
  if (handlerResult instanceof Promise) {
@@ -408,11 +415,11 @@ export async function resolveInterceptEntry<TEnv>(
408
415
  }
409
416
  component =
410
417
  handlerResult instanceof Promise
411
- ? trackStreamedHandler(handlerResult)
418
+ ? streamedComponent(handlerResult)
412
419
  : (Promise.resolve(handlerResult) as ReactNode);
413
420
  loaderDataPromise = Promise.all(loaderPromises);
414
421
  } else if (interceptEntry.loading && handlerResult instanceof Promise) {
415
- component = trackStreamedHandler(handlerResult);
422
+ component = streamedComponent(handlerResult);
416
423
  } else {
417
424
  if (loaderPromises.length > 0) {
418
425
  loaderDataPromise = await Promise.all(loaderPromises);
@@ -29,7 +29,6 @@ import type {
29
29
  LoaderContext,
30
30
  LoaderDataResult,
31
31
  ErrorBoundaryHandler,
32
- ErrorBoundaryFallbackProps,
33
32
  ErrorInfo,
34
33
  NotFoundBoundaryHandler,
35
34
  NotFoundBoundaryFallbackProps,
@@ -44,6 +43,7 @@ import {
44
43
  } from "../redirect-origin.js";
45
44
  import {
46
45
  createNotFoundInfo,
46
+ renderErrorFallback,
47
47
  renderNotFoundFallback,
48
48
  resolveNotFoundFallback,
49
49
  } from "./error-handling.js";
@@ -302,15 +302,7 @@ export function wrapLoaderWithErrorHandling<T>(
302
302
  // error, and the wrapped promise still resolves to a LoaderDataResult.
303
303
  let renderedFallback: ReactNode;
304
304
  try {
305
- if (typeof fallback === "function") {
306
- // ErrorBoundaryHandler - call with error info
307
- const props: ErrorBoundaryFallbackProps = {
308
- error: errorInfo,
309
- };
310
- renderedFallback = fallback(props);
311
- } else {
312
- renderedFallback = fallback;
313
- }
305
+ renderedFallback = renderErrorFallback(fallback, errorInfo);
314
306
  } catch (fallbackError) {
315
307
  debugLog("loader", "error boundary fallback render threw", {
316
308
  segmentId,
@@ -38,6 +38,8 @@ const MODULE_LOAD_FAILURE = Symbol.for("rango.moduleLoadFailure");
38
38
  // LP1 in docs/internal/matching-and-lazy-discovery.md. VERSION comes from the
39
39
  // @rangojs/router:version virtual module which Vite invalidates on RSC module HMR.
40
40
  // When VERSION changes, this module re-evaluates and the cache is recreated empty.
41
+ // Dev module generation only: in production VERSION is constant per process, so
42
+ // the per-router cache versions play no part in this cache.
41
43
  const manifestModuleCache = new Map<string, Map<string, EntryData>>();
42
44
 
43
45
  /**
@@ -171,6 +171,8 @@ export async function rerenderAndCacheRoute<TEnv>(
171
171
  {
172
172
  _handleStore: handleStore,
173
173
  _metricsStore: undefined,
174
+ _renderErrors: [],
175
+ _recoveredHandlerErrors: undefined,
174
176
  _onResponseCallbacks: [],
175
177
  header: sink.header,
176
178
  setCookie: sink.setCookie,