@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.140

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 (460) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +432 -7
  3. package/dist/bin/rango.js +2073 -213
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +7258 -2714
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +140 -67
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +329 -0
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +487 -0
  12. package/skills/caching/SKILL.md +357 -25
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +246 -0
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +16 -10
  19. package/skills/document-cache/SKILL.md +87 -62
  20. package/skills/fonts/SKILL.md +6 -4
  21. package/skills/handler-use/SKILL.md +364 -0
  22. package/skills/hooks/SKILL.md +557 -79
  23. package/skills/host-router/SKILL.md +320 -0
  24. package/skills/i18n/SKILL.md +276 -0
  25. package/skills/intercept/SKILL.md +207 -15
  26. package/skills/layout/SKILL.md +146 -6
  27. package/skills/links/SKILL.md +304 -25
  28. package/skills/loader/SKILL.md +616 -54
  29. package/skills/middleware/SKILL.md +217 -37
  30. package/skills/migrate-nextjs/SKILL.md +611 -0
  31. package/skills/migrate-react-router/SKILL.md +927 -0
  32. package/skills/mime-routes/SKILL.md +42 -11
  33. package/skills/observability/SKILL.md +194 -0
  34. package/skills/parallel/SKILL.md +284 -3
  35. package/skills/ppr/SKILL.md +426 -0
  36. package/skills/prerender/SKILL.md +437 -52
  37. package/skills/rango/SKILL.md +369 -22
  38. package/skills/react-compiler/SKILL.md +168 -0
  39. package/skills/response-routes/SKILL.md +263 -121
  40. package/skills/route/SKILL.md +350 -21
  41. package/skills/router-setup/SKILL.md +246 -33
  42. package/skills/scripts/SKILL.md +179 -0
  43. package/skills/server-actions/SKILL.md +775 -0
  44. package/skills/shell-manifest/SKILL.md +185 -0
  45. package/skills/streams-and-websockets/SKILL.md +283 -0
  46. package/skills/tailwind/SKILL.md +27 -3
  47. package/skills/testing/SKILL.md +126 -222
  48. package/skills/testing/bindings.md +103 -0
  49. package/skills/testing/cache-prerender.md +127 -0
  50. package/skills/testing/client-components.md +124 -0
  51. package/skills/testing/e2e-parity.md +125 -0
  52. package/skills/testing/flight.md +91 -0
  53. package/skills/testing/handles.md +131 -0
  54. package/skills/testing/loader.md +128 -0
  55. package/skills/testing/middleware.md +99 -0
  56. package/skills/testing/render-handler.md +122 -0
  57. package/skills/testing/response-routes.md +95 -0
  58. package/skills/testing/reverse-and-types.md +85 -0
  59. package/skills/testing/server-actions.md +107 -0
  60. package/skills/testing/server-tree.md +128 -0
  61. package/skills/testing/setup.md +123 -0
  62. package/skills/theme/SKILL.md +9 -8
  63. package/skills/typesafety/SKILL.md +532 -103
  64. package/skills/use-cache/SKILL.md +367 -0
  65. package/skills/vercel/SKILL.md +128 -0
  66. package/skills/view-transitions/SKILL.md +337 -0
  67. package/src/__augment-tests__/augment.ts +81 -0
  68. package/src/__augment-tests__/augmented.check.ts +116 -0
  69. package/src/__internal.ts +77 -44
  70. package/src/bin/rango.ts +312 -15
  71. package/src/browser/action-coordinator.ts +114 -0
  72. package/src/browser/action-fence.ts +47 -0
  73. package/src/browser/app-shell.ts +39 -0
  74. package/src/browser/app-version.ts +14 -0
  75. package/src/browser/connection-warmup.ts +134 -0
  76. package/src/browser/cookie-name.ts +140 -0
  77. package/src/browser/event-controller.ts +293 -202
  78. package/src/browser/history-state.ts +101 -0
  79. package/src/browser/index.ts +3 -3
  80. package/src/browser/intercept-utils.ts +52 -0
  81. package/src/browser/invalidate-client-cache.ts +52 -0
  82. package/src/browser/link-interceptor.ts +24 -4
  83. package/src/browser/logging.ts +11 -0
  84. package/src/browser/merge-segment-loaders.ts +20 -12
  85. package/src/browser/navigation-bridge.ts +385 -576
  86. package/src/browser/navigation-client.ts +245 -75
  87. package/src/browser/navigation-store-handle.ts +38 -0
  88. package/src/browser/navigation-store.ts +184 -118
  89. package/src/browser/navigation-transaction.ts +247 -0
  90. package/src/browser/network-error-handler.ts +88 -0
  91. package/src/browser/partial-update.ts +412 -364
  92. package/src/browser/prefetch/cache.ts +359 -0
  93. package/src/browser/prefetch/fetch.ts +452 -0
  94. package/src/browser/prefetch/observer.ts +65 -0
  95. package/src/browser/prefetch/policy.ts +48 -0
  96. package/src/browser/prefetch/queue.ts +209 -0
  97. package/src/browser/prefetch/resource-ready.ts +77 -0
  98. package/src/browser/rango-state.ts +194 -0
  99. package/src/browser/react/Link.tsx +275 -68
  100. package/src/browser/react/NavigationProvider.tsx +265 -109
  101. package/src/browser/react/ScrollRestoration.tsx +10 -6
  102. package/src/browser/react/context.ts +11 -0
  103. package/src/browser/react/filter-segment-order.ts +70 -0
  104. package/src/browser/react/index.ts +0 -48
  105. package/src/browser/react/location-state-shared.ts +272 -60
  106. package/src/browser/react/location-state.ts +90 -20
  107. package/src/browser/react/mount-context.ts +6 -1
  108. package/src/browser/react/nonce-context.ts +23 -0
  109. package/src/browser/react/shallow-equal.ts +27 -0
  110. package/src/browser/react/use-action.ts +35 -66
  111. package/src/browser/react/use-handle.ts +39 -126
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +39 -13
  114. package/src/browser/react/use-navigation.ts +53 -69
  115. package/src/browser/react/use-params.ts +75 -0
  116. package/src/browser/react/use-pathname.ts +47 -0
  117. package/src/browser/react/use-reverse.ts +106 -0
  118. package/src/browser/react/use-router.ts +98 -0
  119. package/src/browser/react/use-search-params.ts +51 -0
  120. package/src/browser/react/use-segments.ts +72 -99
  121. package/src/browser/response-adapter.ts +164 -0
  122. package/src/browser/rsc-router.tsx +300 -72
  123. package/src/browser/scroll-restoration.ts +138 -50
  124. package/src/browser/segment-reconciler.ts +243 -0
  125. package/src/browser/segment-structure-assert.ts +17 -1
  126. package/src/browser/server-action-bridge.ts +668 -613
  127. package/src/browser/types.ts +223 -51
  128. package/src/browser/validate-redirect-origin.ts +56 -0
  129. package/src/build/collect-fallback-refs.ts +107 -0
  130. package/src/build/generate-manifest.ts +252 -161
  131. package/src/build/generate-route-types.ts +41 -1038
  132. package/src/build/index.ts +12 -7
  133. package/src/build/prefix-tree-utils.ts +123 -0
  134. package/src/build/route-trie.ts +225 -42
  135. package/src/build/route-types/ast-helpers.ts +25 -0
  136. package/src/build/route-types/ast-route-extraction.ts +105 -0
  137. package/src/build/route-types/codegen.ts +113 -0
  138. package/src/build/route-types/include-resolution.ts +812 -0
  139. package/src/build/route-types/param-extraction.ts +51 -0
  140. package/src/build/route-types/per-module-writer.ts +144 -0
  141. package/src/build/route-types/router-processing.ts +695 -0
  142. package/src/build/route-types/scan-filter.ts +85 -0
  143. package/src/build/route-types/source-scan.ts +216 -0
  144. package/src/build/runtime-discovery.ts +223 -0
  145. package/src/cache/background-task.ts +34 -0
  146. package/src/cache/cache-error.ts +104 -0
  147. package/src/cache/cache-key-utils.ts +60 -0
  148. package/src/cache/cache-policy.ts +199 -0
  149. package/src/cache/cache-runtime.ts +525 -0
  150. package/src/cache/cache-scope.ts +298 -332
  151. package/src/cache/cache-tag.ts +103 -0
  152. package/src/cache/cf/cf-base64.ts +33 -0
  153. package/src/cache/cf/cf-cache-constants.ts +127 -0
  154. package/src/cache/cf/cf-cache-store.ts +2500 -158
  155. package/src/cache/cf/cf-cache-types.ts +349 -0
  156. package/src/cache/cf/cf-kv-utils.ts +46 -0
  157. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  158. package/src/cache/cf/index.ts +17 -17
  159. package/src/cache/document-cache.ts +199 -92
  160. package/src/cache/handle-capture.ts +81 -0
  161. package/src/cache/handle-snapshot.ts +111 -0
  162. package/src/cache/index.ts +29 -35
  163. package/src/cache/memory-segment-store.ts +363 -30
  164. package/src/cache/profile-registry.ts +88 -0
  165. package/src/cache/read-through-swr.ts +178 -0
  166. package/src/cache/segment-codec.ts +248 -0
  167. package/src/cache/shell-cache.ts +386 -0
  168. package/src/cache/tag-invalidation.ts +230 -0
  169. package/src/cache/taint.ts +153 -0
  170. package/src/cache/types.ts +156 -211
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1102 -0
  173. package/src/client.rsc.tsx +43 -21
  174. package/src/client.tsx +131 -347
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +109 -0
  177. package/src/component-utils.ts +23 -4
  178. package/src/components/DefaultDocument.tsx +13 -3
  179. package/src/context-var.ts +168 -0
  180. package/src/debug.ts +19 -9
  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 +106 -10
  186. package/src/escape-script.ts +52 -0
  187. package/src/handle.ts +110 -35
  188. package/src/handles/MetaTags.tsx +83 -59
  189. package/src/handles/Scripts.tsx +183 -0
  190. package/src/handles/breadcrumbs.ts +93 -0
  191. package/src/handles/deferred-resolution.ts +127 -0
  192. package/src/handles/is-thenable.ts +18 -0
  193. package/src/handles/meta.ts +44 -53
  194. package/src/handles/script.ts +244 -0
  195. package/src/host/cookie-handler.ts +20 -65
  196. package/src/host/errors.ts +21 -30
  197. package/src/host/index.ts +13 -9
  198. package/src/host/pattern-matcher.ts +50 -79
  199. package/src/host/router.ts +151 -121
  200. package/src/host/testing.ts +45 -32
  201. package/src/host/types.ts +52 -11
  202. package/src/host/utils.ts +2 -2
  203. package/src/href-client.ts +192 -57
  204. package/src/index.rsc.ts +177 -35
  205. package/src/index.ts +255 -71
  206. package/src/internal-debug.ts +9 -2
  207. package/src/loader-store.ts +500 -0
  208. package/src/loader.rsc.ts +31 -99
  209. package/src/loader.ts +30 -12
  210. package/src/missing-id-error.ts +68 -0
  211. package/src/outlet-context.ts +1 -1
  212. package/src/outlet-provider.tsx +41 -0
  213. package/src/prerender/param-hash.ts +16 -14
  214. package/src/prerender/store.ts +121 -21
  215. package/src/prerender.ts +460 -26
  216. package/src/redirect-origin.ts +100 -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 +198 -128
  221. package/src/root-error-boundary.tsx +42 -48
  222. package/src/route-content-wrapper.tsx +22 -77
  223. package/src/route-definition/dsl-helpers.ts +1116 -0
  224. package/src/route-definition/helper-factories.ts +88 -0
  225. package/src/route-definition/helpers-types.ts +505 -0
  226. package/src/route-definition/index.ts +54 -0
  227. package/src/route-definition/redirect.ts +134 -0
  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-definition.ts +1 -1481
  231. package/src/route-map-builder.ts +82 -144
  232. package/src/route-name.ts +53 -0
  233. package/src/route-types.ts +71 -45
  234. package/src/router/basename.ts +14 -0
  235. package/src/router/content-negotiation.ts +263 -0
  236. package/src/router/debug-manifest.ts +72 -0
  237. package/src/router/error-handling.ts +54 -27
  238. package/src/router/find-match.ts +245 -0
  239. package/src/router/handler-context.ts +377 -125
  240. package/src/router/instrument.ts +350 -0
  241. package/src/router/intercept-resolution.ts +59 -28
  242. package/src/router/lazy-includes.ts +254 -0
  243. package/src/router/loader-resolution.ts +421 -157
  244. package/src/router/logging.ts +106 -6
  245. package/src/router/manifest.ts +131 -57
  246. package/src/router/match-api.ts +167 -246
  247. package/src/router/match-context.ts +4 -24
  248. package/src/router/match-handlers.ts +440 -0
  249. package/src/router/match-middleware/background-revalidation.ts +117 -93
  250. package/src/router/match-middleware/cache-lookup.ts +297 -150
  251. package/src/router/match-middleware/cache-store.ts +123 -51
  252. package/src/router/match-middleware/intercept-resolution.ts +44 -43
  253. package/src/router/match-middleware/segment-resolution.ts +64 -22
  254. package/src/router/match-pipelines.ts +11 -87
  255. package/src/router/match-result.ts +121 -50
  256. package/src/router/metrics.ts +219 -28
  257. package/src/router/middleware-types.ts +93 -0
  258. package/src/router/middleware.ts +505 -441
  259. package/src/router/navigation-snapshot.ts +133 -0
  260. package/src/router/params-util.ts +23 -0
  261. package/src/router/parse-pattern.ts +115 -0
  262. package/src/router/pattern-matching.ts +311 -142
  263. package/src/router/prefetch-cache-ttl.ts +51 -0
  264. package/src/router/prefetch-limits.ts +37 -0
  265. package/src/router/prerender-match.ts +547 -0
  266. package/src/router/preview-match.ts +102 -0
  267. package/src/router/request-classification.ts +278 -0
  268. package/src/router/revalidation.ts +203 -62
  269. package/src/router/route-snapshot.ts +246 -0
  270. package/src/router/router-context.ts +45 -48
  271. package/src/router/router-interfaces.ts +554 -0
  272. package/src/router/router-options.ts +779 -0
  273. package/src/router/router-registry.ts +21 -0
  274. package/src/router/segment-resolution/fresh.ts +772 -0
  275. package/src/router/segment-resolution/helpers.ts +348 -0
  276. package/src/router/segment-resolution/loader-cache.ts +250 -0
  277. package/src/router/segment-resolution/loader-mask.ts +44 -0
  278. package/src/router/segment-resolution/revalidation.ts +1331 -0
  279. package/src/router/segment-resolution/static-store.ts +81 -0
  280. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  281. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  282. package/src/router/segment-resolution.ts +25 -1354
  283. package/src/router/segment-wrappers.ts +292 -0
  284. package/src/router/state-cookie-name.ts +33 -0
  285. package/src/router/substitute-pattern-params.ts +75 -0
  286. package/src/router/telemetry-otel.ts +261 -0
  287. package/src/router/telemetry.ts +377 -0
  288. package/src/router/timeout.ts +128 -0
  289. package/src/router/tracing.ts +206 -0
  290. package/src/router/trie-matching.ts +240 -61
  291. package/src/router/types.ts +23 -70
  292. package/src/router/url-params.ts +57 -0
  293. package/src/router.ts +781 -2378
  294. package/src/rsc/full-payload.ts +70 -0
  295. package/src/rsc/handler-context.ts +46 -0
  296. package/src/rsc/handler.ts +905 -1142
  297. package/src/rsc/helpers.ts +275 -19
  298. package/src/rsc/index.ts +2 -25
  299. package/src/rsc/json-route-result.ts +38 -0
  300. package/src/rsc/loader-fetch.ts +305 -0
  301. package/src/rsc/manifest-init.ts +77 -0
  302. package/src/rsc/nonce.ts +14 -0
  303. package/src/rsc/origin-guard.ts +155 -0
  304. package/src/rsc/progressive-enhancement.ts +502 -0
  305. package/src/rsc/redirect-guard.ts +99 -0
  306. package/src/rsc/response-cache-serve.ts +238 -0
  307. package/src/rsc/response-error.ts +104 -0
  308. package/src/rsc/response-route-handler.ts +257 -0
  309. package/src/rsc/rsc-rendering.ts +337 -0
  310. package/src/rsc/runtime-warnings.ts +55 -0
  311. package/src/rsc/server-action.ts +522 -0
  312. package/src/rsc/shell-capture.ts +439 -0
  313. package/src/rsc/ssr-setup.ts +144 -0
  314. package/src/rsc/transition-gate.ts +89 -0
  315. package/src/rsc/types.ts +95 -12
  316. package/src/runtime-env.ts +18 -0
  317. package/src/search-params.ts +99 -82
  318. package/src/segment-content-promise.ts +67 -0
  319. package/src/segment-loader-promise.ts +149 -0
  320. package/src/segment-system.tsx +349 -134
  321. package/src/serialize.ts +243 -0
  322. package/src/server/context.ts +452 -85
  323. package/src/server/cookie-parse.ts +32 -0
  324. package/src/server/cookie-store.ts +310 -0
  325. package/src/server/fetchable-loader-store.ts +11 -6
  326. package/src/server/handle-store.ts +123 -42
  327. package/src/server/live.ts +130 -0
  328. package/src/server/loader-registry.ts +51 -100
  329. package/src/server/request-context.ts +842 -157
  330. package/src/server.ts +15 -8
  331. package/src/ssr/index.tsx +412 -136
  332. package/src/ssr/ssr-root.tsx +228 -0
  333. package/src/static-handler.ts +45 -18
  334. package/src/testing/cache-status.ts +162 -0
  335. package/src/testing/collect-handle.ts +46 -0
  336. package/src/testing/dispatch.ts +701 -0
  337. package/src/testing/dom.entry.ts +22 -0
  338. package/src/testing/e2e/fixture.ts +188 -0
  339. package/src/testing/e2e/index.ts +128 -0
  340. package/src/testing/e2e/matchers.ts +35 -0
  341. package/src/testing/e2e/page-helpers.ts +272 -0
  342. package/src/testing/e2e/parity.ts +387 -0
  343. package/src/testing/e2e/server.ts +195 -0
  344. package/src/testing/flight-matchers.ts +97 -0
  345. package/src/testing/flight-normalize.ts +11 -0
  346. package/src/testing/flight-runtime.d.ts +57 -0
  347. package/src/testing/flight-tree.ts +682 -0
  348. package/src/testing/flight.entry.ts +52 -0
  349. package/src/testing/flight.ts +257 -0
  350. package/src/testing/generated-routes.ts +199 -0
  351. package/src/testing/index.ts +105 -0
  352. package/src/testing/internal/context.ts +371 -0
  353. package/src/testing/internal/flight-client-globals.ts +30 -0
  354. package/src/testing/internal/seed-vars.ts +54 -0
  355. package/src/testing/render-handler.ts +357 -0
  356. package/src/testing/render-route.tsx +584 -0
  357. package/src/testing/run-loader.ts +385 -0
  358. package/src/testing/run-middleware.ts +205 -0
  359. package/src/testing/run-transition-when.ts +164 -0
  360. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  361. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  362. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  363. package/src/testing/vitest-stubs/version.ts +5 -0
  364. package/src/testing/vitest.ts +305 -0
  365. package/src/theme/ThemeProvider.tsx +40 -72
  366. package/src/theme/ThemeScript.tsx +12 -14
  367. package/src/theme/constants.ts +57 -15
  368. package/src/theme/index.ts +3 -20
  369. package/src/theme/theme-context.ts +5 -35
  370. package/src/theme/theme-script.ts +43 -39
  371. package/src/theme/use-theme.ts +0 -3
  372. package/src/types/boundaries.ts +123 -0
  373. package/src/types/cache-types.ts +207 -0
  374. package/src/types/error-types.ts +132 -0
  375. package/src/types/global-namespace.ts +113 -0
  376. package/src/types/handler-context.ts +839 -0
  377. package/src/types/index.ts +81 -0
  378. package/src/types/loader-types.ts +212 -0
  379. package/src/types/request-scope.ts +112 -0
  380. package/src/types/route-config.ts +138 -0
  381. package/src/types/route-entry.ts +114 -0
  382. package/src/types/segments.ts +271 -0
  383. package/src/types.ts +1 -1795
  384. package/src/urls/include-helper.ts +162 -0
  385. package/src/urls/include-provider.ts +71 -0
  386. package/src/urls/index.ts +43 -0
  387. package/src/urls/path-helper-types.ts +413 -0
  388. package/src/urls/path-helper.ts +275 -0
  389. package/src/urls/pattern-types.ts +124 -0
  390. package/src/urls/response-types.ts +109 -0
  391. package/src/urls/type-extraction.ts +316 -0
  392. package/src/urls/urls-function.ts +80 -0
  393. package/src/urls.ts +1 -1341
  394. package/src/use-loader.tsx +406 -141
  395. package/src/vercel/index.ts +11 -0
  396. package/src/vercel/tracing.ts +88 -0
  397. package/src/vite/debug.ts +185 -0
  398. package/src/vite/discovery/bundle-postprocess.ts +182 -0
  399. package/src/vite/discovery/discover-routers.ts +389 -0
  400. package/src/vite/discovery/discovery-errors.ts +255 -0
  401. package/src/vite/discovery/gate-state.ts +171 -0
  402. package/src/vite/discovery/prerender-collection.ts +467 -0
  403. package/src/vite/discovery/route-types-writer.ts +214 -0
  404. package/src/vite/discovery/self-gen-tracking.ts +73 -0
  405. package/src/vite/discovery/state.ts +161 -0
  406. package/src/vite/discovery/virtual-module-codegen.ts +183 -0
  407. package/src/vite/index.ts +23 -2255
  408. package/src/vite/inject-client-debug.ts +36 -0
  409. package/src/vite/plugin-types.ts +303 -0
  410. package/src/vite/plugins/cjs-to-esm.ts +90 -0
  411. package/src/vite/plugins/client-ref-dedup.ts +120 -0
  412. package/src/vite/plugins/client-ref-hashing.ts +118 -0
  413. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  414. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  415. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  416. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
  417. package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
  418. package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
  419. package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
  420. package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
  421. package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
  422. package/src/vite/plugins/expose-ids/types.ts +45 -0
  423. package/src/vite/plugins/expose-internal-ids.ts +805 -0
  424. package/src/vite/plugins/performance-tracks.ts +89 -0
  425. package/src/vite/plugins/refresh-cmd.ts +127 -0
  426. package/src/vite/plugins/use-cache-transform.ts +313 -0
  427. package/src/vite/plugins/vercel-output.ts +384 -0
  428. package/src/vite/plugins/version-injector.ts +94 -0
  429. package/src/vite/plugins/version-plugin.ts +263 -0
  430. package/src/vite/plugins/virtual-entries.ts +234 -0
  431. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  432. package/src/vite/rango.ts +560 -0
  433. package/src/vite/router-discovery.ts +1638 -0
  434. package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
  435. package/src/vite/utils/banner.ts +36 -0
  436. package/src/vite/utils/bundle-analysis.ts +132 -0
  437. package/src/vite/utils/client-chunks.ts +184 -0
  438. package/src/vite/utils/directive-prologue.ts +40 -0
  439. package/src/vite/utils/forward-user-plugins.ts +171 -0
  440. package/src/vite/utils/manifest-utils.ts +15 -0
  441. package/src/vite/utils/package-resolution.ts +89 -0
  442. package/src/vite/utils/prerender-utils.ts +249 -0
  443. package/src/vite/utils/shared-utils.ts +269 -0
  444. package/CLAUDE.md +0 -43
  445. package/dist/vite/index.named-routes.gen.ts +0 -103
  446. package/src/browser/lru-cache.ts +0 -69
  447. package/src/browser/react/use-client-cache.ts +0 -56
  448. package/src/browser/request-controller.ts +0 -164
  449. package/src/browser/shallow.ts +0 -35
  450. package/src/cache/memory-store.ts +0 -253
  451. package/src/handles/index.ts +0 -6
  452. package/src/href-context.ts +0 -33
  453. package/src/network-error-thrower.tsx +0 -21
  454. package/src/router.gen.ts +0 -6
  455. package/src/static-handler.gen.ts +0 -5
  456. package/src/urls.gen.ts +0 -8
  457. package/src/vite/expose-internal-ids.ts +0 -1167
  458. package/src/vite/package-resolution.ts +0 -125
  459. package/src/vite/virtual-entries.ts +0 -114
  460. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -5,12 +5,29 @@ import type {
5
5
  RscPayload,
6
6
  RscBrowserDependencies,
7
7
  } from "./types.js";
8
- import { NetworkError, isNetworkError } from "../errors.js";
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";
15
+ import { getRangoState } from "./rango-state.js";
16
+ import { isActionFenceActive } from "./action-fence.js";
17
+ import {
18
+ extractRscHeaderUrl,
19
+ emptyResponse,
20
+ handleReloadHeader,
21
+ teeWithCompletion,
22
+ isForeignRouterId,
23
+ } from "./response-adapter.js";
24
+ import {
25
+ buildPrefetchKey,
26
+ buildSourceKey,
27
+ consumeInflightPrefetch,
28
+ consumePrefetch,
29
+ type DecodedPrefetch,
30
+ } from "./prefetch/cache.js";
14
31
 
15
32
  /**
16
33
  * Create a navigation client for fetching RSC payloads
@@ -18,32 +35,25 @@ import {
18
35
  * The client handles building URLs with RSC parameters and
19
36
  * deserializing the response using the RSC runtime.
20
37
  *
38
+ * Checks the in-memory prefetch cache before making a network request.
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.
43
+ *
21
44
  * @param deps - RSC browser dependencies (createFromFetch)
22
45
  * @returns NavigationClient instance
23
- *
24
- * @example
25
- * ```typescript
26
- * import { createFromFetch } from "@vitejs/plugin-rsc/browser";
27
- *
28
- * const client = createNavigationClient({ createFromFetch });
29
- *
30
- * const payload = await client.fetchPartial({
31
- * targetUrl: "/shop/products",
32
- * segmentIds: ["root", "shop"],
33
- * previousUrl: "/",
34
- * });
35
- * ```
36
46
  */
37
47
  export function createNavigationClient(
38
48
  deps: Pick<RscBrowserDependencies, "createFromFetch">,
39
49
  ): NavigationClient {
40
-
41
50
  return {
42
51
  /**
43
52
  * Fetch a partial RSC payload for navigation
44
53
  *
45
- * Sends current segment IDs to the server so it can determine
46
- * which segments need to be re-rendered (diff).
54
+ * First checks the in-memory prefetch cache for a matching entry.
55
+ * If found, uses the cached response instantly. Otherwise sends
56
+ * current segment IDs to the server for diff-based rendering.
47
57
  *
48
58
  * @param options - Fetch options
49
59
  * @returns RSC payload with segments and metadata, plus stream completion promise
@@ -59,6 +69,7 @@ export function createNavigationClient(
59
69
  staleRevalidation,
60
70
  interceptSourceUrl,
61
71
  version,
72
+ routerId,
62
73
  hmr,
63
74
  } = options;
64
75
 
@@ -75,7 +86,8 @@ export function createNavigationClient(
75
86
  });
76
87
  }
77
88
 
78
- // Build fetch URL with partial rendering params
89
+ // Build fetch URL with partial rendering params (used for both
90
+ // cache key lookup and actual fetch if cache misses)
79
91
  const fetchUrl = new URL(targetUrl, window.location.origin);
80
92
  fetchUrl.searchParams.set("_rsc_partial", "true");
81
93
  fetchUrl.searchParams.set("_rsc_segments", segmentIds.join(","));
@@ -85,85 +97,239 @@ export function createNavigationClient(
85
97
  if (version) {
86
98
  fetchUrl.searchParams.set("_rsc_v", version);
87
99
  }
100
+ if (routerId) {
101
+ fetchUrl.searchParams.set("_rsc_rid", routerId);
102
+ }
88
103
 
89
- if (tx) {
90
- browserDebugLog(tx, "fetching", {
91
- path: `${fetchUrl.pathname}${fetchUrl.search}`,
92
- });
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.
111
+ // Skip cache for stale revalidation (needs fresh data), HMR (needs
112
+ // fresh modules), and intercept contexts (source-dependent responses).
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
+ }
93
135
  }
94
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
+ }
95
147
  // Track when the stream completes
96
148
  let resolveStreamComplete: () => void;
97
149
  const streamComplete = new Promise<void>((resolve) => {
98
150
  resolveStreamComplete = resolve;
99
151
  });
100
152
 
101
- // Create a response promise that tracks stream completion
102
- const responsePromise = fetch(fetchUrl, {
103
- headers: {
104
- "X-RSC-Router-Client-Path": previousUrl,
105
- ...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
106
- ...(interceptSourceUrl && {
107
- "X-RSC-Router-Intercept-Source": interceptSourceUrl,
108
- }),
109
- ...(hmr && { "X-RSC-HMR": "1" }),
110
- },
111
- signal,
112
- }).then((response) => {
113
- // Check for version mismatch - server wants us to reload
114
- const reloadUrl = response.headers.get("X-RSC-Reload");
115
- if (reloadUrl) {
153
+ /**
154
+ * Validate RSC control headers on any response (fresh, cached, or
155
+ * in-flight). Handles version-mismatch reloads and server redirects.
156
+ * Returns the response unchanged when no control header is present.
157
+ */
158
+ const validateRscHeaders = (
159
+ response: Response,
160
+ source: string,
161
+ ): Response | Promise<Response> => {
162
+ // Version mismatch — server wants a full page reload
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;
174
+
175
+ // Server-side redirect without state: the server returned 204 with
176
+ // X-RSC-Redirect instead of a 3xx (which fetch would auto-follow
177
+ // to a URL rendering full HTML). Throw ServerRedirect so the
178
+ // navigation bridge catches it and re-navigates with _skipCache.
179
+ const redirect = extractRscHeaderUrl(response, "X-RSC-Redirect");
180
+ if (redirect === "blocked") {
181
+ resolveStreamComplete();
182
+ return emptyResponse();
183
+ }
184
+ if (redirect) {
116
185
  if (tx) {
117
- browserDebugLog(tx, "version mismatch, reloading", { reloadUrl });
186
+ browserDebugLog(tx, `server redirect (${source})`, {
187
+ redirectUrl: redirect.url,
188
+ });
118
189
  }
119
- window.location.href = reloadUrl;
120
- // Return a never-resolving promise to prevent further processing
121
- return new Promise<Response>(() => {});
190
+ resolveStreamComplete();
191
+ throw new ServerRedirect(redirect.url, undefined);
122
192
  }
123
193
 
124
- if (!response.body) {
125
- // No body means stream is already complete
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
+ }
126
202
  resolveStreamComplete();
127
- return response;
203
+ window.location.href = targetUrl;
204
+ return new Promise<Response>(() => {});
128
205
  }
129
206
 
130
- // Tee the stream: one for RSC runtime, one for tracking completion
131
- const [rscStream, trackingStream] = response.body.tee();
132
-
133
- // Consume the tracking stream to detect when it closes
134
- (async () => {
135
- const reader = trackingStream.getReader();
207
+ return response;
208
+ };
136
209
 
137
- // Cancel tracking if navigation is aborted
138
- const onAbort = reader.cancel.bind(reader);
139
- signal?.addEventListener("abort", onAbort, { once: true });
210
+ /** Start a fresh navigation fetch (no cache / inflight hit). */
211
+ const doFreshFetch = (): Promise<Response> => {
212
+ if (tx) {
213
+ browserDebugLog(tx, "fetching", {
214
+ path: `${fetchUrl.pathname}${fetchUrl.search}`,
215
+ });
216
+ }
140
217
 
141
- try {
142
- while (true) {
143
- const { done } = await reader.read();
144
- if (done) break;
145
- }
146
- } finally {
147
- signal?.removeEventListener("abort", onAbort);
148
- reader.releaseLock();
149
- if (tx) {
150
- browserDebugLog(tx, "stream complete");
151
- }
152
- resolveStreamComplete();
153
- }
154
- })();
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 }),
224
+ headers: {
225
+ "X-RSC-Router-Client-Path": previousUrl,
226
+ "X-Rango-State": getRangoState(),
227
+ ...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
228
+ ...(interceptSourceUrl && {
229
+ "X-RSC-Router-Intercept-Source": interceptSourceUrl,
230
+ }),
231
+ ...(hmr && { "X-RSC-HMR": "1" }),
232
+ },
233
+ signal,
234
+ }).then((response) => {
235
+ const validated = validateRscHeaders(response, "fetch");
236
+ if (validated instanceof Promise) return validated;
155
237
 
156
- // Return response with the RSC stream
157
- return new Response(rscStream, {
158
- headers: response.headers,
159
- status: response.status,
160
- statusText: response.statusText,
238
+ return teeWithCompletion(
239
+ validated,
240
+ () => {
241
+ if (tx) browserDebugLog(tx, "stream complete");
242
+ resolveStreamComplete();
243
+ },
244
+ signal,
245
+ );
161
246
  });
247
+ };
248
+
249
+ // A warm prefetch hit returns its eagerly-decoded payload directly: the
250
+ // route's chunks were imported during the prefetch, so this click runs
251
+ // no decode and no network. Only the fresh path runs createFromFetch and
252
+ // resolves the local streamComplete (via doFreshFetch's teeWithCompletion
253
+ // and the control-header short-circuits in validateRscHeaders).
254
+ const freshResult = (): {
255
+ payload: Promise<RscPayload>;
256
+ streamComplete: Promise<void>;
257
+ } => ({
258
+ payload: deps.createFromFetch<RscPayload>(doFreshFetch()),
259
+ streamComplete,
162
260
  });
163
261
 
262
+ let payloadPromise: Promise<RscPayload>;
263
+ let streamCompletePromise: Promise<void>;
264
+ // True only for a prefetch-cache hit whose stream had already fully drained
265
+ // (complete === true). A still-streaming hit and the fresh path stay false,
266
+ // so only a fully-warmed prefetch commits in a transition (no fallback flash).
267
+ let fullyPrefetched = false;
268
+
269
+ if (cachedEntry) {
270
+ if (tx) {
271
+ browserDebugLog(tx, "prefetch cache hit (warm)", {
272
+ key: hitKey,
273
+ wildcard: hitKey === wildcardKey,
274
+ });
275
+ }
276
+ payloadPromise = cachedEntry.payload;
277
+ streamCompletePromise = cachedEntry.streamComplete;
278
+ // Only a hit whose stream already fully drained is "fully prefetched";
279
+ // a still-streaming hit must keep streaming its fallbacks like a cold load.
280
+ fullyPrefetched = cachedEntry.complete;
281
+ } else if (inflightEntryPromise) {
282
+ if (tx) {
283
+ browserDebugLog(tx, "reusing inflight prefetch", {
284
+ key: hitKey,
285
+ wildcard: hitKey === wildcardKey,
286
+ });
287
+ }
288
+ const adoptedViaWildcard = hitKey === wildcardKey;
289
+ const entry = await inflightEntryPromise;
290
+ if (!entry) {
291
+ if (tx) {
292
+ browserDebugLog(tx, "inflight prefetch unavailable, refetching");
293
+ }
294
+ ({ payload: payloadPromise, streamComplete: streamCompletePromise } =
295
+ freshResult());
296
+ } else if (adoptedViaWildcard && entry.scope === "source") {
297
+ // A wildcard-adopted inflight that turned out source-scoped was
298
+ // built for a different source page. Discard and refetch.
299
+ if (tx) {
300
+ browserDebugLog(
301
+ tx,
302
+ "wildcard inflight turned out source-scoped, refetching",
303
+ );
304
+ }
305
+ ({ payload: payloadPromise, streamComplete: streamCompletePromise } =
306
+ freshResult());
307
+ } else {
308
+ payloadPromise = entry.payload;
309
+ streamCompletePromise = entry.streamComplete;
310
+ // Adopted inflight is normally still streaming (false), but read the
311
+ // flag in case it completed between publish and adoption.
312
+ fullyPrefetched = entry.complete;
313
+ }
314
+ } else {
315
+ ({ payload: payloadPromise, streamComplete: streamCompletePromise } =
316
+ freshResult());
317
+ }
318
+
164
319
  try {
165
- // Deserialize RSC payload
166
- const payload = await deps.createFromFetch<RscPayload>(responsePromise);
320
+ // [VT-DIAG] Gated behind INTERNAL_RANGO_DEBUG. Times how long the RSC
321
+ // payload ROOT takes to resolve: ~full-stream duration means the root
322
+ // model is not flushed early (server/runtime buffering, e.g. wrangler
323
+ // dev gzip); fast means the block, if any, is downstream in render.
324
+ const vtDebugStart = isBrowserDebugEnabled() ? performance.now() : 0;
325
+ const payload = await payloadPromise;
326
+ if (isBrowserDebugEnabled()) {
327
+ debugLog("[VT-DIAG] payloadResolved", {
328
+ ms: Math.round(performance.now() - vtDebugStart),
329
+ isPartial: payload.metadata?.isPartial,
330
+ });
331
+ }
332
+
167
333
  if (tx) {
168
334
  browserDebugLog(tx, "response received", {
169
335
  isPartial: payload.metadata?.isPartial,
@@ -171,7 +337,11 @@ export function createNavigationClient(
171
337
  diffCount: payload.metadata?.diff?.length ?? 0,
172
338
  });
173
339
  }
174
- return { payload, streamComplete };
340
+ return {
341
+ payload,
342
+ streamComplete: streamCompletePromise,
343
+ fullyPrefetched,
344
+ };
175
345
  } catch (error) {
176
346
  // Convert network-level errors to NetworkError for proper handling
177
347
  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
+ }