@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
@@ -8,19 +8,25 @@ import type {
8
8
  import { NetworkError, ServerRedirect, isNetworkError } from "../errors.js";
9
9
  import {
10
10
  browserDebugLog,
11
+ debugLog,
11
12
  isBrowserDebugEnabled,
12
13
  startBrowserTransaction,
13
14
  } from "./logging.js";
14
15
  import { getRangoState } from "./rango-state.js";
16
+ import { isActionFenceActive } from "./action-fence.js";
15
17
  import {
16
18
  extractRscHeaderUrl,
17
19
  emptyResponse,
20
+ handleReloadHeader,
18
21
  teeWithCompletion,
22
+ isForeignRouterId,
19
23
  } from "./response-adapter.js";
20
24
  import {
21
25
  buildPrefetchKey,
26
+ buildSourceKey,
22
27
  consumeInflightPrefetch,
23
28
  consumePrefetch,
29
+ type DecodedPrefetch,
24
30
  } from "./prefetch/cache.js";
25
31
 
26
32
  /**
@@ -30,8 +36,10 @@ import {
30
36
  * deserializing the response using the RSC runtime.
31
37
  *
32
38
  * Checks the in-memory prefetch cache before making a network request.
33
- * The cache key is source-dependent (includes the previous URL) so
34
- * prefetch responses match the exact diff the server would produce.
39
+ * Tries the source-scoped key first (populated when the server tagged
40
+ * the response as source-sensitive via `X-RSC-Prefetch-Scope: source`)
41
+ * and falls back to the Rango-state-keyed wildcard slot used for the
42
+ * common source-agnostic case.
35
43
  *
36
44
  * @param deps - RSC browser dependencies (createFromFetch)
37
45
  * @returns NavigationClient instance
@@ -93,18 +101,49 @@ export function createNavigationClient(
93
101
  fetchUrl.searchParams.set("_rsc_rid", routerId);
94
102
  }
95
103
 
96
- // Check completed in-memory prefetch cache before making a network request.
97
- // The cache key includes the source URL (previousUrl) because the
98
- // server's diff response depends on the source page context.
104
+ // Check completed in-memory prefetch cache before making a network
105
+ // request. Try the source-scoped key first (populated when the server
106
+ // tagged the prefetch response as source-sensitive, e.g. intercepts,
107
+ // or when a Link opted in with `prefetchKey=":source"`), then fall
108
+ // back to the wildcard slot shared across source pages.
109
+ // Both keys embed the Rango state, so state rotation (deploy or
110
+ // server-action invalidation) auto-invalidates both scopes.
99
111
  // Skip cache for stale revalidation (needs fresh data), HMR (needs
100
112
  // fresh modules), and intercept contexts (source-dependent responses).
101
- //
102
- const canUsePrefetch = !staleRevalidation && !hmr && !interceptSourceUrl;
103
- const cacheKey = buildPrefetchKey(previousUrl, fetchUrl);
104
- const cachedResponse = canUsePrefetch ? consumePrefetch(cacheKey) : null;
105
- const inflightResponsePromise = canUsePrefetch
106
- ? consumeInflightPrefetch(cacheKey)
107
- : null;
113
+ // Suspend prefetch consumption while an action is in flight: a queued
114
+ // prefetch holds pre-mutation data and must not be served until the
115
+ // action's response decides whether anything changed.
116
+ const canUsePrefetch =
117
+ !staleRevalidation &&
118
+ !hmr &&
119
+ !interceptSourceUrl &&
120
+ !isActionFenceActive();
121
+ const rangoState = getRangoState();
122
+ const wildcardKey = buildPrefetchKey(rangoState, fetchUrl);
123
+ const cacheKey = buildSourceKey(rangoState, previousUrl, fetchUrl);
124
+
125
+ let cachedEntry: DecodedPrefetch | null = null;
126
+ let hitKey: string | null = null;
127
+ if (canUsePrefetch) {
128
+ cachedEntry = consumePrefetch(cacheKey);
129
+ if (cachedEntry) {
130
+ hitKey = cacheKey;
131
+ } else {
132
+ cachedEntry = consumePrefetch(wildcardKey);
133
+ if (cachedEntry) hitKey = wildcardKey;
134
+ }
135
+ }
136
+
137
+ let inflightEntryPromise: Promise<DecodedPrefetch | null> | null = null;
138
+ if (canUsePrefetch && !cachedEntry) {
139
+ inflightEntryPromise = consumeInflightPrefetch(cacheKey);
140
+ if (inflightEntryPromise) {
141
+ hitKey = cacheKey;
142
+ } else {
143
+ inflightEntryPromise = consumeInflightPrefetch(wildcardKey);
144
+ if (inflightEntryPromise) hitKey = wildcardKey;
145
+ }
146
+ }
108
147
  // Track when the stream completes
109
148
  let resolveStreamComplete: () => void;
110
149
  const streamComplete = new Promise<void>((resolve) => {
@@ -121,21 +160,17 @@ export function createNavigationClient(
121
160
  source: string,
122
161
  ): Response | Promise<Response> => {
123
162
  // Version mismatch — server wants a full page reload
124
- const reload = extractRscHeaderUrl(response, "X-RSC-Reload");
125
- if (reload === "blocked") {
126
- resolveStreamComplete();
127
- return emptyResponse();
128
- }
129
- if (reload) {
130
- if (tx) {
131
- browserDebugLog(tx, `version mismatch, reloading (${source})`, {
132
- reloadUrl: reload.url,
133
- });
134
- }
135
- window.location.href = reload.url;
136
- // Block further processing — page is reloading
137
- return new Promise<Response>(() => {});
138
- }
163
+ const reloadResult = handleReloadHeader(response, {
164
+ onBlocked: resolveStreamComplete,
165
+ onReload: (url) => {
166
+ if (tx) {
167
+ browserDebugLog(tx, `version mismatch, reloading (${source})`, {
168
+ reloadUrl: url,
169
+ });
170
+ }
171
+ },
172
+ });
173
+ if (reloadResult) return reloadResult;
139
174
 
140
175
  // Server-side redirect without state: the server returned 204 with
141
176
  // X-RSC-Redirect instead of a 3xx (which fetch would auto-follow
@@ -156,6 +191,19 @@ export function createNavigationClient(
156
191
  throw new ServerRedirect(redirect.url, undefined);
157
192
  }
158
193
 
194
+ // Integrity check (pre-decode): refuse a foreign app's content response
195
+ // before createFromFetch imports its chunks. Ordered AFTER the reload
196
+ // and redirect handlers — control responses are never stamped with
197
+ // X-RSC-Router-Id, so they are steered first and never reach here.
198
+ if (isForeignRouterId(response, routerId)) {
199
+ if (tx) {
200
+ browserDebugLog(tx, `router id mismatch, reloading (${source})`);
201
+ }
202
+ resolveStreamComplete();
203
+ window.location.href = targetUrl;
204
+ return new Promise<Response>(() => {});
205
+ }
206
+
159
207
  return response;
160
208
  };
161
209
 
@@ -168,9 +216,18 @@ export function createNavigationClient(
168
216
  }
169
217
 
170
218
  return fetch(fetchUrl, {
219
+ // During an action's flight the state is not rotated, so the old
220
+ // X-Rango-State still matches the Vary-keyed HTTP-cache entry; bypass
221
+ // it so a genuine mid-action navigation fetches fresh instead of being
222
+ // served the stale prefetched bytes.
223
+ ...(isActionFenceActive() && { cache: "no-store" as RequestCache }),
171
224
  headers: {
172
225
  "X-RSC-Router-Client-Path": previousUrl,
173
- "X-Rango-State": getRangoState(),
226
+ // Reuse the single per-operation read (see rangoState above): the
227
+ // cache-key lookup and this header must agree on one value, and the
228
+ // cookie read has side effects (external-rotation notify) we do not
229
+ // want to fire twice per navigation.
230
+ "X-Rango-State": rangoState,
174
231
  ...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
175
232
  ...(interceptSourceUrl && {
176
233
  "X-RSC-Router-Intercept-Source": interceptSourceUrl,
@@ -193,57 +250,89 @@ export function createNavigationClient(
193
250
  });
194
251
  };
195
252
 
196
- let responsePromise: Promise<Response>;
253
+ // A warm prefetch hit returns its eagerly-decoded payload directly: the
254
+ // route's chunks were imported during the prefetch, so this click runs
255
+ // no decode and no network. Only the fresh path runs createFromFetch and
256
+ // resolves the local streamComplete (via doFreshFetch's teeWithCompletion
257
+ // and the control-header short-circuits in validateRscHeaders).
258
+ const freshResult = (): {
259
+ payload: Promise<RscPayload>;
260
+ streamComplete: Promise<void>;
261
+ } => ({
262
+ payload: deps.createFromFetch<RscPayload>(doFreshFetch()),
263
+ streamComplete,
264
+ });
265
+
266
+ let payloadPromise: Promise<RscPayload>;
267
+ let streamCompletePromise: Promise<void>;
268
+ // True only for a prefetch-cache hit whose stream had already fully drained
269
+ // (complete === true). A still-streaming hit and the fresh path stay false,
270
+ // so only a fully-warmed prefetch commits in a transition (no fallback flash).
271
+ let fullyPrefetched = false;
197
272
 
198
- if (cachedResponse) {
273
+ if (cachedEntry) {
199
274
  if (tx) {
200
- browserDebugLog(tx, "prefetch cache hit", { key: cacheKey });
275
+ browserDebugLog(tx, "prefetch cache hit (warm)", {
276
+ key: hitKey,
277
+ wildcard: hitKey === wildcardKey,
278
+ });
201
279
  }
202
- responsePromise = Promise.resolve(cachedResponse).then((response) => {
203
- const validated = validateRscHeaders(response, "prefetch cache");
204
- if (validated instanceof Promise) return validated;
205
-
206
- return teeWithCompletion(
207
- validated,
208
- () => {
209
- if (tx) browserDebugLog(tx, "stream complete (from cache)");
210
- resolveStreamComplete();
211
- },
212
- signal,
213
- );
214
- });
215
- } else if (inflightResponsePromise) {
280
+ payloadPromise = cachedEntry.payload;
281
+ streamCompletePromise = cachedEntry.streamComplete;
282
+ // Only a hit whose stream already fully drained is "fully prefetched";
283
+ // a still-streaming hit must keep streaming its fallbacks like a cold load.
284
+ fullyPrefetched = cachedEntry.complete;
285
+ } else if (inflightEntryPromise) {
216
286
  if (tx) {
217
- browserDebugLog(tx, "reusing inflight prefetch", { key: cacheKey });
287
+ browserDebugLog(tx, "reusing inflight prefetch", {
288
+ key: hitKey,
289
+ wildcard: hitKey === wildcardKey,
290
+ });
218
291
  }
219
- responsePromise = inflightResponsePromise.then(async (response) => {
220
- if (!response) {
221
- if (tx) {
222
- browserDebugLog(tx, "inflight prefetch unavailable, refetching");
223
- }
224
- return doFreshFetch();
292
+ const adoptedViaWildcard = hitKey === wildcardKey;
293
+ const entry = await inflightEntryPromise;
294
+ if (!entry) {
295
+ if (tx) {
296
+ browserDebugLog(tx, "inflight prefetch unavailable, refetching");
225
297
  }
226
-
227
- const validated = validateRscHeaders(response, "inflight prefetch");
228
- if (validated instanceof Promise) return validated;
229
-
230
- return teeWithCompletion(
231
- validated,
232
- () => {
233
- if (tx) {
234
- browserDebugLog(tx, "stream complete (from inflight prefetch)");
235
- }
236
- resolveStreamComplete();
237
- },
238
- signal,
239
- );
240
- });
298
+ ({ payload: payloadPromise, streamComplete: streamCompletePromise } =
299
+ freshResult());
300
+ } else if (adoptedViaWildcard && entry.scope === "source") {
301
+ // A wildcard-adopted inflight that turned out source-scoped was
302
+ // built for a different source page. Discard and refetch.
303
+ if (tx) {
304
+ browserDebugLog(
305
+ tx,
306
+ "wildcard inflight turned out source-scoped, refetching",
307
+ );
308
+ }
309
+ ({ payload: payloadPromise, streamComplete: streamCompletePromise } =
310
+ freshResult());
311
+ } else {
312
+ payloadPromise = entry.payload;
313
+ streamCompletePromise = entry.streamComplete;
314
+ // Adopted inflight is normally still streaming (false), but read the
315
+ // flag in case it completed between publish and adoption.
316
+ fullyPrefetched = entry.complete;
317
+ }
241
318
  } else {
242
- responsePromise = doFreshFetch();
319
+ ({ payload: payloadPromise, streamComplete: streamCompletePromise } =
320
+ freshResult());
243
321
  }
244
322
 
245
323
  try {
246
- const payload = await deps.createFromFetch<RscPayload>(responsePromise);
324
+ // [VT-DIAG] Gated behind INTERNAL_RANGO_DEBUG. Times how long the RSC
325
+ // payload ROOT takes to resolve: ~full-stream duration means the root
326
+ // model is not flushed early (server/runtime buffering, e.g. wrangler
327
+ // dev gzip); fast means the block, if any, is downstream in render.
328
+ const vtDebugStart = isBrowserDebugEnabled() ? performance.now() : 0;
329
+ const payload = await payloadPromise;
330
+ if (isBrowserDebugEnabled()) {
331
+ debugLog("[VT-DIAG] payloadResolved", {
332
+ ms: Math.round(performance.now() - vtDebugStart),
333
+ isPartial: payload.metadata?.isPartial,
334
+ });
335
+ }
247
336
 
248
337
  if (tx) {
249
338
  browserDebugLog(tx, "response received", {
@@ -252,7 +341,11 @@ export function createNavigationClient(
252
341
  diffCount: payload.metadata?.diff?.length ?? 0,
253
342
  });
254
343
  }
255
- return { payload, streamComplete };
344
+ return {
345
+ payload,
346
+ streamComplete: streamCompletePromise,
347
+ fullyPrefetched,
348
+ };
256
349
  } catch (error) {
257
350
  // Convert network-level errors to NetworkError for proper handling
258
351
  if (isNetworkError(error)) {
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A module-level handle to the active navigation store.
3
+ *
4
+ * The boot path (`rsc-router.tsx`) calls `createNavigationStore()` directly;
5
+ * there is no global store singleton. This handle is the live reference for
6
+ * code that needs the store but does not
7
+ * receive it by argument: the jar-divergence observer (below) and the client
8
+ * seat of `invalidateClientCache()` (added later).
9
+ *
10
+ * Dependency-light on purpose: it imports only `setRangoStateObserver` and the
11
+ * store type, so pulling it into the default root entry does not drag the
12
+ * navigation store into bundles that previously lacked it.
13
+ */
14
+
15
+ import { setRangoStateObserver } from "./rango-state.js";
16
+ import type { NavigationStore } from "./types.js";
17
+
18
+ let registeredStore: NavigationStore | null = null;
19
+
20
+ /**
21
+ * Register the active navigation store at boot, and wire the jar-divergence
22
+ * observer: when a per-request cookie read detects an EXTERNAL rotation (a
23
+ * sibling tab, a server `Set-Cookie`, or a cookie clear), mark this tab's
24
+ * history cache stale. The history cache is not state-keyed, so the value
25
+ * rotation alone does not reach it. No broadcast, no prefetch clear, no
26
+ * re-rotation — the value already changed externally.
27
+ */
28
+ export function registerNavigationStore(store: NavigationStore): void {
29
+ registeredStore = store;
30
+ setRangoStateObserver(() => {
31
+ registeredStore?.markHistoryCacheStale();
32
+ });
33
+ }
34
+
35
+ /** The active navigation store, or null before boot has registered it. */
36
+ export function getRegisteredStore(): NavigationStore | null {
37
+ return registeredStore;
38
+ }