@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa

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 (411) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +296 -887
  3. package/dist/bin/rango.js +459 -91
  4. package/dist/testing/vitest.js +36 -2
  5. package/dist/vite/index.js +1708 -414
  6. package/package.json +35 -10
  7. package/skills/api-client/SKILL.md +211 -0
  8. package/skills/breadcrumbs/SKILL.md +82 -5
  9. package/skills/bundle-analysis/SKILL.md +2 -2
  10. package/skills/cache-guide/SKILL.md +14 -9
  11. package/skills/caching/SKILL.md +221 -12
  12. package/skills/catalog.json +271 -0
  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 +83 -2
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +5 -3
  19. package/skills/defer-hydration/SKILL.md +235 -0
  20. package/skills/document-cache/SKILL.md +11 -3
  21. package/skills/fonts/SKILL.md +1 -1
  22. package/skills/handler-use/SKILL.md +9 -9
  23. package/skills/hooks/SKILL.md +73 -900
  24. package/skills/hooks/data.md +273 -0
  25. package/skills/hooks/handle-and-actions.md +103 -0
  26. package/skills/hooks/navigation.md +110 -0
  27. package/skills/hooks/outlets.md +41 -0
  28. package/skills/hooks/state.md +228 -0
  29. package/skills/hooks/urls.md +135 -0
  30. package/skills/host-router/SKILL.md +84 -7
  31. package/skills/i18n/SKILL.md +1 -1
  32. package/skills/intercept/SKILL.md +51 -17
  33. package/skills/layout/SKILL.md +38 -16
  34. package/skills/links/SKILL.md +1 -1
  35. package/skills/loader/SKILL.md +48 -20
  36. package/skills/middleware/SKILL.md +11 -5
  37. package/skills/migrate-nextjs/SKILL.md +203 -20
  38. package/skills/migrate-react-router/SKILL.md +59 -675
  39. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  40. package/skills/migrate-react-router/component-migration.md +196 -0
  41. package/skills/migrate-react-router/data-and-actions.md +225 -0
  42. package/skills/migrate-react-router/route-mapping.md +271 -0
  43. package/skills/mime-routes/SKILL.md +3 -3
  44. package/skills/observability/SKILL.md +70 -5
  45. package/skills/parallel/SKILL.md +32 -8
  46. package/skills/ppr/SKILL.md +622 -0
  47. package/skills/prerender/SKILL.md +59 -28
  48. package/skills/rango/SKILL.md +124 -50
  49. package/skills/response-routes/SKILL.md +78 -46
  50. package/skills/route/SKILL.md +85 -6
  51. package/skills/router-setup/SKILL.md +41 -6
  52. package/skills/scripts/SKILL.md +179 -0
  53. package/skills/server-actions/SKILL.md +28 -3
  54. package/skills/shell-manifest/SKILL.md +185 -0
  55. package/skills/streams-and-websockets/SKILL.md +1 -1
  56. package/skills/tailwind/SKILL.md +28 -4
  57. package/skills/testing/SKILL.md +68 -654
  58. package/skills/testing/bindings.md +103 -0
  59. package/skills/testing/cache-prerender.md +127 -0
  60. package/skills/testing/client-components.md +124 -0
  61. package/skills/testing/e2e-parity.md +125 -0
  62. package/skills/testing/flight.md +91 -0
  63. package/skills/testing/handles.md +131 -0
  64. package/skills/testing/loader.md +128 -0
  65. package/skills/testing/middleware.md +99 -0
  66. package/skills/testing/render-handler.md +122 -0
  67. package/skills/testing/response-routes.md +95 -0
  68. package/skills/testing/reverse-and-types.md +85 -0
  69. package/skills/testing/server-actions.md +107 -0
  70. package/skills/testing/server-tree.md +128 -0
  71. package/skills/testing/setup.md +123 -0
  72. package/skills/theme/SKILL.md +1 -1
  73. package/skills/typesafety/SKILL.md +45 -918
  74. package/skills/typesafety/env-and-bindings.md +254 -0
  75. package/skills/typesafety/generated-files-and-cli.md +335 -0
  76. package/skills/typesafety/params-and-search.md +153 -0
  77. package/skills/typesafety/route-types.md +209 -0
  78. package/skills/use-cache/SKILL.md +47 -17
  79. package/skills/vercel/SKILL.md +128 -0
  80. package/skills/view-transitions/SKILL.md +44 -1
  81. package/src/__augment-tests__/augmented.check.ts +2 -3
  82. package/src/__internal.ts +0 -65
  83. package/src/browser/action-coordinator.ts +1 -1
  84. package/src/browser/action-fence.ts +47 -0
  85. package/src/browser/app-shell.ts +14 -27
  86. package/src/browser/connection-warmup.ts +134 -0
  87. package/src/browser/cookie-name.ts +140 -0
  88. package/src/browser/event-controller.ts +178 -100
  89. package/src/browser/invalidate-client-cache.ts +52 -0
  90. package/src/browser/logging.ts +28 -0
  91. package/src/browser/merge-segment-loaders.ts +6 -4
  92. package/src/browser/navigation-bridge.ts +81 -68
  93. package/src/browser/navigation-client.ts +115 -70
  94. package/src/browser/navigation-store-handle.ts +38 -0
  95. package/src/browser/navigation-store.ts +153 -88
  96. package/src/browser/navigation-transaction.ts +0 -32
  97. package/src/browser/network-error-handler.ts +34 -7
  98. package/src/browser/partial-update.ts +157 -144
  99. package/src/browser/prefetch/cache.ts +148 -81
  100. package/src/browser/prefetch/fetch.ts +231 -51
  101. package/src/browser/prefetch/queue.ts +25 -7
  102. package/src/browser/rango-state.ts +157 -115
  103. package/src/browser/react/Link.tsx +40 -7
  104. package/src/browser/react/NavigationProvider.tsx +140 -99
  105. package/src/browser/react/ScrollRestoration.tsx +10 -6
  106. package/src/browser/react/filter-segment-order.ts +17 -2
  107. package/src/browser/react/index.ts +0 -51
  108. package/src/browser/react/location-state-shared.ts +14 -15
  109. package/src/browser/react/location-state.ts +0 -1
  110. package/src/browser/react/use-action.ts +6 -15
  111. package/src/browser/react/use-handle.ts +0 -5
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +33 -8
  114. package/src/browser/react/use-navigation.ts +10 -5
  115. package/src/browser/react/use-params.ts +0 -2
  116. package/src/browser/react/use-router.ts +6 -4
  117. package/src/browser/react/use-search-params.ts +0 -5
  118. package/src/browser/react/use-segments.ts +0 -13
  119. package/src/browser/response-adapter.ts +74 -8
  120. package/src/browser/rsc-router.tsx +97 -22
  121. package/src/browser/scroll-restoration.ts +15 -8
  122. package/src/browser/segment-reconciler.ts +31 -21
  123. package/src/browser/server-action-bridge.ts +216 -38
  124. package/src/browser/types.ts +94 -22
  125. package/src/browser/validate-redirect-origin.ts +43 -16
  126. package/src/build/generate-manifest.ts +155 -131
  127. package/src/build/generate-route-types.ts +1 -1
  128. package/src/build/index.ts +11 -5
  129. package/src/build/prefix-tree-utils.ts +123 -0
  130. package/src/build/route-trie.ts +152 -22
  131. package/src/build/route-types/ast-route-extraction.ts +15 -8
  132. package/src/build/route-types/codegen.ts +12 -1
  133. package/src/build/route-types/include-resolution.ts +455 -61
  134. package/src/build/route-types/param-extraction.ts +6 -3
  135. package/src/build/route-types/per-module-writer.ts +15 -2
  136. package/src/build/route-types/router-processing.ts +77 -41
  137. package/src/build/route-types/source-scan.ts +105 -7
  138. package/src/build/runtime-discovery.ts +4 -1
  139. package/src/cache/cache-error.ts +104 -0
  140. package/src/cache/cache-key-utils.ts +58 -13
  141. package/src/cache/cache-policy.ts +108 -34
  142. package/src/cache/cache-runtime.ts +454 -101
  143. package/src/cache/cache-scope.ts +159 -54
  144. package/src/cache/cache-tag.ts +149 -0
  145. package/src/cache/cf/cf-base64.ts +33 -0
  146. package/src/cache/cf/cf-cache-constants.ts +127 -0
  147. package/src/cache/cf/cf-cache-store.ts +2170 -377
  148. package/src/cache/cf/cf-cache-types.ts +349 -0
  149. package/src/cache/cf/cf-kv-utils.ts +46 -0
  150. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  151. package/src/cache/cf/index.ts +6 -16
  152. package/src/cache/document-cache.ts +126 -41
  153. package/src/cache/handle-snapshot.ts +70 -0
  154. package/src/cache/index.ts +23 -20
  155. package/src/cache/memory-segment-store.ts +243 -37
  156. package/src/cache/profile-registry.ts +46 -31
  157. package/src/cache/read-through-swr.ts +56 -12
  158. package/src/cache/segment-codec.ts +13 -21
  159. package/src/cache/shell-snapshot.ts +417 -0
  160. package/src/cache/tag-invalidation.ts +230 -0
  161. package/src/cache/types.ts +194 -99
  162. package/src/cache/vercel/index.ts +11 -0
  163. package/src/cache/vercel/vercel-cache-store.ts +1132 -0
  164. package/src/client.rsc.tsx +39 -22
  165. package/src/client.tsx +28 -58
  166. package/src/cloudflare/index.ts +11 -0
  167. package/src/cloudflare/tracing.ts +108 -0
  168. package/src/component-utils.ts +19 -0
  169. package/src/components/DefaultDocument.tsx +8 -2
  170. package/src/context-var.ts +13 -1
  171. package/src/decode-loader-results.ts +18 -2
  172. package/src/defer.ts +185 -0
  173. package/src/deps/ssr.ts +0 -1
  174. package/src/encode-kv.ts +49 -0
  175. package/src/errors.ts +0 -3
  176. package/src/escape-script.ts +52 -0
  177. package/src/handle.ts +57 -40
  178. package/src/handles/MetaTags.tsx +24 -53
  179. package/src/handles/Scripts.tsx +183 -0
  180. package/src/handles/breadcrumbs.ts +35 -8
  181. package/src/handles/deferred-resolution.ts +127 -0
  182. package/src/handles/is-thenable.ts +18 -0
  183. package/src/handles/meta.ts +14 -40
  184. package/src/handles/script.ts +244 -0
  185. package/src/host/cookie-handler.ts +9 -60
  186. package/src/host/errors.ts +13 -22
  187. package/src/host/index.ts +7 -0
  188. package/src/host/pattern-matcher.ts +23 -52
  189. package/src/host/router.ts +1 -65
  190. package/src/host/testing.ts +40 -27
  191. package/src/host/types.ts +6 -2
  192. package/src/href-client.ts +7 -12
  193. package/src/index.rsc.ts +88 -8
  194. package/src/index.ts +90 -16
  195. package/src/internal-debug.ts +11 -10
  196. package/src/loader.rsc.ts +19 -9
  197. package/src/loader.ts +12 -4
  198. package/src/outlet-provider.tsx +1 -5
  199. package/src/prerender/param-hash.ts +16 -16
  200. package/src/prerender/store.ts +32 -37
  201. package/src/prerender.ts +75 -7
  202. package/src/redirect-origin.ts +114 -0
  203. package/src/regex-escape.ts +8 -0
  204. package/src/render-error-thrower.tsx +20 -0
  205. package/src/response-utils.ts +25 -0
  206. package/src/root-error-boundary.tsx +1 -19
  207. package/src/route-content-wrapper.tsx +13 -49
  208. package/src/route-definition/dsl-helpers.ts +60 -53
  209. package/src/route-definition/helper-factories.ts +0 -2
  210. package/src/route-definition/helpers-types.ts +46 -46
  211. package/src/route-definition/index.ts +1 -2
  212. package/src/route-definition/redirect.ts +44 -11
  213. package/src/route-definition/resolve-handler-use.ts +6 -1
  214. package/src/route-definition/use-item-types.ts +3 -6
  215. package/src/route-map-builder.ts +41 -20
  216. package/src/route-types.ts +0 -5
  217. package/src/router/content-negotiation.ts +58 -23
  218. package/src/router/error-handling.ts +44 -17
  219. package/src/router/find-match.ts +129 -30
  220. package/src/router/handler-context.ts +6 -1
  221. package/src/router/instrument.ts +355 -0
  222. package/src/router/intercept-resolution.ts +35 -2
  223. package/src/router/lazy-includes.ts +79 -56
  224. package/src/router/loader-resolution.ts +151 -73
  225. package/src/router/logging.ts +0 -6
  226. package/src/router/manifest.ts +74 -40
  227. package/src/router/match-api.ts +76 -52
  228. package/src/router/match-context.ts +0 -22
  229. package/src/router/match-handlers.ts +181 -178
  230. package/src/router/match-middleware/background-revalidation.ts +40 -24
  231. package/src/router/match-middleware/cache-lookup.ts +115 -194
  232. package/src/router/match-middleware/cache-store.ts +61 -50
  233. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  234. package/src/router/match-middleware/segment-resolution.ts +0 -22
  235. package/src/router/match-pipelines.ts +1 -42
  236. package/src/router/match-result.ts +36 -67
  237. package/src/router/metrics.ts +0 -34
  238. package/src/router/middleware-types.ts +0 -116
  239. package/src/router/middleware.ts +231 -120
  240. package/src/router/navigation-snapshot.ts +7 -56
  241. package/src/router/params-util.ts +23 -0
  242. package/src/router/parse-pattern.ts +115 -0
  243. package/src/router/pattern-matching.ts +99 -152
  244. package/src/router/prefetch-cache-ttl.ts +51 -0
  245. package/src/router/prefetch-limits.ts +37 -0
  246. package/src/router/prerender-match.ts +111 -66
  247. package/src/router/preview-match.ts +3 -1
  248. package/src/router/request-classification.ts +47 -42
  249. package/src/router/revalidation.ts +75 -81
  250. package/src/router/route-snapshot.ts +14 -3
  251. package/src/router/router-context.ts +6 -29
  252. package/src/router/router-interfaces.ts +70 -8
  253. package/src/router/router-options.ts +126 -4
  254. package/src/router/segment-resolution/fresh.ts +104 -80
  255. package/src/router/segment-resolution/helpers.ts +86 -6
  256. package/src/router/segment-resolution/loader-cache.ts +155 -39
  257. package/src/router/segment-resolution/loader-mask.ts +60 -0
  258. package/src/router/segment-resolution/loader-snapshot.ts +259 -0
  259. package/src/router/segment-resolution/mask-nested.ts +83 -0
  260. package/src/router/segment-resolution/revalidation.ts +215 -304
  261. package/src/router/segment-resolution/static-store.ts +19 -5
  262. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  263. package/src/router/segment-resolution/view-transition-default.ts +35 -15
  264. package/src/router/segment-resolution.ts +5 -1
  265. package/src/router/segment-wrappers.ts +6 -5
  266. package/src/router/state-cookie-name.ts +33 -0
  267. package/src/router/substitute-pattern-params.ts +54 -35
  268. package/src/router/telemetry-otel.ts +160 -200
  269. package/src/router/telemetry.ts +9 -23
  270. package/src/router/timeout.ts +0 -20
  271. package/src/router/tracing.ts +215 -0
  272. package/src/router/trie-matching.ts +171 -64
  273. package/src/router/types.ts +1 -63
  274. package/src/router/url-params.ts +13 -5
  275. package/src/router.ts +119 -48
  276. package/src/rsc/full-payload.ts +70 -0
  277. package/src/rsc/handler-context.ts +1 -0
  278. package/src/rsc/handler.ts +267 -152
  279. package/src/rsc/helpers.ts +78 -4
  280. package/src/rsc/index.ts +1 -4
  281. package/src/rsc/json-route-result.ts +38 -0
  282. package/src/rsc/loader-fetch.ts +114 -38
  283. package/src/rsc/manifest-init.ts +29 -42
  284. package/src/rsc/nonce.ts +10 -1
  285. package/src/rsc/origin-guard.ts +11 -15
  286. package/src/rsc/progressive-enhancement.ts +120 -13
  287. package/src/rsc/redirect-guard.ts +100 -0
  288. package/src/rsc/response-cache-serve.ts +238 -0
  289. package/src/rsc/response-error.ts +79 -12
  290. package/src/rsc/response-route-handler.ts +58 -141
  291. package/src/rsc/rsc-rendering.ts +492 -49
  292. package/src/rsc/runtime-warnings.ts +14 -0
  293. package/src/rsc/server-action.ts +268 -82
  294. package/src/rsc/shell-capture.ts +1190 -0
  295. package/src/rsc/shell-serve.ts +181 -0
  296. package/src/rsc/transition-gate.ts +89 -0
  297. package/src/rsc/types.ts +45 -3
  298. package/src/runtime-env.ts +18 -0
  299. package/src/search-params.ts +31 -26
  300. package/src/segment-loader-promise.ts +49 -4
  301. package/src/segment-system.tsx +260 -95
  302. package/src/server/context.ts +99 -9
  303. package/src/server/cookie-parse.ts +32 -0
  304. package/src/server/cookie-store.ts +125 -2
  305. package/src/server/handle-store.ts +21 -38
  306. package/src/server/loader-registry.ts +33 -42
  307. package/src/server/request-context.ts +379 -138
  308. package/src/ssr/index.tsx +491 -182
  309. package/src/ssr/inject-rsc-eager.ts +167 -0
  310. package/src/ssr/ssr-root.tsx +228 -0
  311. package/src/static-handler.ts +10 -13
  312. package/src/testing/cache-status.ts +44 -48
  313. package/src/testing/collect-handle.ts +14 -31
  314. package/src/testing/dispatch.ts +533 -160
  315. package/src/testing/e2e/fixture.ts +45 -11
  316. package/src/testing/e2e/index.ts +1 -22
  317. package/src/testing/e2e/matchers.ts +0 -16
  318. package/src/testing/e2e/parity.ts +85 -4
  319. package/src/testing/e2e/server.ts +12 -0
  320. package/src/testing/flight-matchers.ts +7 -14
  321. package/src/testing/flight-normalize.ts +11 -0
  322. package/src/testing/flight-runtime.d.ts +36 -0
  323. package/src/testing/flight-tree.ts +682 -0
  324. package/src/testing/flight.entry.ts +30 -0
  325. package/src/testing/flight.ts +145 -70
  326. package/src/testing/generated-routes.ts +26 -50
  327. package/src/testing/index.ts +18 -19
  328. package/src/testing/internal/context.ts +184 -68
  329. package/src/testing/internal/flight-client-globals.ts +30 -0
  330. package/src/testing/internal/seed-vars.ts +54 -0
  331. package/src/testing/render-handler.ts +357 -0
  332. package/src/testing/render-route.tsx +134 -115
  333. package/src/testing/run-loader.ts +140 -51
  334. package/src/testing/run-middleware.ts +59 -33
  335. package/src/testing/run-transition-when.ts +164 -0
  336. package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
  337. package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
  338. package/src/testing/vitest.ts +138 -16
  339. package/src/theme/ThemeProvider.tsx +56 -84
  340. package/src/theme/ThemeScript.tsx +7 -9
  341. package/src/theme/constants.ts +52 -13
  342. package/src/theme/index.ts +0 -7
  343. package/src/theme/theme-context.ts +1 -5
  344. package/src/theme/theme-script.ts +22 -21
  345. package/src/theme/use-theme.ts +0 -3
  346. package/src/types/boundaries.ts +0 -35
  347. package/src/types/cache-types.ts +13 -4
  348. package/src/types/error-types.ts +30 -90
  349. package/src/types/global-namespace.ts +15 -15
  350. package/src/types/handler-context.ts +45 -15
  351. package/src/types/index.ts +2 -10
  352. package/src/types/loader-types.ts +6 -3
  353. package/src/types/request-scope.ts +8 -22
  354. package/src/types/route-config.ts +20 -52
  355. package/src/types/route-entry.ts +0 -6
  356. package/src/types/segments.ts +100 -13
  357. package/src/urls/include-helper.ts +10 -12
  358. package/src/urls/include-provider.ts +71 -0
  359. package/src/urls/index.ts +2 -8
  360. package/src/urls/path-helper-types.ts +52 -14
  361. package/src/urls/path-helper.ts +5 -54
  362. package/src/urls/pattern-types.ts +36 -0
  363. package/src/urls/type-extraction.ts +76 -42
  364. package/src/urls/urls-function.ts +0 -14
  365. package/src/use-loader.tsx +0 -186
  366. package/src/vercel/index.ts +11 -0
  367. package/src/vercel/tracing.ts +88 -0
  368. package/src/vite/discovery/bundle-postprocess.ts +2 -1
  369. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  370. package/src/vite/discovery/discover-routers.ts +34 -43
  371. package/src/vite/discovery/discovery-errors.ts +61 -0
  372. package/src/vite/discovery/prerender-collection.ts +33 -46
  373. package/src/vite/discovery/state.ts +12 -1
  374. package/src/vite/discovery/virtual-module-codegen.ts +1 -11
  375. package/src/vite/index.ts +9 -0
  376. package/src/vite/inject-client-debug.ts +88 -0
  377. package/src/vite/plugin-types.ts +143 -10
  378. package/src/vite/plugins/cjs-to-esm.ts +8 -12
  379. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  380. package/src/vite/plugins/client-ref-hashing.ts +0 -10
  381. package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
  382. package/src/vite/plugins/expose-action-id.ts +2 -73
  383. package/src/vite/plugins/expose-id-utils.ts +85 -56
  384. package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
  385. package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
  386. package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
  387. package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
  388. package/src/vite/plugins/expose-internal-ids.ts +10 -1
  389. package/src/vite/plugins/performance-tracks.ts +0 -3
  390. package/src/vite/plugins/refresh-cmd.ts +1 -1
  391. package/src/vite/plugins/use-cache-transform.ts +21 -46
  392. package/src/vite/plugins/vercel-output.ts +384 -0
  393. package/src/vite/plugins/version-injector.ts +22 -27
  394. package/src/vite/plugins/version-plugin.ts +6 -66
  395. package/src/vite/plugins/virtual-entries.ts +137 -26
  396. package/src/vite/rango.ts +146 -135
  397. package/src/vite/router-discovery.ts +189 -48
  398. package/src/vite/utils/ast-handler-extract.ts +11 -20
  399. package/src/vite/utils/bundle-analysis.ts +6 -13
  400. package/src/vite/utils/client-chunks.ts +0 -6
  401. package/src/vite/utils/directive-prologue.ts +40 -0
  402. package/src/vite/utils/forward-user-plugins.ts +0 -22
  403. package/src/vite/utils/manifest-utils.ts +4 -75
  404. package/src/vite/utils/package-resolution.ts +1 -73
  405. package/src/vite/utils/prerender-utils.ts +71 -44
  406. package/src/vite/utils/shared-utils.ts +55 -37
  407. package/src/browser/react/use-client-cache.ts +0 -58
  408. package/src/browser/shallow.ts +0 -40
  409. package/src/handles/index.ts +0 -7
  410. package/src/network-error-thrower.tsx +0 -23
  411. package/src/router/middleware-cookies.ts +0 -55
@@ -11,6 +11,16 @@ import {
11
11
  formatNestedRouterConflictError,
12
12
  findNestedRouterConflict,
13
13
  } from "../../build/generate-route-types.js";
14
+ // Pure data transforms over generateManifestFull's output. Imported directly
15
+ // from source (not the public ./build barrel, and not the runner) because they
16
+ // are realm-independent: buildRouteTrie/buildPerRouterTrie operate on plain
17
+ // manifest data, and collectFallbackClientRefs keys on the global-registry
18
+ // Symbol.for("react.client.reference"), so it detects client references in a
19
+ // boundary tree regardless of which realm imported the walker. Only
20
+ // generateManifestFull must stay on the runner (it invokes user handlers via
21
+ // RangoContext from the runner realm) — see the runner.import below.
22
+ import { buildRouteTrie, buildPerRouterTrie } from "../../build/route-trie.js";
23
+ import { collectFallbackClientRefs } from "../../build/collect-fallback-refs.js";
14
24
  import {
15
25
  flattenLeafEntries,
16
26
  buildRouteToStaticPrefix,
@@ -107,7 +117,10 @@ export async function discoverRouters(
107
117
  }
108
118
  }
109
119
 
110
- // Import build utilities for manifest generation
120
+ // generateManifestFull must run in the RSC runner realm: it invokes the
121
+ // user's urlpatterns.handler() via RangoContext, consuming router instances
122
+ // from the runner. The trie/fallback-ref builders are pure transforms over
123
+ // its output and are imported directly from source above.
111
124
  const buildMod = await timed(
112
125
  debug,
113
126
  "inner: import @rangojs/router/build",
@@ -158,11 +171,12 @@ export async function discoverRouters(
158
171
  // are NOT in EntryData, so generateManifestFull's walk misses them. Collect any
159
172
  // "use client" default boundary directly off the router instance. The value is
160
173
  // commonly a handler function wrapping the client boundary in server providers,
161
- // so collectFallbackClientRefs invokes + walks the tree. Routed through buildMod
162
- // so it runs in the same RSC runner realm the boundary value came from.
174
+ // so collectFallbackClientRefs invokes + walks the tree. The walker keys on the
175
+ // global-registry Symbol.for("react.client.reference"), so it detects client
176
+ // references in a runner-realm boundary tree even when imported here directly.
163
177
  const collectFromBoundaryNode = (node: unknown): void => {
164
- if (collectClientFallbackRef && buildMod.collectFallbackClientRefs) {
165
- buildMod.collectFallbackClientRefs(node, collectClientFallbackRef);
178
+ if (collectClientFallbackRef) {
179
+ collectFallbackClientRefs(node, collectClientFallbackRef);
166
180
  }
167
181
  };
168
182
 
@@ -172,7 +186,7 @@ export async function discoverRouters(
172
186
  continue;
173
187
  }
174
188
 
175
- const manifest = generateManifestFull(
189
+ const manifest = await generateManifestFull(
176
190
  router.urlpatterns,
177
191
  routerMountIndex,
178
192
  {
@@ -243,20 +257,19 @@ export async function discoverRouters(
243
257
  // Flatten prefix tree leaf nodes into precomputed entries.
244
258
  // Leaf nodes (no children) can have their routes used directly by
245
259
  // evaluateLazyEntry() without running the handler at runtime.
260
+ // Walk once into a per-router array, then fold it into the merged array;
261
+ // the merged and per-router entries are identical, so a second walk is
262
+ // redundant. Append order is preserved within and across routers.
263
+ const routerPrecomputed: PrecomputedEntry[] = [];
246
264
  flattenLeafEntries(
247
265
  manifest.prefixTree,
248
266
  manifest.routeManifest,
249
- newMergedPrecomputedEntries,
267
+ routerPrecomputed,
250
268
  );
269
+ newMergedPrecomputedEntries.push(...routerPrecomputed);
251
270
 
252
271
  // Store per-router manifest and precomputed entries for isolated virtual modules.
253
272
  newPerRouterManifestDataMap.set(id, manifest.routeManifest);
254
- const routerPrecomputed: PrecomputedEntry[] = [];
255
- flattenLeafEntries(
256
- manifest.prefixTree,
257
- manifest.routeManifest,
258
- routerPrecomputed,
259
- );
260
273
  newPerRouterPrecomputedMap.set(id, routerPrecomputed);
261
274
 
262
275
  console.log(
@@ -294,8 +307,7 @@ export async function discoverRouters(
294
307
  let newMergedRouteTrie: any = null;
295
308
  const trieStart = debug ? performance.now() : 0;
296
309
  if (Object.keys(newMergedRouteManifest).length > 0) {
297
- const buildRouteTrie = buildMod.buildRouteTrie;
298
- if (buildRouteTrie && mergedRouteAncestry) {
310
+ if (mergedRouteAncestry) {
299
311
  // Build routeToStaticPrefix from saved manifests
300
312
  const routeToStaticPrefix: Record<string, string> = {};
301
313
  for (const { manifest } of allManifests) {
@@ -340,36 +352,15 @@ export async function discoverRouters(
340
352
  mergedResponseTypeRoutes,
341
353
  );
342
354
 
343
- // Build per-router tries for multi-router isolation.
355
+ // Build per-router tries for multi-router isolation. Uses the single
356
+ // shared buildPerRouterTrie so the production serialized trie is built by
357
+ // exactly the same code as the dev/HMR runtime rebuild (manifest-init.ts).
358
+ // Returns null for route-less manifests (route-trie.ts).
344
359
  for (const { id, manifest } of allManifests) {
345
- if (
346
- !manifest._routeAncestry ||
347
- Object.keys(manifest._routeAncestry).length === 0
348
- )
349
- continue;
350
- const perRouterStaticPrefix: Record<string, string> = {};
351
- for (const name of Object.keys(manifest.routeManifest)) {
352
- perRouterStaticPrefix[name] = "";
360
+ const perRouterTrie = buildPerRouterTrie(manifest);
361
+ if (perRouterTrie) {
362
+ newPerRouterTrieMap.set(id, perRouterTrie);
353
363
  }
354
- buildRouteToStaticPrefix(manifest.prefixTree, perRouterStaticPrefix);
355
-
356
- const perRouterPrerenderNames = manifest.prerenderRoutes
357
- ? new Set<string>(manifest.prerenderRoutes)
358
- : undefined;
359
- const perRouterPassthroughNames = manifest.passthroughRoutes
360
- ? new Set<string>(manifest.passthroughRoutes)
361
- : undefined;
362
-
363
- const perRouterTrie = buildRouteTrie(
364
- manifest.routeManifest,
365
- manifest._routeAncestry,
366
- perRouterStaticPrefix,
367
- manifest.routeTrailingSlash,
368
- perRouterPrerenderNames,
369
- perRouterPassthroughNames,
370
- manifest.responseTypeRoutes,
371
- );
372
- newPerRouterTrieMap.set(id, perRouterTrie);
373
364
  }
374
365
  }
375
366
  }
@@ -192,3 +192,64 @@ export class DiscoveryError extends Error {
192
192
  Object.setPrototypeOf(this, DiscoveryError.prototype);
193
193
  }
194
194
  }
195
+
196
+ /** How the dev caller should surface a discovery failure. */
197
+ export interface DiscoveryFailureReport {
198
+ level: "error" | "warn";
199
+ message: string;
200
+ }
201
+
202
+ /**
203
+ * Decide how to surface a dev-boot discovery failure in the terminal.
204
+ *
205
+ * The bare "no routers found" case (a DiscoveryError with no caught host-handler
206
+ * failures) is ambiguous. It is either:
207
+ * - a genuine misconfiguration — the entry never calls createRouter(), or the
208
+ * configured entry path is wrong; or
209
+ * - a transient artifact of a Vite dependency re-optimization racing with boot
210
+ * discovery (a module read before the entry import resolves to the
211
+ * pre-optimize copy of the runner graph while createRouter() populated the
212
+ * post-optimize copy — see router-discovery.ts).
213
+ *
214
+ * We can only tell them apart when the caller observed the dep optimizer's
215
+ * `browserHash` change across the discovery attempt (`reoptimizeObserved`): a
216
+ * reload-causing re-optimization landed mid-flight, so the empty read was
217
+ * transient and the app self-heals per-request (handler.ts builds the trie from
218
+ * the router's live urlpatterns) with discovery re-running on the next boot.
219
+ *
220
+ * A DiscoveryError that DOES carry caught host-handler failures already embeds
221
+ * the real cause in its message, and any non-DiscoveryError is a hard failure;
222
+ * both stay loud with full detail.
223
+ */
224
+ export function describeDiscoveryFailure(
225
+ err: unknown,
226
+ opts: { reoptimizeObserved?: boolean } = {},
227
+ ): DiscoveryFailureReport {
228
+ if (err instanceof DiscoveryError && err.caught.length === 0) {
229
+ const entry = err.entryPath ?? "the router entry";
230
+ if (opts.reoptimizeObserved) {
231
+ return {
232
+ level: "warn",
233
+ message:
234
+ `[rango] No routers found while Vite was re-optimizing dependencies on ` +
235
+ `dev boot. This is transient: routes are served per-request and ` +
236
+ `discovery re-runs automatically, so it clears on the next boot. If ` +
237
+ `routes still 404, confirm ${entry} calls createRouter().`,
238
+ };
239
+ }
240
+ return {
241
+ level: "error",
242
+ message:
243
+ `${err.message}\n` +
244
+ ` Ensure ${entry} calls createRouter() at module top level and that the ` +
245
+ `configured router entry path is correct.`,
246
+ };
247
+ }
248
+
249
+ const e = err as { stack?: string; message?: string };
250
+ const detail = e?.stack ?? e?.message ?? String(err);
251
+ return {
252
+ level: "error",
253
+ message: `[rango] Router discovery failed: ${detail}`,
254
+ };
255
+ }
@@ -6,13 +6,14 @@
6
6
  * generation.
7
7
  */
8
8
 
9
- import { contextSet } from "../../context-var.js";
9
+ import { contextSet, hasContextVars } from "../../context-var.js";
10
10
  import {
11
11
  encodePathParam,
12
12
  substituteRouteParams,
13
13
  runWithConcurrency,
14
14
  groupByConcurrency,
15
15
  notifyOnError,
16
+ resolvePrerenderError,
16
17
  stageBuildAssetModule,
17
18
  } from "../utils/prerender-utils.js";
18
19
  import type { DiscoveryState } from "./state.js";
@@ -135,9 +136,7 @@ export async function expandPrerenderRoutes(
135
136
  (performance.now() - getParamsStart).toFixed(1),
136
137
  );
137
138
  const concurrency = def.options?.concurrency ?? 1;
138
- const hasBuildVars =
139
- Object.keys(buildVars).length > 0 ||
140
- Object.getOwnPropertySymbols(buildVars).length > 0;
139
+ const hasBuildVars = hasContextVars(buildVars);
141
140
  for (const params of paramsList) {
142
141
  let url = substituteRouteParams(
143
142
  pattern,
@@ -233,6 +232,10 @@ export async function expandPrerenderRoutes(
233
232
  const manifestEntries: Record<string, string> = {};
234
233
  let doneCount = 0;
235
234
  let skipCount = 0;
235
+ // #587: a render error reaches here (matchForPrerender now re-throws it rather
236
+ // than baking the error boundary). Default "fail" fails the build; "warn" logs
237
+ // and skips baking the URL.
238
+ const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
236
239
  const startTotal = performance.now();
237
240
 
238
241
  // Group entries by concurrency for batched rendering.
@@ -282,10 +285,9 @@ export async function expandPrerenderRoutes(
282
285
  const interceptKey = `${result.routeName}/${paramHash}/i`;
283
286
  const interceptValue = JSON.stringify({
284
287
  segments: [...result.segments, ...result.interceptSegments],
285
- handles: {
286
- ...result.handles,
287
- ...(result.interceptHandles || {}),
288
- },
288
+ // interceptHandles is the pre-encoded MERGED (main + intercept)
289
+ // handle string (the producer merged before encoding).
290
+ handles: result.interceptHandles ?? "",
289
291
  });
290
292
  manifestEntries[interceptKey] = stageBuildAssetModule(
291
293
  state.projectRoot,
@@ -300,35 +302,22 @@ export async function expandPrerenderRoutes(
300
302
  doneCount++;
301
303
  break;
302
304
  } catch (err: any) {
303
- if (err.name === "Skip") {
304
- const elapsed = (performance.now() - startUrl).toFixed(0);
305
- console.log(
306
- `[rango] SKIP ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
307
- );
308
- skipCount++;
309
- notifyOnError(
310
- registry,
311
- err,
312
- "prerender",
313
- entry.routeName,
314
- entry.urlPath,
315
- true,
316
- );
317
- break;
318
- }
319
- // Regular error: log, notify, and fail the build
305
+ // Skip, or a render error under prerender.onError "warn": skip the
306
+ // URL (never bake the error page, #587). A render error under the
307
+ // default "fail" re-throws below to fail the build.
320
308
  const elapsed = (performance.now() - startUrl).toFixed(0);
321
- console.error(
322
- `[rango] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
323
- );
324
- notifyOnError(
309
+ resolvePrerenderError(
325
310
  registry,
326
311
  err,
312
+ prerenderOnError,
313
+ entry.urlPath.padEnd(40),
314
+ elapsed,
327
315
  "prerender",
328
316
  entry.routeName,
329
317
  entry.urlPath,
330
318
  );
331
- throw err;
319
+ skipCount++;
320
+ break;
332
321
  }
333
322
  }
334
323
  },
@@ -381,6 +370,7 @@ export async function renderStaticHandlers(
381
370
  let staticDone = 0;
382
371
  let staticSkip = 0;
383
372
  let totalStaticCount = 0;
373
+ const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
384
374
 
385
375
  // Count handlers for the log header
386
376
  for (const [, exportNames] of state.resolvedStaticModules) {
@@ -420,7 +410,8 @@ export async function renderStaticHandlers(
420
410
  !state.isBuildMode,
421
411
  );
422
412
  if (result) {
423
- const hasHandles = Object.keys(result.handles).length > 0;
413
+ // result.handles is the pre-encoded handle string ("" when none).
414
+ const hasHandles = result.handles !== "";
424
415
  const exportValue = hasHandles
425
416
  ? JSON.stringify(result)
426
417
  : JSON.stringify(result.encoded);
@@ -436,23 +427,19 @@ export async function renderStaticHandlers(
436
427
  break;
437
428
  }
438
429
  } catch (err: any) {
439
- if (err.name === "Skip") {
440
- const elapsed = (performance.now() - startHandler).toFixed(0);
441
- console.log(
442
- `[rango] SKIP ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
443
- );
444
- staticSkip++;
445
- notifyOnError(registry, err, "static", undefined, undefined, true);
446
- handled = true;
447
- break;
448
- }
449
- // Regular error: log, notify, and fail the build
430
+ // Same Skip/warn/fail policy as the prerender loop (shared helper).
450
431
  const elapsed = (performance.now() - startHandler).toFixed(0);
451
- console.error(
452
- `[rango] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
432
+ resolvePrerenderError(
433
+ registry,
434
+ err,
435
+ prerenderOnError,
436
+ name.padEnd(40),
437
+ elapsed,
438
+ "static",
453
439
  );
454
- notifyOnError(registry, err, "static");
455
- throw err;
440
+ staticSkip++;
441
+ handled = true;
442
+ break;
456
443
  }
457
444
  }
458
445
  if (!handled) {
@@ -19,7 +19,18 @@ export interface PluginOptions {
19
19
  /** Build-time env option from rango() config. */
20
20
  buildEnv?: import("../plugin-types.js").BuildEnvOption;
21
21
  /** Deployment preset (needed for buildEnv "auto" resolution). */
22
- preset?: "node" | "cloudflare";
22
+ preset?: "node" | "cloudflare" | "vercel";
23
+ /**
24
+ * Route-discovery scan filter (glob include/exclude) from rango() config.
25
+ * Compiled into `DiscoveryState.scanFilter` once `projectRoot` is known.
26
+ */
27
+ discovery?: { include?: string[]; exclude?: string[] };
28
+ /**
29
+ * What to do when a Prerender/Static render throws at build time, from
30
+ * rango({ prerender: { onError } }). "fail" (default) fails the build; "warn"
31
+ * logs and skips baking the URL. See {@link import("../plugin-types.js").RangoOptions}.
32
+ */
33
+ prerenderOnError?: "fail" | "warn";
23
34
  /**
24
35
  * Shared context the built-in clientChunks strategy reads. Discovery populates
25
36
  * it (registered fallback hashes + single-router name) before the client build
@@ -49,7 +49,6 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
49
49
  );
50
50
  genFileVars.push(varName);
51
51
  } else {
52
- // Routers without sourceFile: inline their manifest data directly
53
52
  routersWithoutGenFile.push({
54
53
  id: entry.id,
55
54
  manifest: entry.routeManifest,
@@ -68,14 +67,12 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
68
67
  `clearAllRouterData();`,
69
68
  ];
70
69
 
71
- // Flatten NamedRoutes entries: search schema objects -> plain string paths
72
70
  if (genFileVars.length > 0) {
73
71
  lines.push(
74
72
  `function __flat(r) { const o = {}; for (const [k, v] of Object.entries(r)) o[k] = typeof v === "string" ? v : v.path; return o; }`,
75
73
  );
76
74
  }
77
75
 
78
- // Build the merged manifest from gen file imports + inlined data
79
76
  if (genFileVars.length === 1 && routersWithoutGenFile.length === 0) {
80
77
  lines.push(`setCachedManifest(__flat(${genFileVars[0]}));`);
81
78
  } else {
@@ -86,7 +83,6 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
86
83
  lines.push(`setCachedManifest({ ${parts.join(", ")} });`);
87
84
  }
88
85
 
89
- // Set per-router manifests
90
86
  let genVarIdx = 0;
91
87
  for (const entry of state.perRouterManifests) {
92
88
  if (entry.sourceFile) {
@@ -114,8 +110,6 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
114
110
  // against live router.urlpatterns, which is always correct after a
115
111
  // program reload.
116
112
 
117
- // Register lazy loaders for per-router manifest modules.
118
- // Each import() uses a static string literal so Rollup creates separate chunks.
119
113
  for (const routerId of state.perRouterManifestDataMap.keys()) {
120
114
  lines.push(
121
115
  `registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`,
@@ -129,9 +123,6 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
129
123
  return lines.join("\n");
130
124
  }
131
125
 
132
- // No manifest: either discovery hasn't completed or no runner (Cloudflare dev).
133
- // Still inject __PRERENDER_DEV_URL so the prerender store can fetch on-demand.
134
- // Re-resolve origin now since the server is listening by module load time.
135
126
  if (!state.isBuildMode) {
136
127
  const origin =
137
128
  state.devServerOrigin ||
@@ -160,7 +151,6 @@ export function generatePerRouterModule(
160
151
  const lines: string[] = [];
161
152
 
162
153
  if (routerEntry?.sourceFile) {
163
- // Import manifest from the gen file so HMR auto-propagates
164
154
  const routerDir = dirname(routerEntry.sourceFile);
165
155
  const routerBasename = basename(routerEntry.sourceFile).replace(
166
156
  /\.(tsx?|jsx?)$/,
@@ -189,5 +179,5 @@ export function generatePerRouterModule(
189
179
  `export const precomputedEntries = ${jsonParseExpression(entries)};`,
190
180
  );
191
181
  }
192
- return lines.join("\n") || "// empty router manifest";
182
+ return lines.join("\n") || "";
193
183
  }
package/src/vite/index.ts CHANGED
@@ -8,10 +8,19 @@
8
8
 
9
9
  export { rango } from "./rango.js";
10
10
  export { poke } from "./plugins/refresh-cmd.js";
11
+ // The built-in clientChunks strategy, exported so a custom `clientChunks`
12
+ // function can OVERLAY it (route a few modules to a dedicated chunk, delegate
13
+ // the rest) instead of replacing the whole route/marker grouping. Without this
14
+ // a consumer override silently loses app-fallback/route splitting for the
15
+ // entire app. Note: called without a ClientChunkContext the fallbackRefs-based
16
+ // `app-fallback` split is inactive — discovery wires it only for the built-in.
17
+ export { directoryClientChunks } from "./utils/client-chunks.js";
11
18
 
12
19
  export type {
13
20
  RangoNodeOptions,
14
21
  RangoCloudflareOptions,
22
+ RangoVercelOptions,
23
+ VercelPresetOptions,
15
24
  RangoOptions,
16
25
  ClientChunks,
17
26
  ClientChunkMeta,
@@ -0,0 +1,88 @@
1
+ import type { Connect } from "vite";
2
+
3
+ /**
4
+ * Bake the resolved INTERNAL_RANGO_DEBUG value into the router's `internal-debug`
5
+ * module so the flag reaches the CLIENT debug logs by just setting the env var.
6
+ *
7
+ * internal-debug.ts normally reads the flag via `typeof __RANGO_DEBUG__`, a Vite
8
+ * define. That delivery is unreliable on the client: in dev Vite ships the define
9
+ * only as an injected global whose presence varies across consumer setups, so the
10
+ * module can fall through to `process.env` (undefined in the browser) and the FE
11
+ * debug flag silently stays false while the server logs work. A Vite `transform`
12
+ * runs on the module regardless of how (or whether) the define is delivered, in
13
+ * both dev and build and for every environment, so the discovery plugin uses this
14
+ * to replace the module with the resolved literal.
15
+ */
16
+
17
+ /**
18
+ * Scope to the router's own internal-debug module: the published package
19
+ * (`/@rangojs/router/`, incl. pnpm's nested layout) or the monorepo workspace
20
+ * (`/packages/rangojs-router/`). The package-anchored path avoids matching a
21
+ * consumer file that merely sits under a directory named `rangojs-router`.
22
+ * Accepts module ids and dev-server URLs (`/@fs/...internal-debug.ts?v=abc`).
23
+ */
24
+ export function isRouterInternalDebugId(id: string): boolean {
25
+ if (!id.includes("internal-debug")) return false;
26
+ const norm = id.replace(/\\/g, "/");
27
+ return (
28
+ /\/internal-debug\.[cm]?[jt]sx?(\?|$)/.test(norm) &&
29
+ (norm.includes("/@rangojs/router/") ||
30
+ norm.includes("/packages/rangojs-router/"))
31
+ );
32
+ }
33
+
34
+ /**
35
+ * Transform: replace the module with the resolved literal.
36
+ * Returns null for any module that is not the router's internal-debug module.
37
+ */
38
+ export function injectClientDebugFlag(
39
+ id: string,
40
+ ): { code: string; map: null } | null {
41
+ // Cheap early-out: this hook runs on every module in every environment.
42
+ if (!isRouterInternalDebugId(id)) return null;
43
+ // Emit the whole module: internal-debug.ts has a single export, kept in sync.
44
+ return {
45
+ code: `export const INTERNAL_RANGO_DEBUG = ${!!process.env.INTERNAL_RANGO_DEBUG};\n`,
46
+ map: null,
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Dev middleware companion: serve the internal-debug module `no-cache` so the
52
+ * browser revalidates it (etag) instead of trusting an immutable cache entry.
53
+ *
54
+ * Why: the transform bakes the flag into module CONTENT, but a published
55
+ * consumer resolves the module into node_modules, where dev serves it as
56
+ * `internal-debug.ts?v=<hash>` with `Cache-Control: max-age=31536000,immutable`.
57
+ * That `?v=` hash does not vary with env vars (verified on Vite 8: getConfigHash
58
+ * hashes NODE_ENV, resolve, plugin names, optimizeDeps -- not arbitrary env
59
+ * state), so toggling the flag changed the content under an unchanged immutable
60
+ * URL: a browser that ever loaded the app with the flag off kept the
61
+ * baked-`false` module across dev-server restarts, and INTERNAL_RANGO_DEBUG
62
+ * never reached the FE logs while the server logs worked. The monorepo was
63
+ * immune -- workspace source is outside node_modules and served no-cache --
64
+ * which is why this bit only npm consumers.
65
+ *
66
+ * internal-debug.ts is the ONLY flag-varying module in the graph (its importers
67
+ * are byte-identical across flag states), so forcing revalidation for this one
68
+ * tiny module is sufficient and costs one conditional request per session. The
69
+ * middleware is unconditional (not gated on the flag) so an already-poisoned
70
+ * cache heals in both directions. Alternatives that do not work: a plugin
71
+ * `resolveId` appending a flag query never fires in Vite 8 dev for
72
+ * fs-resolvable relative imports, and the pre-#621 `define` no longer rotates
73
+ * the optimizer hash (define contents are not part of getConfigHash).
74
+ */
75
+ export function internalDebugNoCacheMiddleware(): Connect.NextHandleFunction {
76
+ return function rangoInternalDebugNoCache(req, res, next) {
77
+ if (req.url && isRouterInternalDebugId(req.url)) {
78
+ const setHeader = res.setHeader.bind(res);
79
+ res.setHeader = (name, value) => {
80
+ return setHeader(
81
+ name,
82
+ name.toLowerCase() === "cache-control" ? "no-cache" : value,
83
+ );
84
+ };
85
+ }
86
+ next();
87
+ };
88
+ }