@rangojs/router 0.0.0-experimental.79 → 0.0.0-experimental.7c7e4327

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 (440) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +301 -797
  3. package/dist/bin/rango.js +603 -145
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3750 -1160
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +96 -24
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +85 -6
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +228 -33
  12. package/skills/caching/SKILL.md +336 -19
  13. package/skills/catalog.json +271 -0
  14. package/skills/comparison/SKILL.md +50 -0
  15. package/skills/comparison/agents/openai.yaml +4 -0
  16. package/skills/comparison/references/framework-comparison.md +837 -0
  17. package/skills/composability/SKILL.md +110 -4
  18. package/skills/css/SKILL.md +76 -0
  19. package/skills/debug-manifest/SKILL.md +5 -3
  20. package/skills/defer-hydration/SKILL.md +235 -0
  21. package/skills/document-cache/SKILL.md +87 -56
  22. package/skills/fonts/SKILL.md +1 -1
  23. package/skills/handler-use/SKILL.md +12 -10
  24. package/skills/hooks/SKILL.md +73 -691
  25. package/skills/hooks/data.md +273 -0
  26. package/skills/hooks/handle-and-actions.md +103 -0
  27. package/skills/hooks/navigation.md +110 -0
  28. package/skills/hooks/outlets.md +41 -0
  29. package/skills/hooks/state.md +228 -0
  30. package/skills/hooks/urls.md +135 -0
  31. package/skills/host-router/SKILL.md +129 -27
  32. package/skills/i18n/SKILL.md +276 -0
  33. package/skills/intercept/SKILL.md +75 -19
  34. package/skills/layout/SKILL.md +40 -19
  35. package/skills/links/SKILL.md +247 -17
  36. package/skills/loader/SKILL.md +248 -10
  37. package/skills/middleware/SKILL.md +25 -13
  38. package/skills/migrate-nextjs/SKILL.md +205 -20
  39. package/skills/migrate-react-router/SKILL.md +59 -670
  40. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  41. package/skills/migrate-react-router/component-migration.md +196 -0
  42. package/skills/migrate-react-router/data-and-actions.md +225 -0
  43. package/skills/migrate-react-router/route-mapping.md +271 -0
  44. package/skills/mime-routes/SKILL.md +29 -2
  45. package/skills/observability/SKILL.md +202 -0
  46. package/skills/parallel/SKILL.md +40 -10
  47. package/skills/ppr/SKILL.md +616 -0
  48. package/skills/prerender/SKILL.md +72 -60
  49. package/skills/rango/SKILL.md +318 -26
  50. package/skills/react-compiler/SKILL.md +168 -0
  51. package/skills/response-routes/SKILL.md +138 -49
  52. package/skills/route/SKILL.md +117 -9
  53. package/skills/router-setup/SKILL.md +44 -9
  54. package/skills/scripts/SKILL.md +179 -0
  55. package/skills/server-actions/SKILL.md +776 -0
  56. package/skills/shell-manifest/SKILL.md +185 -0
  57. package/skills/streams-and-websockets/SKILL.md +283 -0
  58. package/skills/tailwind/SKILL.md +28 -4
  59. package/skills/testing/SKILL.md +130 -0
  60. package/skills/testing/bindings.md +103 -0
  61. package/skills/testing/cache-prerender.md +127 -0
  62. package/skills/testing/client-components.md +124 -0
  63. package/skills/testing/e2e-parity.md +125 -0
  64. package/skills/testing/flight.md +91 -0
  65. package/skills/testing/handles.md +131 -0
  66. package/skills/testing/loader.md +128 -0
  67. package/skills/testing/middleware.md +99 -0
  68. package/skills/testing/render-handler.md +122 -0
  69. package/skills/testing/response-routes.md +95 -0
  70. package/skills/testing/reverse-and-types.md +85 -0
  71. package/skills/testing/server-actions.md +107 -0
  72. package/skills/testing/server-tree.md +128 -0
  73. package/skills/testing/setup.md +123 -0
  74. package/skills/theme/SKILL.md +1 -1
  75. package/skills/typesafety/SKILL.md +45 -626
  76. package/skills/typesafety/env-and-bindings.md +254 -0
  77. package/skills/typesafety/generated-files-and-cli.md +335 -0
  78. package/skills/typesafety/params-and-search.md +153 -0
  79. package/skills/typesafety/route-types.md +209 -0
  80. package/skills/use-cache/SKILL.md +74 -15
  81. package/skills/vercel/SKILL.md +128 -0
  82. package/skills/view-transitions/SKILL.md +337 -0
  83. package/src/__augment-tests__/augment.ts +81 -0
  84. package/src/__augment-tests__/augmented.check.ts +116 -0
  85. package/src/__internal.ts +0 -65
  86. package/src/browser/action-coordinator.ts +53 -36
  87. package/src/browser/action-fence.ts +47 -0
  88. package/src/browser/app-shell.ts +39 -0
  89. package/src/browser/connection-warmup.ts +134 -0
  90. package/src/browser/cookie-name.ts +140 -0
  91. package/src/browser/event-controller.ts +252 -158
  92. package/src/browser/history-state.ts +21 -0
  93. package/src/browser/index.ts +3 -3
  94. package/src/browser/invalidate-client-cache.ts +52 -0
  95. package/src/browser/logging.ts +28 -0
  96. package/src/browser/merge-segment-loaders.ts +6 -4
  97. package/src/browser/navigation-bridge.ts +94 -25
  98. package/src/browser/navigation-client.ts +144 -79
  99. package/src/browser/navigation-store-handle.ts +38 -0
  100. package/src/browser/navigation-store.ts +161 -73
  101. package/src/browser/navigation-transaction.ts +9 -59
  102. package/src/browser/network-error-handler.ts +34 -7
  103. package/src/browser/partial-update.ts +183 -144
  104. package/src/browser/prefetch/cache.ts +242 -77
  105. package/src/browser/prefetch/fetch.ts +325 -69
  106. package/src/browser/prefetch/queue.ts +61 -12
  107. package/src/browser/rango-state.ts +158 -76
  108. package/src/browser/react/Link.tsx +58 -20
  109. package/src/browser/react/NavigationProvider.tsx +202 -120
  110. package/src/browser/react/ScrollRestoration.tsx +10 -6
  111. package/src/browser/react/filter-segment-order.ts +66 -7
  112. package/src/browser/react/index.ts +0 -48
  113. package/src/browser/react/location-state-shared.ts +178 -8
  114. package/src/browser/react/location-state.ts +39 -14
  115. package/src/browser/react/use-action.ts +6 -15
  116. package/src/browser/react/use-handle.ts +17 -14
  117. package/src/browser/react/use-href.tsx +8 -1
  118. package/src/browser/react/use-link-status.ts +33 -8
  119. package/src/browser/react/use-navigation.ts +32 -7
  120. package/src/browser/react/use-params.ts +20 -10
  121. package/src/browser/react/use-reverse.ts +106 -0
  122. package/src/browser/react/use-router.ts +25 -3
  123. package/src/browser/react/use-search-params.ts +0 -5
  124. package/src/browser/react/use-segments.ts +11 -21
  125. package/src/browser/response-adapter.ts +99 -8
  126. package/src/browser/rsc-router.tsx +145 -28
  127. package/src/browser/scroll-restoration.ts +37 -22
  128. package/src/browser/segment-reconciler.ts +31 -21
  129. package/src/browser/segment-structure-assert.ts +2 -2
  130. package/src/browser/server-action-bridge.ts +236 -65
  131. package/src/browser/types.ts +102 -9
  132. package/src/browser/validate-redirect-origin.ts +43 -16
  133. package/src/build/collect-fallback-refs.ts +107 -0
  134. package/src/build/generate-manifest.ts +203 -154
  135. package/src/build/generate-route-types.ts +3 -1
  136. package/src/build/index.ts +11 -3
  137. package/src/build/prefix-tree-utils.ts +123 -0
  138. package/src/build/route-trie.ts +152 -21
  139. package/src/build/route-types/ast-route-extraction.ts +15 -8
  140. package/src/build/route-types/codegen.ts +16 -5
  141. package/src/build/route-types/include-resolution.ts +456 -62
  142. package/src/build/route-types/param-extraction.ts +6 -3
  143. package/src/build/route-types/per-module-writer.ts +22 -6
  144. package/src/build/route-types/router-processing.ts +128 -51
  145. package/src/build/route-types/scan-filter.ts +1 -1
  146. package/src/build/route-types/source-scan.ts +216 -0
  147. package/src/build/runtime-discovery.ts +13 -21
  148. package/src/cache/cache-error.ts +104 -0
  149. package/src/cache/cache-key-utils.ts +58 -13
  150. package/src/cache/cache-policy.ts +108 -34
  151. package/src/cache/cache-runtime.ts +421 -58
  152. package/src/cache/cache-scope.ts +187 -96
  153. package/src/cache/cache-tag.ts +149 -0
  154. package/src/cache/cf/cf-base64.ts +33 -0
  155. package/src/cache/cf/cf-cache-constants.ts +127 -0
  156. package/src/cache/cf/cf-cache-store.ts +2202 -372
  157. package/src/cache/cf/cf-cache-types.ts +349 -0
  158. package/src/cache/cf/cf-kv-utils.ts +46 -0
  159. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  160. package/src/cache/cf/index.ts +6 -16
  161. package/src/cache/document-cache.ts +126 -41
  162. package/src/cache/handle-snapshot.ts +70 -0
  163. package/src/cache/index.ts +23 -20
  164. package/src/cache/memory-segment-store.ts +243 -37
  165. package/src/cache/profile-registry.ts +46 -31
  166. package/src/cache/read-through-swr.ts +56 -12
  167. package/src/cache/segment-codec.ts +13 -21
  168. package/src/cache/shell-snapshot.ts +417 -0
  169. package/src/cache/tag-invalidation.ts +230 -0
  170. package/src/cache/types.ts +180 -99
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1127 -0
  173. package/src/client.rsc.tsx +41 -21
  174. package/src/client.tsx +33 -61
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +108 -0
  177. package/src/component-utils.ts +19 -0
  178. package/src/components/DefaultDocument.tsx +8 -2
  179. package/src/context-var.ts +18 -6
  180. package/src/decode-loader-results.ts +52 -0
  181. package/src/defer.ts +185 -0
  182. package/src/deps/ssr.ts +0 -1
  183. package/src/encode-kv.ts +49 -0
  184. package/src/errors.ts +30 -4
  185. package/src/escape-script.ts +52 -0
  186. package/src/handle.ts +67 -37
  187. package/src/handles/MetaTags.tsx +24 -53
  188. package/src/handles/Scripts.tsx +183 -0
  189. package/src/handles/breadcrumbs.ts +35 -8
  190. package/src/handles/deferred-resolution.ts +127 -0
  191. package/src/handles/is-thenable.ts +18 -0
  192. package/src/handles/meta.ts +14 -40
  193. package/src/handles/script.ts +244 -0
  194. package/src/host/cookie-handler.ts +9 -60
  195. package/src/host/errors.ts +13 -22
  196. package/src/host/index.ts +9 -2
  197. package/src/host/pattern-matcher.ts +23 -52
  198. package/src/host/router.ts +107 -99
  199. package/src/host/testing.ts +40 -27
  200. package/src/host/types.ts +37 -4
  201. package/src/host/utils.ts +1 -1
  202. package/src/href-client.ts +137 -22
  203. package/src/index.rsc.ts +97 -12
  204. package/src/index.ts +98 -14
  205. package/src/internal-debug.ts +11 -10
  206. package/src/loader-store.ts +500 -0
  207. package/src/loader.rsc.ts +20 -13
  208. package/src/loader.ts +12 -11
  209. package/src/missing-id-error.ts +68 -0
  210. package/src/outlet-context.ts +1 -1
  211. package/src/outlet-provider.tsx +1 -5
  212. package/src/prerender/param-hash.ts +16 -16
  213. package/src/prerender/store.ts +32 -37
  214. package/src/prerender.ts +78 -10
  215. package/src/redirect-origin.ts +114 -0
  216. package/src/regex-escape.ts +8 -0
  217. package/src/render-error-thrower.tsx +20 -0
  218. package/src/response-utils.ts +62 -0
  219. package/src/reverse.ts +65 -39
  220. package/src/root-error-boundary.tsx +1 -19
  221. package/src/route-content-wrapper.tsx +19 -77
  222. package/src/route-definition/dsl-helpers.ts +304 -309
  223. package/src/route-definition/helper-factories.ts +28 -140
  224. package/src/route-definition/helpers-types.ts +87 -59
  225. package/src/route-definition/index.ts +1 -2
  226. package/src/route-definition/redirect.ts +44 -11
  227. package/src/route-definition/resolve-handler-use.ts +12 -1
  228. package/src/route-definition/use-item-types.ts +29 -0
  229. package/src/route-map-builder.ts +41 -20
  230. package/src/route-types.ts +19 -46
  231. package/src/router/basename.ts +14 -0
  232. package/src/router/content-negotiation.ts +73 -25
  233. package/src/router/error-handling.ts +45 -18
  234. package/src/router/find-match.ts +129 -30
  235. package/src/router/handler-context.ts +27 -42
  236. package/src/router/instrument.ts +355 -0
  237. package/src/router/intercept-resolution.ts +39 -20
  238. package/src/router/lazy-includes.ts +82 -59
  239. package/src/router/loader-resolution.ts +167 -72
  240. package/src/router/logging.ts +0 -6
  241. package/src/router/manifest.ts +74 -40
  242. package/src/router/match-api.ts +80 -55
  243. package/src/router/match-context.ts +0 -22
  244. package/src/router/match-handlers.ts +211 -165
  245. package/src/router/match-middleware/background-revalidation.ts +40 -24
  246. package/src/router/match-middleware/cache-lookup.ts +159 -285
  247. package/src/router/match-middleware/cache-store.ts +64 -52
  248. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  249. package/src/router/match-middleware/segment-resolution.ts +0 -22
  250. package/src/router/match-pipelines.ts +1 -42
  251. package/src/router/match-result.ts +69 -79
  252. package/src/router/metrics.ts +0 -34
  253. package/src/router/middleware-types.ts +7 -134
  254. package/src/router/middleware.ts +298 -172
  255. package/src/router/navigation-snapshot.ts +7 -56
  256. package/src/router/params-util.ts +23 -0
  257. package/src/router/parse-pattern.ts +115 -0
  258. package/src/router/pattern-matching.ts +181 -150
  259. package/src/router/prefetch-cache-ttl.ts +51 -0
  260. package/src/router/prefetch-limits.ts +37 -0
  261. package/src/router/prerender-match.ts +112 -67
  262. package/src/router/preview-match.ts +6 -2
  263. package/src/router/request-classification.ts +50 -69
  264. package/src/router/revalidation.ts +123 -73
  265. package/src/router/route-snapshot.ts +14 -3
  266. package/src/router/router-context.ts +6 -29
  267. package/src/router/router-interfaces.ts +115 -36
  268. package/src/router/router-options.ts +166 -5
  269. package/src/router/router-registry.ts +2 -5
  270. package/src/router/segment-resolution/fresh.ts +131 -86
  271. package/src/router/segment-resolution/helpers.ts +86 -6
  272. package/src/router/segment-resolution/loader-cache.ts +139 -39
  273. package/src/router/segment-resolution/loader-mask.ts +67 -0
  274. package/src/router/segment-resolution/loader-snapshot.ts +251 -0
  275. package/src/router/segment-resolution/revalidation.ts +272 -320
  276. package/src/router/segment-resolution/static-store.ts +19 -5
  277. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  278. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  279. package/src/router/segment-resolution.ts +5 -1
  280. package/src/router/segment-wrappers.ts +6 -5
  281. package/src/router/state-cookie-name.ts +33 -0
  282. package/src/router/substitute-pattern-params.ts +75 -0
  283. package/src/router/telemetry-otel.ts +160 -200
  284. package/src/router/telemetry.ts +105 -20
  285. package/src/router/timeout.ts +0 -20
  286. package/src/router/tracing.ts +215 -0
  287. package/src/router/trie-matching.ts +171 -59
  288. package/src/router/types.ts +9 -63
  289. package/src/router/url-params.ts +57 -0
  290. package/src/router.ts +157 -71
  291. package/src/rsc/full-payload.ts +70 -0
  292. package/src/rsc/handler-context.ts +3 -2
  293. package/src/rsc/handler.ts +291 -217
  294. package/src/rsc/helpers.ts +168 -46
  295. package/src/rsc/index.ts +2 -5
  296. package/src/rsc/json-route-result.ts +38 -0
  297. package/src/rsc/loader-fetch.ts +114 -38
  298. package/src/rsc/manifest-init.ts +29 -42
  299. package/src/rsc/nonce.ts +10 -1
  300. package/src/rsc/origin-guard.ts +39 -25
  301. package/src/rsc/progressive-enhancement.ts +124 -13
  302. package/src/rsc/redirect-guard.ts +100 -0
  303. package/src/rsc/response-cache-serve.ts +238 -0
  304. package/src/rsc/response-error.ts +79 -12
  305. package/src/rsc/response-route-handler.ts +99 -189
  306. package/src/rsc/rsc-rendering.ts +421 -76
  307. package/src/rsc/runtime-warnings.ts +23 -10
  308. package/src/rsc/server-action.ts +282 -116
  309. package/src/rsc/shell-capture.ts +1158 -0
  310. package/src/rsc/shell-serve.ts +150 -0
  311. package/src/rsc/ssr-setup.ts +16 -0
  312. package/src/rsc/transition-gate.ts +89 -0
  313. package/src/rsc/types.ts +53 -5
  314. package/src/runtime-env.ts +18 -0
  315. package/src/search-params.ts +35 -30
  316. package/src/segment-loader-promise.ts +49 -4
  317. package/src/segment-system.tsx +350 -149
  318. package/src/serialize.ts +243 -0
  319. package/src/server/context.ts +208 -51
  320. package/src/server/cookie-parse.ts +32 -0
  321. package/src/server/cookie-store.ts +152 -5
  322. package/src/server/handle-store.ts +21 -38
  323. package/src/server/loader-registry.ts +33 -42
  324. package/src/server/request-context.ts +395 -176
  325. package/src/ssr/index.tsx +458 -178
  326. package/src/ssr/ssr-root.tsx +228 -0
  327. package/src/static-handler.ts +10 -13
  328. package/src/testing/cache-status.ts +162 -0
  329. package/src/testing/collect-handle.ts +46 -0
  330. package/src/testing/dispatch.ts +813 -0
  331. package/src/testing/dom.entry.ts +22 -0
  332. package/src/testing/e2e/fixture.ts +188 -0
  333. package/src/testing/e2e/index.ts +128 -0
  334. package/src/testing/e2e/matchers.ts +35 -0
  335. package/src/testing/e2e/page-helpers.ts +272 -0
  336. package/src/testing/e2e/parity.ts +387 -0
  337. package/src/testing/e2e/server.ts +195 -0
  338. package/src/testing/flight-matchers.ts +97 -0
  339. package/src/testing/flight-normalize.ts +11 -0
  340. package/src/testing/flight-runtime.d.ts +57 -0
  341. package/src/testing/flight-tree.ts +682 -0
  342. package/src/testing/flight.entry.ts +52 -0
  343. package/src/testing/flight.ts +257 -0
  344. package/src/testing/generated-routes.ts +199 -0
  345. package/src/testing/index.ts +105 -0
  346. package/src/testing/internal/context.ts +371 -0
  347. package/src/testing/internal/flight-client-globals.ts +30 -0
  348. package/src/testing/internal/seed-vars.ts +54 -0
  349. package/src/testing/render-handler.ts +357 -0
  350. package/src/testing/render-route.tsx +584 -0
  351. package/src/testing/run-loader.ts +385 -0
  352. package/src/testing/run-middleware.ts +205 -0
  353. package/src/testing/run-transition-when.ts +164 -0
  354. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  355. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  356. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  357. package/src/testing/vitest-stubs/version.ts +5 -0
  358. package/src/testing/vitest.ts +305 -0
  359. package/src/theme/ThemeProvider.tsx +56 -84
  360. package/src/theme/ThemeScript.tsx +7 -9
  361. package/src/theme/constants.ts +52 -13
  362. package/src/theme/index.ts +0 -7
  363. package/src/theme/theme-context.ts +1 -5
  364. package/src/theme/theme-script.ts +22 -21
  365. package/src/theme/use-theme.ts +0 -3
  366. package/src/types/boundaries.ts +0 -35
  367. package/src/types/cache-types.ts +13 -4
  368. package/src/types/error-types.ts +30 -90
  369. package/src/types/global-namespace.ts +54 -41
  370. package/src/types/handler-context.ts +110 -62
  371. package/src/types/index.ts +3 -10
  372. package/src/types/loader-types.ts +11 -9
  373. package/src/types/request-scope.ts +112 -0
  374. package/src/types/route-config.ts +20 -52
  375. package/src/types/route-entry.ts +0 -6
  376. package/src/types/segments.ts +135 -14
  377. package/src/urls/include-helper.ts +19 -64
  378. package/src/urls/include-provider.ts +71 -0
  379. package/src/urls/index.ts +2 -11
  380. package/src/urls/path-helper-types.ts +63 -17
  381. package/src/urls/path-helper.ts +22 -106
  382. package/src/urls/pattern-types.ts +72 -19
  383. package/src/urls/response-types.ts +22 -29
  384. package/src/urls/type-extraction.ts +98 -154
  385. package/src/urls/urls-function.ts +1 -19
  386. package/src/use-loader.tsx +292 -107
  387. package/src/vercel/index.ts +11 -0
  388. package/src/vercel/tracing.ts +88 -0
  389. package/src/vite/debug.ts +185 -0
  390. package/src/vite/discovery/bundle-postprocess.ts +8 -7
  391. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  392. package/src/vite/discovery/discover-routers.ts +127 -86
  393. package/src/vite/discovery/discovery-errors.ts +255 -0
  394. package/src/vite/discovery/gate-state.ts +171 -0
  395. package/src/vite/discovery/prerender-collection.ts +96 -68
  396. package/src/vite/discovery/route-types-writer.ts +40 -84
  397. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  398. package/src/vite/discovery/state.ts +45 -1
  399. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  400. package/src/vite/index.ts +4 -0
  401. package/src/vite/inject-client-debug.ts +88 -0
  402. package/src/vite/plugin-types.ts +210 -10
  403. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  404. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  405. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  406. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  407. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  408. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  409. package/src/vite/plugins/expose-action-id.ts +48 -95
  410. package/src/vite/plugins/expose-id-utils.ts +88 -55
  411. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  412. package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
  413. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  414. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  415. package/src/vite/plugins/expose-internal-ids.ts +505 -486
  416. package/src/vite/plugins/performance-tracks.ts +26 -25
  417. package/src/vite/plugins/refresh-cmd.ts +1 -1
  418. package/src/vite/plugins/use-cache-transform.ts +73 -83
  419. package/src/vite/plugins/vercel-output.ts +384 -0
  420. package/src/vite/plugins/version-injector.ts +40 -29
  421. package/src/vite/plugins/version-plugin.ts +37 -40
  422. package/src/vite/plugins/virtual-entries.ts +138 -27
  423. package/src/vite/rango.ts +236 -138
  424. package/src/vite/router-discovery.ts +927 -136
  425. package/src/vite/utils/ast-handler-extract.ts +26 -35
  426. package/src/vite/utils/banner.ts +1 -1
  427. package/src/vite/utils/bundle-analysis.ts +10 -15
  428. package/src/vite/utils/client-chunks.ts +184 -0
  429. package/src/vite/utils/directive-prologue.ts +40 -0
  430. package/src/vite/utils/forward-user-plugins.ts +171 -0
  431. package/src/vite/utils/manifest-utils.ts +4 -59
  432. package/src/vite/utils/package-resolution.ts +20 -52
  433. package/src/vite/utils/prerender-utils.ts +71 -43
  434. package/src/vite/utils/shared-utils.ts +142 -43
  435. package/src/browser/action-response-classifier.ts +0 -99
  436. package/src/browser/react/use-client-cache.ts +0 -58
  437. package/src/browser/shallow.ts +0 -40
  438. package/src/handles/index.ts +0 -7
  439. package/src/network-error-thrower.tsx +0 -23
  440. package/src/router/middleware-cookies.ts +0 -55
@@ -33,10 +33,116 @@ import type { ErrorBoundaryHandler, NotFoundBoundaryHandler } from "../types";
33
33
  import type { MiddlewareFn } from "./middleware.js";
34
34
  import {
35
35
  type TelemetrySink,
36
+ type CacheSegmentSignal,
36
37
  safeEmit,
37
38
  resolveSink,
38
39
  getRequestId,
40
+ buildCacheSignalSegments,
39
41
  } from "./telemetry.js";
42
+ import { _getRequestContext } from "../server/request-context.js";
43
+
44
+ /**
45
+ * Per-call telemetry lifecycle emitter for match()/matchPartial(). Each method
46
+ * reproduces the exact event object the two functions used to emit inline and is
47
+ * gated on the same per-call flag (`enabled` = the request's `emitTelemetry`), so
48
+ * a PPR shell-capture run (enabled=false) emits nothing while a foreground run
49
+ * emits byte-identical events. Extracted so the two transactions can't drift;
50
+ * pinned by thrown-response-telemetry.test.ts and
51
+ * shell-capture-telemetry-suppression.test.ts.
52
+ */
53
+ interface LifecycleEmitter {
54
+ start(): void;
55
+ end(segmentCount: number, cacheHit: boolean, status?: number): void;
56
+ cacheDecision(
57
+ routeKey: string,
58
+ state: {
59
+ cacheHit: boolean;
60
+ cacheSource?: "runtime" | "prerender";
61
+ shouldRevalidate?: boolean;
62
+ },
63
+ segments: CacheSegmentSignal[],
64
+ ): void;
65
+ error(error: Error, phase: string): void;
66
+ }
67
+
68
+ function createLifecycleEmitter(args: {
69
+ enabled: boolean;
70
+ sink: TelemetrySink;
71
+ requestId: string | undefined;
72
+ method: string;
73
+ pathname: string;
74
+ transaction: "match" | "matchPartial";
75
+ isPartial: boolean;
76
+ matchStart: number;
77
+ }): LifecycleEmitter {
78
+ return {
79
+ start(): void {
80
+ if (!args.enabled) return;
81
+ safeEmit(args.sink, {
82
+ type: "request.start",
83
+ timestamp: args.matchStart,
84
+ requestId: args.requestId,
85
+ method: args.method,
86
+ pathname: args.pathname,
87
+ transaction: args.transaction,
88
+ isPartial: args.isPartial,
89
+ });
90
+ },
91
+ end(segmentCount: number, cacheHit: boolean, status?: number): void {
92
+ if (!args.enabled) return;
93
+ safeEmit(args.sink, {
94
+ type: "request.end",
95
+ timestamp: performance.now(),
96
+ requestId: args.requestId,
97
+ method: args.method,
98
+ pathname: args.pathname,
99
+ transaction: args.transaction,
100
+ durationMs: performance.now() - args.matchStart,
101
+ segmentCount,
102
+ cacheHit,
103
+ // Only a thrown-Response short-circuit passes a status; a normal render
104
+ // completion omits it (the Response is built after match()).
105
+ ...(status !== undefined && { status }),
106
+ });
107
+ },
108
+ cacheDecision(
109
+ routeKey: string,
110
+ state: {
111
+ cacheHit: boolean;
112
+ cacheSource?: "runtime" | "prerender";
113
+ shouldRevalidate?: boolean;
114
+ },
115
+ segments: CacheSegmentSignal[],
116
+ ): void {
117
+ if (!args.enabled) return;
118
+ safeEmit(args.sink, {
119
+ type: "cache.decision",
120
+ timestamp: performance.now(),
121
+ requestId: args.requestId,
122
+ pathname: args.pathname,
123
+ routeKey,
124
+ hit: state.cacheHit,
125
+ shouldRevalidate: !!state.shouldRevalidate,
126
+ source: state.cacheSource,
127
+ segments,
128
+ });
129
+ },
130
+ error(error: Error, phase: string): void {
131
+ if (!args.enabled) return;
132
+ safeEmit(args.sink, {
133
+ type: "request.error",
134
+ timestamp: performance.now(),
135
+ requestId: args.requestId,
136
+ method: args.method,
137
+ pathname: args.pathname,
138
+ transaction: args.transaction,
139
+ error,
140
+ phase,
141
+ durationMs: performance.now() - args.matchStart,
142
+ });
143
+ },
144
+ };
145
+ }
40
146
 
41
147
  export interface MatchHandlerDeps<TEnv = any> {
42
148
  buildRouterContext: () => RouterContext<TEnv>;
@@ -51,6 +157,12 @@ export interface MatchHandlerDeps<TEnv = any> {
51
157
  isAction: boolean,
52
158
  ) => { intercept: InterceptEntry; entry: EntryData } | null;
53
159
  telemetry?: TelemetrySink;
160
+ /**
161
+ * DEVELOPMENT/TEST ONLY gate for the X-Rango-Cache debug header. When true,
162
+ * match/matchPartial stash a coarse route-level cache signal on the request
163
+ * context for the response-finalization path to emit. Default off.
164
+ */
165
+ cacheSignalEnabled?: boolean;
54
166
  }
55
167
 
56
168
  export interface MatchHandlers<TEnv = any> {
@@ -80,20 +192,6 @@ export interface MatchHandlers<TEnv = any> {
80
192
  negotiated?: boolean;
81
193
  manifestEntry?: EntryData;
82
194
  } | null>;
83
- createMatchContextForFull: (
84
- request: Request,
85
- env: TEnv,
86
- ) => Promise<MatchContext<TEnv> | { type: "redirect"; redirectUrl: string }>;
87
- createMatchContextForPartial: (
88
- request: Request,
89
- env: TEnv,
90
- actionContext?: {
91
- actionId?: string;
92
- actionUrl?: URL;
93
- actionResult?: any;
94
- formData?: FormData;
95
- },
96
- ) => Promise<MatchContext<TEnv> | null>;
97
195
  }
98
196
 
99
197
  /**
@@ -113,6 +211,20 @@ export function createMatchHandlers<TEnv = any>(
113
211
  } = deps;
114
212
  const hasTelemetry = !!deps.telemetry;
115
213
  const telemetry = resolveSink(deps.telemetry);
214
+ const cacheSignalEnabled = !!deps.cacheSignalEnabled;
215
+ const buildSignal = (
216
+ routeKey: string,
217
+ state: {
218
+ cacheHit: boolean;
219
+ cacheSource?: "runtime" | "prerender";
220
+ shouldRevalidate?: boolean;
221
+ },
222
+ ): CacheSegmentSignal[] => buildCacheSignalSegments(routeKey, state);
223
+ const recordSignalIfEnabled = (segments: CacheSegmentSignal[]): void => {
224
+ if (!cacheSignalEnabled) return;
225
+ const reqCtx = _getRequestContext();
226
+ if (reqCtx) reqCtx._cacheSignal = segments;
227
+ };
116
228
 
117
229
  async function createMatchContextForFull(
118
230
  request: Request,
@@ -145,57 +257,49 @@ export function createMatchHandlers<TEnv = any>(
145
257
  );
146
258
  }
147
259
 
148
- /**
149
- * Match request and return segments (document/SSR requests)
150
- *
151
- * Uses generator middleware pipeline for clean separation of concerns:
152
- * - cache-lookup: Check cache first
153
- * - segment-resolution: Resolve segments on cache miss
154
- * - cache-store: Store results in cache
155
- * - background-revalidation: SWR revalidation
156
- */
157
260
  async function match(request: Request, env: TEnv): Promise<MatchResult> {
158
- const requestId = hasTelemetry ? getRequestId(request) : undefined;
261
+ // Silence telemetry for the PPR background shell capture: it re-runs match()
262
+ // under a derived request context flagged _shellCaptureRun (shell-capture.ts
263
+ // attemptCapture), re-using the foreground Request — a second request.start/
264
+ // cache.decision/request.end stamped with the same WeakMap-keyed requestId
265
+ // would double-count dashboards. Derived here (inside the capture's active
266
+ // request-context ALS) so the read sees the derived context, not module state.
267
+ const emitTelemetry =
268
+ hasTelemetry && !_getRequestContext()?._shellCaptureRun;
269
+ const requestId = emitTelemetry ? getRequestId(request) : undefined;
159
270
  return runWithRouterLogContext({ request, transaction: "match" }, () => {
160
271
  const routerCtx = buildRouterContext();
272
+ // Also mute in-pipeline observeEvent emitters (revalidation.decision,
273
+ // cache-lookup's cache.decision) which read routerCtx.telemetry.
274
+ if (!emitTelemetry) routerCtx.telemetry = undefined;
161
275
  routerCtx.requestId = requestId;
162
276
  return runWithRouterContext(routerCtx, async () =>
163
277
  withRouterLogScope("match", async () => {
164
278
  const matchStart = performance.now();
165
- const pathname = new URL(request.url).pathname;
166
- if (hasTelemetry) {
167
- safeEmit(telemetry, {
168
- type: "request.start",
169
- timestamp: matchStart,
170
- requestId,
171
- method: request.method,
172
- pathname,
173
- transaction: "match",
174
- isPartial: false,
175
- });
176
- }
279
+ const pathname =
280
+ _getRequestContext()?.url?.pathname ??
281
+ new URL(request.url).pathname;
282
+ const emitter = createLifecycleEmitter({
283
+ enabled: emitTelemetry,
284
+ sink: telemetry,
285
+ requestId,
286
+ method: request.method,
287
+ pathname,
288
+ transaction: "match",
289
+ isPartial: false,
290
+ matchStart,
291
+ });
292
+ emitter.start();
177
293
 
178
294
  const result = await createMatchContextForFull(request, env);
179
295
 
180
- // Handle redirect case
181
296
  if ("type" in result && result.type === "redirect") {
182
- if (hasTelemetry) {
183
- safeEmit(telemetry, {
184
- type: "request.end",
185
- timestamp: performance.now(),
186
- requestId,
187
- method: request.method,
188
- pathname,
189
- transaction: "match",
190
- durationMs: performance.now() - matchStart,
191
- segmentCount: 0,
192
- cacheHit: false,
193
- });
194
- }
297
+ emitter.end(0, false);
195
298
  return {
196
299
  segments: [],
197
300
  matched: [],
198
301
  diff: [],
302
+ resolvedIds: [],
199
303
  params: {},
200
304
  redirect: result.redirectUrl,
201
305
  };
@@ -207,48 +311,29 @@ export function createMatchHandlers<TEnv = any>(
207
311
  const state = createPipelineState();
208
312
  const pipeline = createMatchPartialPipeline(ctx, state);
209
313
  const matchResult = await collectMatchResult(pipeline, ctx, state);
210
- if (hasTelemetry) {
211
- safeEmit(telemetry, {
212
- type: "cache.decision",
213
- timestamp: performance.now(),
214
- requestId,
215
- pathname,
216
- routeKey: ctx.routeKey,
217
- hit: state.cacheHit,
218
- shouldRevalidate: !!state.shouldRevalidate,
219
- source: state.cacheSource,
220
- });
221
- safeEmit(telemetry, {
222
- type: "request.end",
223
- timestamp: performance.now(),
224
- requestId,
225
- method: request.method,
226
- pathname,
227
- transaction: "match",
228
- durationMs: performance.now() - matchStart,
229
- segmentCount: matchResult.segments.length,
230
- cacheHit: state.cacheHit,
231
- });
314
+ if (hasTelemetry || cacheSignalEnabled) {
315
+ const signalSegments = buildSignal(ctx.routeKey, state);
316
+ recordSignalIfEnabled(signalSegments);
317
+ emitter.cacheDecision(ctx.routeKey, state, signalSegments);
232
318
  }
319
+ emitter.end(matchResult.segments.length, state.cacheHit);
233
320
  return matchResult;
234
321
  } catch (error) {
235
- if (hasTelemetry) {
236
- const errorObj =
237
- error instanceof Error ? error : new Error(String(error));
238
- safeEmit(telemetry, {
239
- type: "request.error",
240
- timestamp: performance.now(),
241
- requestId,
242
- method: request.method,
243
- pathname,
244
- transaction: "match",
245
- error: errorObj,
246
- phase: error instanceof Response ? "redirect" : "routing",
247
- durationMs: performance.now() - matchStart,
248
- });
322
+ if (error instanceof Response) {
323
+ // A thrown Response (middleware short-circuit — redirect / auth
324
+ // gate) is a COMPLETED request from the consumer's seat, not an
325
+ // error: emit request.end (the same shape the non-thrown redirect
326
+ // result above already emits), never request.error with a
327
+ // synthetic "[object Response]" error. Rethrow so the caller
328
+ // drives the redirect. Carry the Response's status so a sink can
329
+ // tell a 3xx short-circuit from a 2xx completion.
330
+ emitter.end(0, false, error.status);
331
+ throw error;
249
332
  }
250
- if (error instanceof Response) throw error;
251
- // Report unhandled errors during full match pipeline
333
+ emitter.error(
334
+ error instanceof Error ? error : new Error(String(error)),
335
+ "routing",
336
+ );
252
337
  callOnError(error, "routing", {
253
338
  request,
254
339
  url: ctx.url,
@@ -283,42 +368,39 @@ export function createMatchHandlers<TEnv = any>(
283
368
  );
284
369
  }
285
370
 
286
- /**
287
- * Match partial request with revalidation
288
- *
289
- * Uses generator middleware pipeline for clean separation of concerns:
290
- * - cache-lookup: Check cache first
291
- * - segment-resolution: Resolve segments on cache miss
292
- * - intercept-resolution: Handle intercept routes
293
- * - cache-store: Store results in cache
294
- * - background-revalidation: SWR revalidation
295
- */
296
371
  async function matchPartial(
297
372
  request: Request,
298
373
  context: TEnv,
299
374
  actionContext?: ActionContext,
300
375
  ): Promise<MatchResult | null> {
301
- const partialRequestId = hasTelemetry ? getRequestId(request) : undefined;
376
+ // See match() above: the PPR shell capture re-runs matchPartial() under a
377
+ // _shellCaptureRun context and must stay invisible to the sink.
378
+ const emitTelemetry =
379
+ hasTelemetry && !_getRequestContext()?._shellCaptureRun;
380
+ const partialRequestId = emitTelemetry ? getRequestId(request) : undefined;
302
381
  return runWithRouterLogContext(
303
382
  { request, transaction: "matchPartial" },
304
383
  () => {
305
384
  const routerCtx = buildRouterContext();
385
+ if (!emitTelemetry) routerCtx.telemetry = undefined;
306
386
  routerCtx.requestId = partialRequestId;
307
387
  return runWithRouterContext(routerCtx, async () =>
308
388
  withRouterLogScope("matchPartial", async () => {
309
389
  const matchStart = performance.now();
310
- const pathname = new URL(request.url).pathname;
311
- if (hasTelemetry) {
312
- safeEmit(telemetry, {
313
- type: "request.start",
314
- timestamp: matchStart,
315
- requestId: partialRequestId,
316
- method: request.method,
317
- pathname,
318
- transaction: "matchPartial",
319
- isPartial: true,
320
- });
321
- }
390
+ const pathname =
391
+ _getRequestContext()?.url?.pathname ??
392
+ new URL(request.url).pathname;
393
+ const emitter = createLifecycleEmitter({
394
+ enabled: emitTelemetry,
395
+ sink: telemetry,
396
+ requestId: partialRequestId,
397
+ method: request.method,
398
+ pathname,
399
+ transaction: "matchPartial",
400
+ isPartial: true,
401
+ matchStart,
402
+ });
403
+ emitter.start();
322
404
 
323
405
  const ctx = await createMatchContextForPartial(
324
406
  request,
@@ -326,19 +408,7 @@ export function createMatchHandlers<TEnv = any>(
326
408
  actionContext,
327
409
  );
328
410
  if (!ctx) {
329
- if (hasTelemetry) {
330
- safeEmit(telemetry, {
331
- type: "request.end",
332
- timestamp: performance.now(),
333
- requestId: partialRequestId,
334
- method: request.method,
335
- pathname,
336
- transaction: "matchPartial",
337
- durationMs: performance.now() - matchStart,
338
- segmentCount: 0,
339
- cacheHit: false,
340
- });
341
- }
411
+ emitter.end(0, false);
342
412
  return null;
343
413
  }
344
414
 
@@ -362,50 +432,28 @@ export function createMatchHandlers<TEnv = any>(
362
432
  state,
363
433
  );
364
434
  flushRevalidationTrace();
365
- if (hasTelemetry) {
366
- safeEmit(telemetry, {
367
- type: "cache.decision",
368
- timestamp: performance.now(),
369
- requestId: partialRequestId,
370
- pathname,
371
- routeKey: ctx.routeKey,
372
- hit: state.cacheHit,
373
- shouldRevalidate: !!state.shouldRevalidate,
374
- source: state.cacheSource,
375
- });
376
- safeEmit(telemetry, {
377
- type: "request.end",
378
- timestamp: performance.now(),
379
- requestId: partialRequestId,
380
- method: request.method,
381
- pathname,
382
- transaction: "matchPartial",
383
- durationMs: performance.now() - matchStart,
384
- segmentCount: matchResult.segments.length,
385
- cacheHit: state.cacheHit,
386
- });
435
+ if (hasTelemetry || cacheSignalEnabled) {
436
+ const signalSegments = buildSignal(ctx.routeKey, state);
437
+ recordSignalIfEnabled(signalSegments);
438
+ emitter.cacheDecision(ctx.routeKey, state, signalSegments);
387
439
  }
440
+ emitter.end(matchResult.segments.length, state.cacheHit);
388
441
  return matchResult;
389
442
  } catch (error) {
390
443
  flushRevalidationTrace();
391
- if (hasTelemetry) {
392
- const errorObj =
393
- error instanceof Error ? error : new Error(String(error));
394
- const phase = actionContext ? "action" : "revalidation";
395
- safeEmit(telemetry, {
396
- type: "request.error",
397
- timestamp: performance.now(),
398
- requestId: partialRequestId,
399
- method: request.method,
400
- pathname,
401
- transaction: "matchPartial",
402
- error: errorObj,
403
- phase: error instanceof Response ? "redirect" : phase,
404
- durationMs: performance.now() - matchStart,
405
- });
444
+ if (error instanceof Response) {
445
+ // A thrown Response (middleware short-circuit — redirect / auth
446
+ // gate) is a COMPLETED request, not an error: emit request.end
447
+ // (parity with match()), never request.error. Rethrow so the
448
+ // caller drives the redirect. Carry the Response's status so a
449
+ // sink can tell a 3xx short-circuit from a 2xx completion.
450
+ emitter.end(0, false, error.status);
451
+ throw error;
406
452
  }
407
- if (error instanceof Response) throw error;
408
- // Report unhandled errors during partial match pipeline
453
+ emitter.error(
454
+ error instanceof Error ? error : new Error(String(error)),
455
+ actionContext ? "action" : "revalidation",
456
+ );
409
457
  callOnError(error, actionContext ? "action" : "revalidation", {
410
458
  request,
411
459
  url: ctx.url,
@@ -434,7 +482,5 @@ export function createMatchHandlers<TEnv = any>(
434
482
  matchPartial: matchPartial,
435
483
  matchError: matchError,
436
484
  previewMatch: previewMatch,
437
- createMatchContextForFull: createMatchContextForFull,
438
- createMatchContextForPartial: createMatchContextForPartial,
439
485
  };
440
486
  }
@@ -105,6 +105,10 @@ import { getRouterContext } from "../router-context.js";
105
105
  import type { GeneratorMiddleware } from "./cache-lookup.js";
106
106
  import { debugLog, debugWarn, getOrCreateRequestId } from "../logging.js";
107
107
  import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
108
+ import {
109
+ runWithRequestContext,
110
+ type RequestContext,
111
+ } from "../../server/request-context.js";
108
112
 
109
113
  /**
110
114
  * Creates background revalidation middleware
@@ -168,8 +172,6 @@ export function withBackgroundRevalidation<TEnv>(
168
172
  requestCtx._handleStore = createHandleStore();
169
173
 
170
174
  try {
171
- // Create fresh handler context and loader promises to avoid
172
- // reusing memoized results from the foreground pass
173
175
  const freshHandlerContext = createHandlerContext(
174
176
  ctx.matched.params,
175
177
  ctx.request,
@@ -185,32 +187,46 @@ export function withBackgroundRevalidation<TEnv>(
185
187
  const freshLoaderPromises = new Map<string, Promise<any>>();
186
188
  setupLoaderAccess(freshHandlerContext, freshLoaderPromises);
187
189
 
188
- // Resolve all segments fresh (without revalidation logic)
189
- // to ensure complete components for caching.
190
- // Skip DSL loaders they are never cached (cacheRoute filters them)
191
- // and are always resolved fresh on each request.
192
- const freshSegments = await ctx.Store.run(() =>
193
- resolveAllSegments(
194
- ctx.entries,
195
- ctx.routeKey,
196
- ctx.matched.params,
197
- freshHandlerContext,
198
- freshLoaderPromises,
199
- { skipLoaders: true },
200
- ),
190
+ // Re-establish the request-context ALS around the re-render. ctx.Store
191
+ // is a different ALS (DSL build context); on workerd a waitUntil task
192
+ // runs detached from the request's I/O context, so a handler/component
193
+ // that reads the ambient getRequestContext() during this background
194
+ // re-render would otherwise throw "called outside of a request context".
195
+ const freshSegments = await runWithRequestContext(
196
+ requestCtx as RequestContext<TEnv>,
197
+ () =>
198
+ ctx.Store.run(() =>
199
+ resolveAllSegments(
200
+ ctx.entries,
201
+ ctx.routeKey,
202
+ ctx.matched.params,
203
+ freshHandlerContext,
204
+ freshLoaderPromises,
205
+ { skipLoaders: true },
206
+ ),
207
+ ),
201
208
  );
202
209
 
203
- // Also resolve intercept segments fresh if applicable
204
210
  let freshInterceptSegments: ResolvedSegment[] = [];
205
211
  if (ctx.interceptResult) {
206
- freshInterceptSegments = await ctx.Store.run(() =>
207
- resolveInterceptEntry(
208
- ctx.interceptResult!.intercept,
209
- ctx.interceptResult!.entry,
210
- ctx.matched.params,
211
- freshHandlerContext,
212
- true,
213
- ),
212
+ freshInterceptSegments = await runWithRequestContext(
213
+ requestCtx as RequestContext<TEnv>,
214
+ () =>
215
+ ctx.Store.run(() =>
216
+ resolveInterceptEntry(
217
+ ctx.interceptResult!.intercept,
218
+ ctx.interceptResult!.entry,
219
+ ctx.matched.params,
220
+ freshHandlerContext,
221
+ true,
222
+ undefined,
223
+ // Skip intercept middleware: this is a post-response background
224
+ // re-render to refresh a stale cached route. The foreground
225
+ // already ran the middleware; re-running it would double its
226
+ // side effects and a short-circuit Response would abort the write.
227
+ { skipMiddleware: true },
228
+ ),
229
+ ),
214
230
  );
215
231
  }
216
232