@rangojs/router 0.0.0-experimental.1878aa49 → 0.0.0-experimental.190fb30d

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 (443) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +303 -741
  3. package/dist/bin/rango.js +605 -146
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +4117 -1211
  6. package/dist/vite/index.js.bak +5448 -0
  7. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  8. package/package.json +86 -15
  9. package/skills/api-client/SKILL.md +211 -0
  10. package/skills/breadcrumbs/SKILL.md +85 -6
  11. package/skills/bundle-analysis/SKILL.md +159 -0
  12. package/skills/cache-guide/SKILL.md +228 -33
  13. package/skills/caching/SKILL.md +336 -19
  14. package/skills/catalog.json +271 -0
  15. package/skills/comparison/SKILL.md +50 -0
  16. package/skills/comparison/agents/openai.yaml +4 -0
  17. package/skills/comparison/references/framework-comparison.md +837 -0
  18. package/skills/composability/SKILL.md +110 -4
  19. package/skills/css/SKILL.md +76 -0
  20. package/skills/debug-manifest/SKILL.md +5 -3
  21. package/skills/defer-hydration/SKILL.md +235 -0
  22. package/skills/document-cache/SKILL.md +87 -56
  23. package/skills/fonts/SKILL.md +1 -1
  24. package/skills/handler-use/SKILL.md +364 -0
  25. package/skills/hooks/SKILL.md +73 -691
  26. package/skills/hooks/data.md +273 -0
  27. package/skills/hooks/handle-and-actions.md +103 -0
  28. package/skills/hooks/navigation.md +110 -0
  29. package/skills/hooks/outlets.md +41 -0
  30. package/skills/hooks/state.md +228 -0
  31. package/skills/hooks/urls.md +135 -0
  32. package/skills/host-router/SKILL.md +129 -27
  33. package/skills/i18n/SKILL.md +276 -0
  34. package/skills/intercept/SKILL.md +94 -18
  35. package/skills/layout/SKILL.md +62 -19
  36. package/skills/links/SKILL.md +247 -17
  37. package/skills/loader/SKILL.md +248 -10
  38. package/skills/middleware/SKILL.md +57 -16
  39. package/skills/migrate-nextjs/SKILL.md +745 -0
  40. package/skills/migrate-react-router/SKILL.md +153 -0
  41. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  42. package/skills/migrate-react-router/component-migration.md +196 -0
  43. package/skills/migrate-react-router/data-and-actions.md +225 -0
  44. package/skills/migrate-react-router/route-mapping.md +271 -0
  45. package/skills/mime-routes/SKILL.md +29 -2
  46. package/skills/observability/SKILL.md +202 -0
  47. package/skills/parallel/SKILL.md +99 -10
  48. package/skills/ppr/SKILL.md +618 -0
  49. package/skills/prerender/SKILL.md +178 -124
  50. package/skills/rango/SKILL.md +318 -24
  51. package/skills/react-compiler/SKILL.md +168 -0
  52. package/skills/response-routes/SKILL.md +138 -49
  53. package/skills/route/SKILL.md +141 -9
  54. package/skills/router-setup/SKILL.md +44 -9
  55. package/skills/scripts/SKILL.md +179 -0
  56. package/skills/server-actions/SKILL.md +776 -0
  57. package/skills/shell-manifest/SKILL.md +185 -0
  58. package/skills/streams-and-websockets/SKILL.md +283 -0
  59. package/skills/tailwind/SKILL.md +28 -4
  60. package/skills/testing/SKILL.md +130 -0
  61. package/skills/testing/bindings.md +103 -0
  62. package/skills/testing/cache-prerender.md +127 -0
  63. package/skills/testing/client-components.md +124 -0
  64. package/skills/testing/e2e-parity.md +125 -0
  65. package/skills/testing/flight.md +91 -0
  66. package/skills/testing/handles.md +131 -0
  67. package/skills/testing/loader.md +128 -0
  68. package/skills/testing/middleware.md +99 -0
  69. package/skills/testing/render-handler.md +122 -0
  70. package/skills/testing/response-routes.md +95 -0
  71. package/skills/testing/reverse-and-types.md +85 -0
  72. package/skills/testing/server-actions.md +107 -0
  73. package/skills/testing/server-tree.md +128 -0
  74. package/skills/testing/setup.md +123 -0
  75. package/skills/theme/SKILL.md +1 -1
  76. package/skills/typesafety/SKILL.md +45 -626
  77. package/skills/typesafety/env-and-bindings.md +254 -0
  78. package/skills/typesafety/generated-files-and-cli.md +335 -0
  79. package/skills/typesafety/params-and-search.md +153 -0
  80. package/skills/typesafety/route-types.md +209 -0
  81. package/skills/use-cache/SKILL.md +74 -15
  82. package/skills/vercel/SKILL.md +128 -0
  83. package/skills/view-transitions/SKILL.md +337 -0
  84. package/src/__augment-tests__/augment.ts +81 -0
  85. package/src/__augment-tests__/augmented.check.ts +116 -0
  86. package/src/__internal.ts +1 -66
  87. package/src/browser/action-coordinator.ts +53 -36
  88. package/src/browser/action-fence.ts +47 -0
  89. package/src/browser/app-shell.ts +39 -0
  90. package/src/browser/connection-warmup.ts +134 -0
  91. package/src/browser/cookie-name.ts +140 -0
  92. package/src/browser/event-controller.ts +252 -158
  93. package/src/browser/history-state.ts +21 -0
  94. package/src/browser/index.ts +3 -3
  95. package/src/browser/invalidate-client-cache.ts +52 -0
  96. package/src/browser/logging.ts +28 -0
  97. package/src/browser/merge-segment-loaders.ts +6 -4
  98. package/src/browser/navigation-bridge.ts +115 -27
  99. package/src/browser/navigation-client.ts +163 -70
  100. package/src/browser/navigation-store-handle.ts +38 -0
  101. package/src/browser/navigation-store.ts +161 -73
  102. package/src/browser/navigation-transaction.ts +9 -59
  103. package/src/browser/network-error-handler.ts +34 -7
  104. package/src/browser/partial-update.ts +186 -135
  105. package/src/browser/prefetch/cache.ts +246 -71
  106. package/src/browser/prefetch/fetch.ts +350 -38
  107. package/src/browser/prefetch/queue.ts +61 -12
  108. package/src/browser/rango-state.ts +158 -76
  109. package/src/browser/react/Link.tsx +70 -9
  110. package/src/browser/react/NavigationProvider.tsx +202 -120
  111. package/src/browser/react/ScrollRestoration.tsx +10 -6
  112. package/src/browser/react/filter-segment-order.ts +66 -7
  113. package/src/browser/react/index.ts +0 -48
  114. package/src/browser/react/location-state-shared.ts +178 -8
  115. package/src/browser/react/location-state.ts +39 -14
  116. package/src/browser/react/use-action.ts +6 -15
  117. package/src/browser/react/use-handle.ts +23 -69
  118. package/src/browser/react/use-href.tsx +8 -1
  119. package/src/browser/react/use-link-status.ts +33 -8
  120. package/src/browser/react/use-navigation.ts +32 -7
  121. package/src/browser/react/use-params.ts +20 -10
  122. package/src/browser/react/use-reverse.ts +106 -0
  123. package/src/browser/react/use-router.ts +25 -3
  124. package/src/browser/react/use-search-params.ts +0 -5
  125. package/src/browser/react/use-segments.ts +11 -21
  126. package/src/browser/response-adapter.ts +99 -8
  127. package/src/browser/rsc-router.tsx +145 -28
  128. package/src/browser/scroll-restoration.ts +44 -27
  129. package/src/browser/segment-reconciler.ts +44 -12
  130. package/src/browser/segment-structure-assert.ts +2 -2
  131. package/src/browser/server-action-bridge.ts +236 -65
  132. package/src/browser/types.ts +102 -9
  133. package/src/browser/validate-redirect-origin.ts +43 -16
  134. package/src/build/collect-fallback-refs.ts +107 -0
  135. package/src/build/generate-manifest.ts +205 -159
  136. package/src/build/generate-route-types.ts +3 -1
  137. package/src/build/index.ts +11 -3
  138. package/src/build/prefix-tree-utils.ts +123 -0
  139. package/src/build/route-trie.ts +198 -41
  140. package/src/build/route-types/ast-route-extraction.ts +15 -8
  141. package/src/build/route-types/codegen.ts +16 -5
  142. package/src/build/route-types/include-resolution.ts +456 -62
  143. package/src/build/route-types/param-extraction.ts +6 -3
  144. package/src/build/route-types/per-module-writer.ts +22 -6
  145. package/src/build/route-types/router-processing.ts +128 -51
  146. package/src/build/route-types/scan-filter.ts +9 -2
  147. package/src/build/route-types/source-scan.ts +216 -0
  148. package/src/build/runtime-discovery.ts +13 -21
  149. package/src/cache/cache-error.ts +104 -0
  150. package/src/cache/cache-key-utils.ts +58 -13
  151. package/src/cache/cache-policy.ts +108 -34
  152. package/src/cache/cache-runtime.ts +454 -101
  153. package/src/cache/cache-scope.ts +187 -96
  154. package/src/cache/cache-tag.ts +149 -0
  155. package/src/cache/cf/cf-base64.ts +33 -0
  156. package/src/cache/cf/cf-cache-constants.ts +127 -0
  157. package/src/cache/cf/cf-cache-store.ts +2206 -372
  158. package/src/cache/cf/cf-cache-types.ts +349 -0
  159. package/src/cache/cf/cf-kv-utils.ts +46 -0
  160. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  161. package/src/cache/cf/index.ts +6 -16
  162. package/src/cache/document-cache.ts +126 -41
  163. package/src/cache/handle-snapshot.ts +70 -0
  164. package/src/cache/index.ts +23 -20
  165. package/src/cache/memory-segment-store.ts +243 -37
  166. package/src/cache/profile-registry.ts +46 -31
  167. package/src/cache/read-through-swr.ts +56 -12
  168. package/src/cache/segment-codec.ts +13 -21
  169. package/src/cache/shell-snapshot.ts +417 -0
  170. package/src/cache/tag-invalidation.ts +230 -0
  171. package/src/cache/types.ts +194 -99
  172. package/src/cache/vercel/index.ts +11 -0
  173. package/src/cache/vercel/vercel-cache-store.ts +1132 -0
  174. package/src/client.rsc.tsx +41 -21
  175. package/src/client.tsx +116 -290
  176. package/src/cloudflare/index.ts +11 -0
  177. package/src/cloudflare/tracing.ts +108 -0
  178. package/src/component-utils.ts +19 -0
  179. package/src/components/DefaultDocument.tsx +8 -2
  180. package/src/context-var.ts +18 -6
  181. package/src/decode-loader-results.ts +52 -0
  182. package/src/defer.ts +185 -0
  183. package/src/deps/ssr.ts +0 -1
  184. package/src/encode-kv.ts +49 -0
  185. package/src/errors.ts +30 -4
  186. package/src/escape-script.ts +52 -0
  187. package/src/handle.ts +104 -34
  188. package/src/handles/MetaTags.tsx +24 -53
  189. package/src/handles/Scripts.tsx +183 -0
  190. package/src/handles/breadcrumbs.ts +35 -8
  191. package/src/handles/deferred-resolution.ts +127 -0
  192. package/src/handles/is-thenable.ts +18 -0
  193. package/src/handles/meta.ts +14 -40
  194. package/src/handles/script.ts +244 -0
  195. package/src/host/cookie-handler.ts +9 -60
  196. package/src/host/errors.ts +13 -22
  197. package/src/host/index.ts +9 -2
  198. package/src/host/pattern-matcher.ts +23 -52
  199. package/src/host/router.ts +107 -99
  200. package/src/host/testing.ts +40 -27
  201. package/src/host/types.ts +37 -4
  202. package/src/host/utils.ts +1 -1
  203. package/src/href-client.ts +137 -22
  204. package/src/index.rsc.ts +100 -13
  205. package/src/index.ts +143 -19
  206. package/src/internal-debug.ts +11 -10
  207. package/src/loader-store.ts +500 -0
  208. package/src/loader.rsc.ts +20 -13
  209. package/src/loader.ts +12 -11
  210. package/src/missing-id-error.ts +68 -0
  211. package/src/outlet-context.ts +1 -1
  212. package/src/outlet-provider.tsx +1 -5
  213. package/src/prerender/param-hash.ts +16 -16
  214. package/src/prerender/store.ts +37 -41
  215. package/src/prerender.ts +215 -86
  216. package/src/redirect-origin.ts +114 -0
  217. package/src/regex-escape.ts +8 -0
  218. package/src/render-error-thrower.tsx +20 -0
  219. package/src/response-utils.ts +62 -0
  220. package/src/reverse.ts +65 -15
  221. package/src/root-error-boundary.tsx +1 -19
  222. package/src/route-content-wrapper.tsx +19 -77
  223. package/src/route-definition/dsl-helpers.ts +461 -304
  224. package/src/route-definition/helper-factories.ts +28 -140
  225. package/src/route-definition/helpers-types.ts +147 -72
  226. package/src/route-definition/index.ts +4 -2
  227. package/src/route-definition/redirect.ts +44 -11
  228. package/src/route-definition/resolve-handler-use.ts +160 -0
  229. package/src/route-definition/use-item-types.ts +29 -0
  230. package/src/route-map-builder.ts +41 -20
  231. package/src/route-types.ts +37 -46
  232. package/src/router/basename.ts +14 -0
  233. package/src/router/content-negotiation.ts +164 -17
  234. package/src/router/error-handling.ts +45 -18
  235. package/src/router/find-match.ts +129 -30
  236. package/src/router/handler-context.ts +47 -22
  237. package/src/router/instrument.ts +355 -0
  238. package/src/router/intercept-resolution.ts +39 -20
  239. package/src/router/lazy-includes.ts +85 -62
  240. package/src/router/loader-resolution.ts +277 -54
  241. package/src/router/logging.ts +0 -6
  242. package/src/router/manifest.ts +97 -57
  243. package/src/router/match-api.ts +178 -218
  244. package/src/router/match-context.ts +0 -22
  245. package/src/router/match-handlers.ts +211 -165
  246. package/src/router/match-middleware/background-revalidation.ts +40 -24
  247. package/src/router/match-middleware/cache-lookup.ts +168 -277
  248. package/src/router/match-middleware/cache-store.ts +64 -52
  249. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  250. package/src/router/match-middleware/segment-resolution.ts +45 -14
  251. package/src/router/match-pipelines.ts +1 -42
  252. package/src/router/match-result.ts +113 -45
  253. package/src/router/metrics.ts +0 -34
  254. package/src/router/middleware-types.ts +7 -134
  255. package/src/router/middleware.ts +298 -172
  256. package/src/router/navigation-snapshot.ts +133 -0
  257. package/src/router/params-util.ts +23 -0
  258. package/src/router/parse-pattern.ts +115 -0
  259. package/src/router/pattern-matching.ts +181 -150
  260. package/src/router/prefetch-cache-ttl.ts +51 -0
  261. package/src/router/prefetch-limits.ts +37 -0
  262. package/src/router/prerender-match.ts +201 -56
  263. package/src/router/preview-match.ts +35 -103
  264. package/src/router/request-classification.ts +291 -0
  265. package/src/router/revalidation.ts +123 -73
  266. package/src/router/route-snapshot.ts +256 -0
  267. package/src/router/router-context.ts +6 -29
  268. package/src/router/router-interfaces.ts +125 -35
  269. package/src/router/router-options.ts +166 -5
  270. package/src/router/router-registry.ts +2 -5
  271. package/src/router/segment-resolution/fresh.ts +188 -86
  272. package/src/router/segment-resolution/helpers.ts +86 -6
  273. package/src/router/segment-resolution/loader-cache.ts +155 -39
  274. package/src/router/segment-resolution/loader-mask.ts +67 -0
  275. package/src/router/segment-resolution/loader-snapshot.ts +308 -0
  276. package/src/router/segment-resolution/revalidation.ts +344 -319
  277. package/src/router/segment-resolution/static-store.ts +19 -5
  278. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  279. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  280. package/src/router/segment-resolution.ts +5 -1
  281. package/src/router/segment-wrappers.ts +6 -5
  282. package/src/router/state-cookie-name.ts +33 -0
  283. package/src/router/substitute-pattern-params.ts +75 -0
  284. package/src/router/telemetry-otel.ts +160 -200
  285. package/src/router/telemetry.ts +105 -20
  286. package/src/router/timeout.ts +0 -20
  287. package/src/router/tracing.ts +215 -0
  288. package/src/router/trie-matching.ts +171 -59
  289. package/src/router/types.ts +9 -63
  290. package/src/router/url-params.ts +57 -0
  291. package/src/router.ts +170 -72
  292. package/src/rsc/full-payload.ts +70 -0
  293. package/src/rsc/handler-context.ts +3 -2
  294. package/src/rsc/handler.ts +678 -513
  295. package/src/rsc/helpers.ts +168 -46
  296. package/src/rsc/index.ts +2 -5
  297. package/src/rsc/json-route-result.ts +38 -0
  298. package/src/rsc/loader-fetch.ts +127 -31
  299. package/src/rsc/manifest-init.ts +29 -42
  300. package/src/rsc/nonce.ts +10 -1
  301. package/src/rsc/origin-guard.ts +39 -25
  302. package/src/rsc/progressive-enhancement.ts +134 -15
  303. package/src/rsc/redirect-guard.ts +100 -0
  304. package/src/rsc/response-cache-serve.ts +238 -0
  305. package/src/rsc/response-error.ts +79 -12
  306. package/src/rsc/response-route-handler.ts +99 -189
  307. package/src/rsc/rsc-rendering.ts +497 -77
  308. package/src/rsc/runtime-warnings.ts +23 -10
  309. package/src/rsc/server-action.ts +286 -114
  310. package/src/rsc/shell-capture.ts +1166 -0
  311. package/src/rsc/shell-serve.ts +181 -0
  312. package/src/rsc/ssr-setup.ts +17 -1
  313. package/src/rsc/transition-gate.ts +89 -0
  314. package/src/rsc/types.ts +54 -5
  315. package/src/runtime-env.ts +18 -0
  316. package/src/search-params.ts +35 -30
  317. package/src/segment-content-promise.ts +67 -0
  318. package/src/segment-loader-promise.ts +167 -0
  319. package/src/segment-system.tsx +355 -204
  320. package/src/serialize.ts +243 -0
  321. package/src/server/context.ts +247 -54
  322. package/src/server/cookie-parse.ts +32 -0
  323. package/src/server/cookie-store.ts +152 -5
  324. package/src/server/handle-store.ts +40 -38
  325. package/src/server/loader-registry.ts +33 -42
  326. package/src/server/request-context.ts +502 -161
  327. package/src/ssr/index.tsx +467 -178
  328. package/src/ssr/inject-rsc-eager.ts +167 -0
  329. package/src/ssr/ssr-root.tsx +228 -0
  330. package/src/static-handler.ts +27 -18
  331. package/src/testing/cache-status.ts +162 -0
  332. package/src/testing/collect-handle.ts +46 -0
  333. package/src/testing/dispatch.ts +813 -0
  334. package/src/testing/dom.entry.ts +22 -0
  335. package/src/testing/e2e/fixture.ts +188 -0
  336. package/src/testing/e2e/index.ts +128 -0
  337. package/src/testing/e2e/matchers.ts +35 -0
  338. package/src/testing/e2e/page-helpers.ts +272 -0
  339. package/src/testing/e2e/parity.ts +387 -0
  340. package/src/testing/e2e/server.ts +195 -0
  341. package/src/testing/flight-matchers.ts +97 -0
  342. package/src/testing/flight-normalize.ts +11 -0
  343. package/src/testing/flight-runtime.d.ts +57 -0
  344. package/src/testing/flight-tree.ts +682 -0
  345. package/src/testing/flight.entry.ts +52 -0
  346. package/src/testing/flight.ts +257 -0
  347. package/src/testing/generated-routes.ts +199 -0
  348. package/src/testing/index.ts +105 -0
  349. package/src/testing/internal/context.ts +371 -0
  350. package/src/testing/internal/flight-client-globals.ts +30 -0
  351. package/src/testing/internal/seed-vars.ts +54 -0
  352. package/src/testing/render-handler.ts +357 -0
  353. package/src/testing/render-route.tsx +584 -0
  354. package/src/testing/run-loader.ts +385 -0
  355. package/src/testing/run-middleware.ts +205 -0
  356. package/src/testing/run-transition-when.ts +164 -0
  357. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  358. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  359. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  360. package/src/testing/vitest-stubs/version.ts +5 -0
  361. package/src/testing/vitest.ts +305 -0
  362. package/src/theme/ThemeProvider.tsx +56 -84
  363. package/src/theme/ThemeScript.tsx +7 -9
  364. package/src/theme/constants.ts +52 -13
  365. package/src/theme/index.ts +0 -7
  366. package/src/theme/theme-context.ts +1 -5
  367. package/src/theme/theme-script.ts +22 -21
  368. package/src/theme/use-theme.ts +0 -3
  369. package/src/types/boundaries.ts +0 -35
  370. package/src/types/cache-types.ts +13 -4
  371. package/src/types/error-types.ts +30 -90
  372. package/src/types/global-namespace.ts +54 -41
  373. package/src/types/handler-context.ts +120 -62
  374. package/src/types/index.ts +3 -10
  375. package/src/types/loader-types.ts +40 -10
  376. package/src/types/request-scope.ts +112 -0
  377. package/src/types/route-config.ts +20 -52
  378. package/src/types/route-entry.ts +12 -7
  379. package/src/types/segments.ts +136 -15
  380. package/src/urls/include-helper.ts +40 -75
  381. package/src/urls/include-provider.ts +71 -0
  382. package/src/urls/index.ts +2 -11
  383. package/src/urls/path-helper-types.ts +102 -23
  384. package/src/urls/path-helper.ts +62 -111
  385. package/src/urls/pattern-types.ts +72 -19
  386. package/src/urls/response-types.ts +25 -22
  387. package/src/urls/type-extraction.ts +98 -154
  388. package/src/urls/urls-function.ts +1 -19
  389. package/src/use-loader.tsx +346 -89
  390. package/src/vercel/index.ts +11 -0
  391. package/src/vercel/tracing.ts +88 -0
  392. package/src/vite/debug.ts +185 -0
  393. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  394. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  395. package/src/vite/discovery/discover-routers.ts +127 -86
  396. package/src/vite/discovery/discovery-errors.ts +255 -0
  397. package/src/vite/discovery/gate-state.ts +171 -0
  398. package/src/vite/discovery/prerender-collection.ts +214 -132
  399. package/src/vite/discovery/route-types-writer.ts +40 -84
  400. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  401. package/src/vite/discovery/state.ts +57 -4
  402. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  403. package/src/vite/index.ts +15 -0
  404. package/src/vite/inject-client-debug.ts +88 -0
  405. package/src/vite/plugin-types.ts +261 -6
  406. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  407. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  408. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  409. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  410. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  411. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  412. package/src/vite/plugins/expose-action-id.ts +48 -95
  413. package/src/vite/plugins/expose-id-utils.ts +96 -51
  414. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  415. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  416. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  417. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  418. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  419. package/src/vite/plugins/performance-tracks.ts +26 -25
  420. package/src/vite/plugins/refresh-cmd.ts +89 -27
  421. package/src/vite/plugins/use-cache-transform.ts +73 -83
  422. package/src/vite/plugins/vercel-output.ts +384 -0
  423. package/src/vite/plugins/version-injector.ts +40 -29
  424. package/src/vite/plugins/version-plugin.ts +37 -40
  425. package/src/vite/plugins/virtual-entries.ts +138 -27
  426. package/src/vite/rango.ts +238 -139
  427. package/src/vite/router-discovery.ts +1091 -159
  428. package/src/vite/utils/ast-handler-extract.ts +26 -35
  429. package/src/vite/utils/banner.ts +1 -1
  430. package/src/vite/utils/bundle-analysis.ts +10 -15
  431. package/src/vite/utils/client-chunks.ts +184 -0
  432. package/src/vite/utils/directive-prologue.ts +40 -0
  433. package/src/vite/utils/forward-user-plugins.ts +171 -0
  434. package/src/vite/utils/manifest-utils.ts +4 -59
  435. package/src/vite/utils/package-resolution.ts +20 -52
  436. package/src/vite/utils/prerender-utils.ts +98 -38
  437. package/src/vite/utils/shared-utils.ts +142 -43
  438. package/src/browser/action-response-classifier.ts +0 -99
  439. package/src/browser/react/use-client-cache.ts +0 -58
  440. package/src/browser/shallow.ts +0 -40
  441. package/src/handles/index.ts +0 -7
  442. package/src/network-error-thrower.tsx +0 -23
  443. package/src/router/middleware-cookies.ts +0 -55
@@ -93,15 +93,17 @@
93
93
  */
94
94
  import type { ResolvedSegment } from "../../types.js";
95
95
  import type { MatchContext, MatchPipelineState } from "../match-context.js";
96
- import { getRouterContext } from "../router-context.js";
97
- import { resolveSink, safeEmit } from "../telemetry.js";
96
+ import { getRouterContext, type RouterContext } from "../router-context.js";
97
+ import { observeEvent } from "../instrument.js";
98
98
  import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
99
+ import { treeHasStreaming } from "./segment-resolution.js";
99
100
  import type { PrerenderStore, PrerenderEntry } from "../../prerender/store.js";
100
101
  import type { HandleStore } from "../../server/handle-store.js";
101
102
  import {
102
103
  getRequestContext,
103
104
  _getRequestContext,
104
105
  } from "../../server/request-context.js";
106
+ import { paramsEqual } from "../params-util.js";
105
107
 
106
108
  // Lazily initialized prerender store singleton and dynamically imported deps.
107
109
  // Dynamic imports prevent pulling in @vitejs/plugin-rsc/rsc virtual module at
@@ -113,6 +115,9 @@ let _deserializeSegments:
113
115
  let _restoreHandles:
114
116
  | typeof import("../../cache/handle-snapshot.js").restoreHandles
115
117
  | undefined;
118
+ let _decodeHandles:
119
+ | typeof import("../../cache/handle-snapshot.js").decodeHandles
120
+ | undefined;
116
121
  let _hashParams:
117
122
  | typeof import("../../prerender/param-hash.js").hashParams
118
123
  | undefined;
@@ -120,22 +125,6 @@ let _lazyGetRequestContext:
120
125
  | typeof import("../../server/request-context.js").getRequestContext
121
126
  | undefined;
122
127
 
123
- function paramsEqual(
124
- a: Record<string, string>,
125
- b: Record<string, string>,
126
- ): boolean {
127
- if (a === b) return true;
128
-
129
- const keysA = Object.keys(a);
130
- if (keysA.length !== Object.keys(b).length) return false;
131
-
132
- for (const key of keysA) {
133
- if (a[key] !== b[key]) return false;
134
- }
135
-
136
- return true;
137
- }
138
-
139
128
  async function ensurePrerenderDeps() {
140
129
  if (!_deserializeSegments) {
141
130
  const [codec, snapshot, paramHash, reqCtx, store] = await Promise.all([
@@ -147,6 +136,7 @@ async function ensurePrerenderDeps() {
147
136
  ]);
148
137
  _deserializeSegments = codec.deserializeSegments;
149
138
  _restoreHandles = snapshot.restoreHandles;
139
+ _decodeHandles = snapshot.decodeHandles;
150
140
  _hashParams = paramHash.hashParams;
151
141
  _lazyGetRequestContext = reqCtx.getRequestContext;
152
142
  if (prerenderStoreInstance === undefined) {
@@ -160,59 +150,21 @@ async function ensurePrerenderDeps() {
160
150
  * Deserializes segments, replays handle data, yields segments with partial
161
151
  * navigation nullification, and resolves fresh loaders.
162
152
  */
163
- async function* yieldFromStore<TEnv>(
164
- entry: PrerenderEntry,
153
+ // Resolve loaders fresh on a cache hit (loaders are NEVER cached) and yield
154
+ // the loader segments, updating state.matchedIds and pushing the loader-resolve
155
+ // + cache-hit metrics. Shared verbatim by the prerender-store path
156
+ // (yieldFromStore) and the runtime cache-hit path (withCacheLookup). The router
157
+ // resolve fns are passed in (captured early by the callers) rather than re-read
158
+ // from getRouterContext() here, because that is ALS-backed and the callers run
159
+ // awaits before reaching this point (workerd can disrupt ALS mid-pipeline).
160
+ async function* resolveFreshLoadersAndYield<TEnv>(
165
161
  ctx: MatchContext<TEnv>,
166
162
  state: MatchPipelineState,
167
163
  pipelineStart: number,
168
- handleStoreRef?: HandleStore,
164
+ ms: MatchContext<TEnv>["metricsStore"],
165
+ resolveLoadersOnly: RouterContext<TEnv>["resolveLoadersOnly"],
166
+ resolveLoadersOnlyWithRevalidation: RouterContext<TEnv>["resolveLoadersOnlyWithRevalidation"],
169
167
  ): AsyncGenerator<ResolvedSegment> {
170
- const { resolveLoadersOnlyWithRevalidation, resolveLoadersOnly } =
171
- getRouterContext<TEnv>();
172
-
173
- if (
174
- !_deserializeSegments ||
175
- !_restoreHandles ||
176
- !_hashParams ||
177
- !_lazyGetRequestContext
178
- ) {
179
- throw new Error("yieldFromStore called before ensurePrerenderDeps");
180
- }
181
-
182
- const segments = await _deserializeSegments(entry.segments);
183
-
184
- // Replay handle data (same as runtime cache hit path).
185
- // Prefer the eagerly-captured handleStoreRef to avoid ALS disruption in workerd.
186
- const handleStore = handleStoreRef ?? _lazyGetRequestContext()?._handleStore;
187
- if (handleStore) {
188
- _restoreHandles(entry.handles, handleStore);
189
- }
190
-
191
- state.cacheHit = true;
192
- state.cacheSource = "prerender";
193
- state.cachedSegments = segments;
194
- state.cachedMatchedIds = segments.map((s) => s.id);
195
-
196
- // For partial navigation, nullify components the client already has
197
- // so parent layouts stay live (client keeps its existing versions).
198
- // When params changed (e.g., different guide slug), the segments have
199
- // different content, so we must NOT nullify.
200
- const paramsChanged =
201
- !ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
202
- for (const segment of segments) {
203
- if (
204
- !ctx.isFullMatch &&
205
- !paramsChanged &&
206
- ctx.clientSegmentSet.has(segment.id)
207
- ) {
208
- segment.component = null;
209
- segment.loading = undefined;
210
- }
211
- yield segment;
212
- }
213
-
214
- // Resolve loaders fresh (loaders are never pre-rendered/cached)
215
- const ms = ctx.metricsStore;
216
168
  const loaderStart = performance.now();
217
169
 
218
170
  if (ctx.isFullMatch) {
@@ -240,6 +192,9 @@ async function* yieldFromStore<TEnv>(
240
192
  ctx.url,
241
193
  ctx.routeKey,
242
194
  ctx.actionContext,
195
+ // Loaders are never cached in the segment cache, so segment staleness
196
+ // must not propagate; browser-sent staleness (ctx.stale) still must.
197
+ ctx.stale || undefined,
243
198
  ),
244
199
  );
245
200
  state.matchedIds = [
@@ -270,6 +225,115 @@ async function* yieldFromStore<TEnv>(
270
225
  }
271
226
  }
272
227
 
228
+ async function* yieldFromStore<TEnv>(
229
+ entry: PrerenderEntry,
230
+ ctx: MatchContext<TEnv>,
231
+ state: MatchPipelineState,
232
+ pipelineStart: number,
233
+ handleStoreRef?: HandleStore,
234
+ ): AsyncGenerator<ResolvedSegment> {
235
+ const { resolveLoadersOnlyWithRevalidation, resolveLoadersOnly } =
236
+ getRouterContext<TEnv>();
237
+
238
+ if (
239
+ !_deserializeSegments ||
240
+ !_restoreHandles ||
241
+ !_decodeHandles ||
242
+ !_hashParams ||
243
+ !_lazyGetRequestContext
244
+ ) {
245
+ throw new Error("yieldFromStore called before ensurePrerenderDeps");
246
+ }
247
+
248
+ const segments = await _deserializeSegments(entry.segments);
249
+
250
+ // Replay handle data (same as runtime cache hit path). entry.handles is a
251
+ // Flight-encoded string ("" when none) — decode before restore so
252
+ // Promise/ReactNode handle values are revived, not the corrupted JSON form.
253
+ const handleStore = handleStoreRef ?? _lazyGetRequestContext()?._handleStore;
254
+ if (handleStore && entry.handles) {
255
+ const handlesRecord = await _decodeHandles(entry.handles);
256
+ if (handlesRecord) {
257
+ _restoreHandles(handlesRecord, handleStore);
258
+ }
259
+ }
260
+
261
+ state.cacheHit = true;
262
+ state.cacheSource = "prerender";
263
+ state.cachedSegments = segments;
264
+ state.cachedMatchedIds = segments.map((s) => s.id);
265
+
266
+ // Set streaming flag (once) and resolve render barrier.
267
+ const reqCtx = handleStoreRef ? undefined : _lazyGetRequestContext?.();
268
+ const barrierReqCtx = reqCtx ?? _getRequestContext();
269
+ if (barrierReqCtx) {
270
+ if (barrierReqCtx._treeHasStreaming === undefined) {
271
+ barrierReqCtx._treeHasStreaming = treeHasStreaming(ctx.entries);
272
+ }
273
+ barrierReqCtx._resolveRenderBarrier(segments);
274
+ }
275
+
276
+ // For partial navigation, nullify components the client already has
277
+ // so parent layouts stay live (client keeps its existing versions).
278
+ // When params changed (e.g., different guide slug), the segments have
279
+ // different content, so we must NOT nullify.
280
+ const paramsChanged =
281
+ !ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
282
+ for (const segment of segments) {
283
+ if (
284
+ !ctx.isFullMatch &&
285
+ !paramsChanged &&
286
+ ctx.clientSegmentSet.has(segment.id)
287
+ ) {
288
+ segment.component = null;
289
+ segment.loading = undefined;
290
+ }
291
+ yield segment;
292
+ }
293
+
294
+ // Resolve loaders fresh (loaders are never pre-rendered/cached).
295
+ yield* resolveFreshLoadersAndYield(
296
+ ctx,
297
+ state,
298
+ pipelineStart,
299
+ ctx.metricsStore,
300
+ resolveLoadersOnly,
301
+ resolveLoadersOnlyWithRevalidation,
302
+ );
303
+ }
304
+
305
+ /**
306
+ * Look up a prerendered (build-time cached) entry for the current route and, on
307
+ * a hit, yield its segments. Returns true when an entry was served (the caller
308
+ * should stop the pipeline) and false on a miss. Intercept navigations consult
309
+ * only the intercept-specific entry (`paramHash + "/i"`); a miss there falls
310
+ * through to the normal pipeline so intercept-resolution can run. Callers must
311
+ * guard on `prerenderStoreInstance` after `ensurePrerenderDeps()`.
312
+ */
313
+ async function* tryPrerenderLookup<TEnv>(
314
+ ctx: MatchContext<TEnv>,
315
+ state: MatchPipelineState,
316
+ pipelineStart: number,
317
+ handleStoreRef?: HandleStore,
318
+ ): AsyncGenerator<ResolvedSegment, boolean> {
319
+ const paramHash = _hashParams!(ctx.matched.params);
320
+ const isPassthroughPrerenderRoute = ctx.entries.some(
321
+ (entry) => entry.type === "route" && entry.isPassthrough === true,
322
+ );
323
+ const lookupHash = ctx.isIntercept ? paramHash + "/i" : paramHash;
324
+ const entry = await prerenderStoreInstance!.get(
325
+ ctx.matched.routeKey,
326
+ lookupHash,
327
+ {
328
+ pathname: ctx.pathname,
329
+ isPassthroughRoute: isPassthroughPrerenderRoute,
330
+ },
331
+ );
332
+ if (!entry) return false;
333
+ yield* yieldFromStore(entry, ctx, state, pipelineStart, handleStoreRef);
334
+ return true;
335
+ }
336
+
273
337
  /**
274
338
  * Async generator middleware type
275
339
  */
@@ -314,75 +378,20 @@ export function withCacheLookup<TEnv>(
314
378
  resolveLoadersOnly,
315
379
  } = getRouterContext<TEnv>();
316
380
 
317
- // Prerender lookup: check build-time cached data before runtime cache.
318
- // Prerender data is available regardless of runtime cache configuration.
319
- // Skip for HMR requests — the dev prerender endpoint reads from a stale
320
- // RouterRegistry snapshot; rendering fresh ensures edits are visible.
321
381
  const isHmr = !!ctx.request.headers.get("X-RSC-HMR");
322
382
  if (!ctx.isAction && !isHmr && ctx.matched.pr) {
323
383
  await ensurePrerenderDeps();
324
384
  if (prerenderStoreInstance) {
325
- const paramHash = _hashParams!(ctx.matched.params);
326
- const isPassthroughPrerenderRoute = ctx.entries.some(
327
- (entry) =>
328
- entry.type === "route" &&
329
- entry.prerenderDef?.options?.passthrough === true,
385
+ const served = yield* tryPrerenderLookup(
386
+ ctx,
387
+ state,
388
+ pipelineStart,
389
+ handleStoreRef,
330
390
  );
331
-
332
- if (ctx.isIntercept) {
333
- // Intercept navigation: try intercept-specific prerender entry
334
- const entry = await prerenderStoreInstance.get(
335
- ctx.matched.routeKey,
336
- paramHash + "/i",
337
- {
338
- pathname: ctx.pathname,
339
- isPassthroughRoute: isPassthroughPrerenderRoute,
340
- },
341
- );
342
- if (entry) {
343
- yield* yieldFromStore(
344
- entry,
345
- ctx,
346
- state,
347
- pipelineStart,
348
- handleStoreRef,
349
- );
350
- return;
351
- }
352
- // No intercept prerender -- fall through to normal pipeline
353
- // (skip non-intercept prerender to let intercept-resolution run)
354
- } else {
355
- // Normal navigation: existing behavior
356
- const entry = await prerenderStoreInstance.get(
357
- ctx.matched.routeKey,
358
- paramHash,
359
- {
360
- pathname: ctx.pathname,
361
- isPassthroughRoute: isPassthroughPrerenderRoute,
362
- },
363
- );
364
- if (entry) {
365
- yield* yieldFromStore(
366
- entry,
367
- ctx,
368
- state,
369
- pipelineStart,
370
- handleStoreRef,
371
- );
372
- return;
373
- }
374
- }
391
+ if (served) return;
375
392
  }
376
393
  }
377
394
 
378
- // Dev-mode static handler interception for non-Node.js runtimes.
379
- // __PRERENDER_DEV_URL is set by the Vite plugin when the RSC environment
380
- // lacks a Node.js module runner (e.g. workerd, Deno workers). In those
381
- // runtimes, handlers that depend on Node APIs like node:fs can't run
382
- // in-process. We redirect them to the /__rsc_prerender endpoint which
383
- // resolves segments in a Node.js temp server, same as prerender routes.
384
- // In Node.js dev mode this variable is undefined -- handlers run
385
- // in-process where Node APIs work, so no interception is needed.
386
395
  if (!ctx.isAction && !ctx.matched.pr && globalThis.__PRERENDER_DEV_URL) {
387
396
  const hasStatic = ctx.entries.some(
388
397
  (e) =>
@@ -394,60 +403,18 @@ export function withCacheLookup<TEnv>(
394
403
  if (hasStatic) {
395
404
  await ensurePrerenderDeps();
396
405
  if (prerenderStoreInstance) {
397
- const paramHash = _hashParams!(ctx.matched.params);
398
- const isPassthroughPrerenderRoute = ctx.entries.some(
399
- (entry) =>
400
- entry.type === "route" &&
401
- entry.prerenderDef?.options?.passthrough === true,
406
+ const served = yield* tryPrerenderLookup(
407
+ ctx,
408
+ state,
409
+ pipelineStart,
410
+ handleStoreRef,
402
411
  );
403
-
404
- if (ctx.isIntercept) {
405
- const entry = await prerenderStoreInstance.get(
406
- ctx.matched.routeKey,
407
- paramHash + "/i",
408
- {
409
- pathname: ctx.pathname,
410
- isPassthroughRoute: isPassthroughPrerenderRoute,
411
- },
412
- );
413
- if (entry) {
414
- yield* yieldFromStore(
415
- entry,
416
- ctx,
417
- state,
418
- pipelineStart,
419
- handleStoreRef,
420
- );
421
- return;
422
- }
423
- // No intercept prerender -- fall through to normal pipeline
424
- } else {
425
- const entry = await prerenderStoreInstance.get(
426
- ctx.matched.routeKey,
427
- paramHash,
428
- {
429
- pathname: ctx.pathname,
430
- isPassthroughRoute: isPassthroughPrerenderRoute,
431
- },
432
- );
433
- if (entry) {
434
- yield* yieldFromStore(
435
- entry,
436
- ctx,
437
- state,
438
- pipelineStart,
439
- handleStoreRef,
440
- );
441
- return;
442
- }
443
- }
412
+ if (served) return;
444
413
  }
445
414
  }
446
415
  }
447
416
 
448
- // Skip cache during actions
449
417
  if (ctx.isAction || !ctx.cacheScope?.enabled) {
450
- // Cache miss - pass through to segment resolution
451
418
  yield* source;
452
419
  if (ms) {
453
420
  ms.metrics.push({
@@ -459,7 +426,6 @@ export function withCacheLookup<TEnv>(
459
426
  return;
460
427
  }
461
428
 
462
- // Lookup cache
463
429
  const cacheResult = await ctx.cacheScope.lookupRoute(
464
430
  ctx.pathname,
465
431
  ctx.matched.params,
@@ -467,7 +433,6 @@ export function withCacheLookup<TEnv>(
467
433
  );
468
434
 
469
435
  if (!cacheResult) {
470
- // Cache miss - pass through to segment resolution
471
436
  yield* source;
472
437
  if (ms) {
473
438
  ms.metrics.push({
@@ -479,16 +444,12 @@ export function withCacheLookup<TEnv>(
479
444
  return;
480
445
  }
481
446
 
482
- // Cache HIT
483
447
  state.cacheHit = true;
484
448
  state.cacheSource = "runtime";
485
449
  state.shouldRevalidate = cacheResult.shouldRevalidate;
486
450
  state.cachedSegments = cacheResult.segments;
487
451
  state.cachedMatchedIds = cacheResult.segments.map((s) => s.id);
488
452
 
489
- // Apply revalidation to cached segments.
490
- // For full matches or empty client segment sets, this map is unnecessary:
491
- // we never run segment-level revalidation and can stream segments directly.
492
453
  const canCheckSegmentRevalidation =
493
454
  !ctx.isFullMatch &&
494
455
  ctx.clientSegmentSet.size > 0 &&
@@ -498,7 +459,6 @@ export function withCacheLookup<TEnv>(
498
459
  : undefined;
499
460
 
500
461
  for (const segment of cacheResult.segments) {
501
- // Skip segments client doesn't have - they need their component
502
462
  if (!ctx.clientSegmentSet.has(segment.id)) {
503
463
  if (isTraceActive()) {
504
464
  pushRevalidationTraceEntry({
@@ -515,19 +475,13 @@ export function withCacheLookup<TEnv>(
515
475
  continue;
516
476
  }
517
477
 
518
- // Skip intercept segments - they're handled separately
519
478
  if (segment.namespace?.startsWith("intercept:")) {
520
479
  yield segment;
521
480
  continue;
522
481
  }
523
482
 
524
- // Look up revalidation rules for this segment
525
483
  const entryInfo = entryRevalidateMap?.get(segment.id);
526
484
 
527
- // Even without explicit revalidation rules, route segments and their
528
- // children must re-render when params or search params change — the
529
- // handler reads ctx.params/ctx.searchParams so different values produce
530
- // different content. Matches evaluateRevalidation's default logic.
531
485
  const searchChanged = ctx.prevUrl.search !== ctx.url.search;
532
486
  const routeParamsChanged = !paramsEqual(
533
487
  ctx.matched.params,
@@ -541,7 +495,6 @@ export function withCacheLookup<TEnv>(
541
495
 
542
496
  if (!entryInfo || entryInfo.revalidate.length === 0) {
543
497
  if (shouldDefaultRevalidate) {
544
- // Params or search params changed — must re-render even without custom rules
545
498
  if (isTraceActive()) {
546
499
  pushRevalidationTraceEntry({
547
500
  segmentId: segment.id,
@@ -558,7 +511,6 @@ export function withCacheLookup<TEnv>(
558
511
  yield segment;
559
512
  continue;
560
513
  }
561
- // No revalidation rules, use default behavior (skip if client has)
562
514
  if (isTraceActive()) {
563
515
  pushRevalidationTraceEntry({
564
516
  segmentId: segment.id,
@@ -576,7 +528,6 @@ export function withCacheLookup<TEnv>(
576
528
  continue;
577
529
  }
578
530
 
579
- // Evaluate revalidation rules
580
531
  const shouldRevalidate = await evaluateRevalidation({
581
532
  segment,
582
533
  prevParams: ctx.prevParams,
@@ -591,26 +542,20 @@ export function withCacheLookup<TEnv>(
591
542
  routeKey: ctx.routeKey,
592
543
  context: ctx.handlerContext,
593
544
  actionContext: ctx.actionContext,
594
- stale: cacheResult.shouldRevalidate || undefined,
545
+ stale: cacheResult.shouldRevalidate || ctx.stale || undefined,
595
546
  traceSource: "cache-hit",
596
547
  });
597
548
 
598
- const routerCtx = getRouterContext<TEnv>();
599
- if (routerCtx.telemetry) {
600
- const tSink = resolveSink(routerCtx.telemetry);
601
- safeEmit(tSink, {
602
- type: "revalidation.decision",
603
- timestamp: performance.now(),
604
- requestId: routerCtx.requestId,
605
- segmentId: segment.id,
606
- pathname: ctx.pathname,
607
- routeKey: ctx.routeKey,
608
- shouldRevalidate,
609
- });
610
- }
549
+ observeEvent({
550
+ type: "revalidation.decision",
551
+ timestamp: performance.now(),
552
+ segmentId: segment.id,
553
+ pathname: ctx.pathname,
554
+ routeKey: ctx.routeKey,
555
+ shouldRevalidate,
556
+ });
611
557
 
612
558
  if (!shouldRevalidate) {
613
- // Client has it, no revalidation needed
614
559
  segment.component = null;
615
560
  segment.loading = undefined;
616
561
  }
@@ -618,77 +563,23 @@ export function withCacheLookup<TEnv>(
618
563
  yield segment;
619
564
  }
620
565
 
621
- // Resolve loaders fresh (loaders are NOT cached by default)
622
- // This ensures fresh data even on cache hit
623
- const Store = ctx.Store;
624
- const loaderStart = performance.now();
625
-
626
- if (ctx.isFullMatch) {
627
- // Full match (document request) - simple loader resolution without revalidation
628
- if (resolveLoadersOnly) {
629
- const loaderSegments = await Store.run(() =>
630
- resolveLoadersOnly(ctx.entries, ctx.handlerContext),
631
- );
632
-
633
- // Update state - full match doesn't track matchedIds separately
634
- state.matchedIds = state.cachedMatchedIds!;
635
-
636
- // Yield fresh loader segments
637
- for (const segment of loaderSegments) {
638
- yield segment;
639
- }
640
- } else {
641
- state.matchedIds = state.cachedMatchedIds!;
642
- }
643
- } else {
644
- // Partial match (navigation) - loader resolution with revalidation
645
- if (resolveLoadersOnlyWithRevalidation) {
646
- const loaderResult = await Store.run(() =>
647
- resolveLoadersOnlyWithRevalidation(
648
- ctx.entries,
649
- ctx.handlerContext,
650
- ctx.clientSegmentSet,
651
- ctx.prevParams,
652
- ctx.request,
653
- ctx.prevUrl,
654
- ctx.url,
655
- ctx.routeKey,
656
- ctx.actionContext,
657
- // Loaders are never cached in the segment cache, so segment
658
- // staleness (cacheResult.shouldRevalidate) must not propagate.
659
- // But browser-sent staleness (ctx.stale) — indicating an action
660
- // happened in this or another tab — must still reach loaders.
661
- ctx.stale || undefined,
662
- ),
663
- );
664
-
665
- // Update state with fresh loader matchedIds
666
- state.matchedIds = [
667
- ...state.cachedMatchedIds!,
668
- ...loaderResult.matchedIds,
669
- ];
670
-
671
- // Yield fresh loader segments
672
- for (const segment of loaderResult.segments) {
673
- yield segment;
674
- }
675
- } else {
676
- state.matchedIds = state.cachedMatchedIds!;
566
+ const barrierReqCtx = _getRequestContext();
567
+ if (barrierReqCtx) {
568
+ if (barrierReqCtx._treeHasStreaming === undefined) {
569
+ barrierReqCtx._treeHasStreaming = treeHasStreaming(ctx.entries);
677
570
  }
571
+ barrierReqCtx._resolveRenderBarrier(cacheResult.segments);
678
572
  }
679
- if (ms) {
680
- const loaderEnd = performance.now();
681
- ms.metrics.push({
682
- label: "pipeline:loader-resolve",
683
- duration: loaderEnd - loaderStart,
684
- startTime: loaderStart - ms.requestStart,
685
- depth: 1,
686
- });
687
- ms.metrics.push({
688
- label: "pipeline:cache-hit",
689
- duration: loaderEnd - pipelineStart,
690
- startTime: pipelineStart - ms.requestStart,
691
- });
692
- }
573
+
574
+ // Resolve loaders fresh (loaders are never cached). Shared with the
575
+ // prerender-store path via resolveFreshLoadersAndYield.
576
+ yield* resolveFreshLoadersAndYield(
577
+ ctx,
578
+ state,
579
+ pipelineStart,
580
+ ms,
581
+ resolveLoadersOnly,
582
+ resolveLoadersOnlyWithRevalidation,
583
+ );
693
584
  };
694
585
  }