@rangojs/router 0.0.0-experimental.135c6902 → 0.0.0-experimental.136

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