@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650

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 (356) hide show
  1. package/README.md +24 -9
  2. package/dist/bin/rango.js +157 -63
  3. package/dist/testing/vitest.js +82 -0
  4. package/dist/vite/index.js +1584 -639
  5. package/package.json +71 -21
  6. package/skills/api-client/SKILL.md +211 -0
  7. package/skills/breadcrumbs/SKILL.md +60 -0
  8. package/skills/bundle-analysis/SKILL.md +159 -0
  9. package/skills/cache-guide/SKILL.md +222 -30
  10. package/skills/caching/SKILL.md +263 -8
  11. package/skills/composability/SKILL.md +27 -2
  12. package/skills/css/SKILL.md +76 -0
  13. package/skills/document-cache/SKILL.md +78 -55
  14. package/skills/handler-use/SKILL.md +3 -1
  15. package/skills/hooks/SKILL.md +235 -28
  16. package/skills/host-router/SKILL.md +122 -22
  17. package/skills/i18n/SKILL.md +276 -0
  18. package/skills/intercept/SKILL.md +29 -5
  19. package/skills/layout/SKILL.md +13 -9
  20. package/skills/links/SKILL.md +173 -17
  21. package/skills/loader/SKILL.md +170 -23
  22. package/skills/middleware/SKILL.md +16 -10
  23. package/skills/migrate-nextjs/SKILL.md +38 -16
  24. package/skills/mime-routes/SKILL.md +27 -0
  25. package/skills/observability/SKILL.md +137 -0
  26. package/skills/parallel/SKILL.md +11 -7
  27. package/skills/prerender/SKILL.md +14 -33
  28. package/skills/rango/SKILL.md +250 -25
  29. package/skills/react-compiler/SKILL.md +168 -0
  30. package/skills/response-routes/SKILL.md +114 -47
  31. package/skills/route/SKILL.md +42 -5
  32. package/skills/router-setup/SKILL.md +3 -3
  33. package/skills/server-actions/SKILL.md +78 -42
  34. package/skills/tailwind/SKILL.md +27 -3
  35. package/skills/testing/SKILL.md +129 -0
  36. package/skills/testing/bindings.md +89 -0
  37. package/skills/testing/cache-prerender.md +124 -0
  38. package/skills/testing/client-components.md +122 -0
  39. package/skills/testing/e2e-parity.md +125 -0
  40. package/skills/testing/flight.md +92 -0
  41. package/skills/testing/handles.md +129 -0
  42. package/skills/testing/loader.md +128 -0
  43. package/skills/testing/middleware.md +99 -0
  44. package/skills/testing/render-handler.md +121 -0
  45. package/skills/testing/response-routes.md +95 -0
  46. package/skills/testing/reverse-and-types.md +84 -0
  47. package/skills/testing/server-actions.md +107 -0
  48. package/skills/testing/server-tree.md +128 -0
  49. package/skills/testing/setup.md +120 -0
  50. package/skills/typesafety/SKILL.md +316 -26
  51. package/skills/use-cache/SKILL.md +36 -5
  52. package/skills/vercel/SKILL.md +107 -0
  53. package/skills/view-transitions/SKILL.md +294 -0
  54. package/src/__augment-tests__/augment.ts +81 -0
  55. package/src/__augment-tests__/augmented.check.ts +116 -0
  56. package/src/__internal.ts +0 -65
  57. package/src/browser/action-coordinator.ts +53 -36
  58. package/src/browser/action-fence.ts +47 -0
  59. package/src/browser/app-shell.ts +14 -27
  60. package/src/browser/cookie-name.ts +140 -0
  61. package/src/browser/event-controller.ts +37 -143
  62. package/src/browser/history-state.ts +21 -0
  63. package/src/browser/index.ts +3 -3
  64. package/src/browser/invalidate-client-cache.ts +52 -0
  65. package/src/browser/navigation-bridge.ts +30 -59
  66. package/src/browser/navigation-client.ts +96 -84
  67. package/src/browser/navigation-store-handle.ts +38 -0
  68. package/src/browser/navigation-store.ts +32 -82
  69. package/src/browser/navigation-transaction.ts +9 -59
  70. package/src/browser/partial-update.ts +60 -127
  71. package/src/browser/prefetch/cache.ts +82 -72
  72. package/src/browser/prefetch/fetch.ts +108 -33
  73. package/src/browser/prefetch/queue.ts +6 -3
  74. package/src/browser/rango-state.ts +157 -115
  75. package/src/browser/react/Link.tsx +0 -2
  76. package/src/browser/react/NavigationProvider.tsx +41 -48
  77. package/src/browser/react/ScrollRestoration.tsx +10 -6
  78. package/src/browser/react/filter-segment-order.ts +0 -2
  79. package/src/browser/react/index.ts +0 -48
  80. package/src/browser/react/location-state-shared.ts +166 -8
  81. package/src/browser/react/location-state.ts +39 -14
  82. package/src/browser/react/use-action.ts +6 -15
  83. package/src/browser/react/use-handle.ts +17 -14
  84. package/src/browser/react/use-link-status.ts +0 -4
  85. package/src/browser/react/use-navigation.ts +0 -3
  86. package/src/browser/react/use-params.ts +11 -11
  87. package/src/browser/react/use-reverse.ts +106 -0
  88. package/src/browser/react/use-router.ts +20 -5
  89. package/src/browser/react/use-search-params.ts +0 -5
  90. package/src/browser/react/use-segments.ts +0 -13
  91. package/src/browser/response-adapter.ts +52 -1
  92. package/src/browser/rsc-router.tsx +70 -34
  93. package/src/browser/scroll-restoration.ts +22 -14
  94. package/src/browser/segment-structure-assert.ts +2 -2
  95. package/src/browser/server-action-bridge.ts +168 -44
  96. package/src/browser/types.ts +36 -21
  97. package/src/browser/validate-redirect-origin.ts +43 -16
  98. package/src/build/collect-fallback-refs.ts +107 -0
  99. package/src/build/generate-manifest.ts +60 -35
  100. package/src/build/generate-route-types.ts +3 -0
  101. package/src/build/index.ts +8 -2
  102. package/src/build/prefix-tree-utils.ts +123 -0
  103. package/src/build/route-trie.ts +89 -10
  104. package/src/build/route-types/codegen.ts +4 -4
  105. package/src/build/route-types/include-resolution.ts +1 -1
  106. package/src/build/route-types/param-extraction.ts +6 -3
  107. package/src/build/route-types/per-module-writer.ts +7 -4
  108. package/src/build/route-types/router-processing.ts +122 -22
  109. package/src/build/route-types/scan-filter.ts +1 -1
  110. package/src/build/route-types/source-scan.ts +118 -0
  111. package/src/build/runtime-discovery.ts +9 -20
  112. package/src/cache/cache-error.ts +104 -0
  113. package/src/cache/cache-policy.ts +68 -28
  114. package/src/cache/cache-runtime.ts +134 -32
  115. package/src/cache/cache-scope.ts +100 -74
  116. package/src/cache/cache-tag.ts +98 -0
  117. package/src/cache/cf/cf-cache-store.ts +2255 -238
  118. package/src/cache/cf/index.ts +6 -16
  119. package/src/cache/document-cache.ts +61 -20
  120. package/src/cache/handle-snapshot.ts +63 -0
  121. package/src/cache/index.ts +22 -20
  122. package/src/cache/memory-segment-store.ts +136 -37
  123. package/src/cache/profile-registry.ts +6 -30
  124. package/src/cache/read-through-swr.ts +41 -11
  125. package/src/cache/segment-codec.ts +0 -16
  126. package/src/cache/tag-invalidation.ts +230 -0
  127. package/src/cache/types.ts +33 -100
  128. package/src/cache/vercel/index.ts +11 -0
  129. package/src/cache/vercel/vercel-cache-store.ts +799 -0
  130. package/src/client.rsc.tsx +6 -21
  131. package/src/client.tsx +25 -61
  132. package/src/component-utils.ts +19 -0
  133. package/src/context-var.ts +17 -5
  134. package/src/decode-loader-results.ts +36 -0
  135. package/src/defer.ts +196 -0
  136. package/src/deps/ssr.ts +0 -1
  137. package/src/errors.ts +30 -4
  138. package/src/handle.ts +31 -23
  139. package/src/handles/MetaTags.tsx +0 -14
  140. package/src/handles/breadcrumbs.ts +16 -5
  141. package/src/handles/meta.ts +0 -39
  142. package/src/host/cookie-handler.ts +0 -36
  143. package/src/host/errors.ts +0 -24
  144. package/src/host/index.ts +8 -2
  145. package/src/host/pattern-matcher.ts +7 -50
  146. package/src/host/router.ts +107 -99
  147. package/src/host/testing.ts +40 -27
  148. package/src/host/types.ts +37 -4
  149. package/src/host/utils.ts +1 -1
  150. package/src/href-client.ts +137 -22
  151. package/src/index.rsc.ts +63 -9
  152. package/src/index.ts +64 -9
  153. package/src/internal-debug.ts +2 -4
  154. package/src/loader-store.ts +500 -0
  155. package/src/loader.rsc.ts +20 -13
  156. package/src/loader.ts +12 -11
  157. package/src/missing-id-error.ts +68 -0
  158. package/src/network-error-thrower.tsx +1 -6
  159. package/src/outlet-provider.tsx +1 -5
  160. package/src/prerender/param-hash.ts +10 -11
  161. package/src/prerender/store.ts +32 -37
  162. package/src/prerender.ts +61 -6
  163. package/src/redirect-origin.ts +100 -0
  164. package/src/response-utils.ts +9 -0
  165. package/src/reverse.ts +65 -40
  166. package/src/root-error-boundary.tsx +1 -19
  167. package/src/route-content-wrapper.tsx +7 -72
  168. package/src/route-definition/dsl-helpers.ts +244 -281
  169. package/src/route-definition/helper-factories.ts +29 -139
  170. package/src/route-definition/helpers-types.ts +40 -17
  171. package/src/route-definition/redirect.ts +43 -9
  172. package/src/route-definition/resolve-handler-use.ts +6 -0
  173. package/src/route-definition/use-item-types.ts +32 -0
  174. package/src/route-map-builder.ts +0 -16
  175. package/src/route-types.ts +19 -41
  176. package/src/router/basename.ts +14 -0
  177. package/src/router/content-negotiation.ts +15 -15
  178. package/src/router/error-handling.ts +13 -17
  179. package/src/router/find-match.ts +44 -23
  180. package/src/router/handler-context.ts +4 -41
  181. package/src/router/intercept-resolution.ts +14 -19
  182. package/src/router/lazy-includes.ts +9 -46
  183. package/src/router/loader-resolution.ts +91 -46
  184. package/src/router/logging.ts +0 -6
  185. package/src/router/manifest.ts +18 -29
  186. package/src/router/match-api.ts +0 -20
  187. package/src/router/match-context.ts +0 -22
  188. package/src/router/match-handlers.ts +57 -58
  189. package/src/router/match-middleware/background-revalidation.ts +0 -7
  190. package/src/router/match-middleware/cache-lookup.ts +150 -271
  191. package/src/router/match-middleware/cache-store.ts +3 -33
  192. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  193. package/src/router/match-middleware/segment-resolution.ts +0 -22
  194. package/src/router/match-pipelines.ts +1 -42
  195. package/src/router/match-result.ts +31 -80
  196. package/src/router/metrics.ts +0 -34
  197. package/src/router/middleware-types.ts +5 -112
  198. package/src/router/middleware.ts +118 -133
  199. package/src/router/navigation-snapshot.ts +0 -51
  200. package/src/router/params-util.ts +23 -0
  201. package/src/router/pattern-matching.ts +62 -67
  202. package/src/router/prerender-match.ts +99 -63
  203. package/src/router/preview-match.ts +3 -1
  204. package/src/router/request-classification.ts +28 -62
  205. package/src/router/revalidation.ts +50 -56
  206. package/src/router/route-snapshot.ts +0 -1
  207. package/src/router/router-context.ts +0 -27
  208. package/src/router/router-interfaces.ts +68 -35
  209. package/src/router/router-options.ts +55 -1
  210. package/src/router/router-registry.ts +2 -5
  211. package/src/router/segment-resolution/fresh.ts +44 -63
  212. package/src/router/segment-resolution/helpers.ts +34 -0
  213. package/src/router/segment-resolution/loader-cache.ts +40 -37
  214. package/src/router/segment-resolution/revalidation.ts +203 -285
  215. package/src/router/segment-resolution/static-store.ts +19 -5
  216. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  217. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  218. package/src/router/segment-resolution.ts +4 -1
  219. package/src/router/segment-wrappers.ts +0 -3
  220. package/src/router/state-cookie-name.ts +33 -0
  221. package/src/router/substitute-pattern-params.ts +56 -0
  222. package/src/router/telemetry-otel.ts +0 -20
  223. package/src/router/telemetry.ts +96 -19
  224. package/src/router/timeout.ts +0 -20
  225. package/src/router/trie-matching.ts +87 -48
  226. package/src/router/types.ts +9 -63
  227. package/src/router/url-params.ts +0 -5
  228. package/src/router.ts +80 -41
  229. package/src/rsc/handler-context.ts +3 -2
  230. package/src/rsc/handler.ts +83 -78
  231. package/src/rsc/helpers.ts +93 -5
  232. package/src/rsc/index.ts +1 -1
  233. package/src/rsc/json-route-result.ts +38 -0
  234. package/src/rsc/manifest-init.ts +28 -41
  235. package/src/rsc/origin-guard.ts +39 -25
  236. package/src/rsc/progressive-enhancement.ts +12 -1
  237. package/src/rsc/redirect-guard.ts +99 -0
  238. package/src/rsc/response-error.ts +79 -12
  239. package/src/rsc/response-route-handler.ts +76 -62
  240. package/src/rsc/rsc-rendering.ts +41 -60
  241. package/src/rsc/runtime-warnings.ts +23 -10
  242. package/src/rsc/server-action.ts +62 -67
  243. package/src/rsc/ssr-setup.ts +16 -0
  244. package/src/rsc/types.ts +10 -5
  245. package/src/runtime-env.ts +18 -0
  246. package/src/search-params.ts +4 -20
  247. package/src/segment-loader-promise.ts +14 -2
  248. package/src/segment-system.tsx +199 -142
  249. package/src/serialize.ts +243 -0
  250. package/src/server/context.ts +150 -51
  251. package/src/server/cookie-store.ts +80 -5
  252. package/src/server/handle-store.ts +7 -24
  253. package/src/server/loader-registry.ts +5 -24
  254. package/src/server/request-context.ts +165 -87
  255. package/src/ssr/index.tsx +14 -14
  256. package/src/static-handler.ts +10 -13
  257. package/src/testing/cache-status.ts +162 -0
  258. package/src/testing/collect-handle.ts +40 -0
  259. package/src/testing/dispatch.ts +618 -0
  260. package/src/testing/dom.entry.ts +22 -0
  261. package/src/testing/e2e/fixture.ts +188 -0
  262. package/src/testing/e2e/index.ts +128 -0
  263. package/src/testing/e2e/matchers.ts +35 -0
  264. package/src/testing/e2e/page-helpers.ts +272 -0
  265. package/src/testing/e2e/parity.ts +387 -0
  266. package/src/testing/e2e/server.ts +195 -0
  267. package/src/testing/flight-matchers.ts +97 -0
  268. package/src/testing/flight-normalize.ts +11 -0
  269. package/src/testing/flight-runtime.d.ts +57 -0
  270. package/src/testing/flight-tree.ts +682 -0
  271. package/src/testing/flight.entry.ts +52 -0
  272. package/src/testing/flight.ts +232 -0
  273. package/src/testing/generated-routes.ts +183 -0
  274. package/src/testing/index.ts +99 -0
  275. package/src/testing/internal/context.ts +348 -0
  276. package/src/testing/internal/flight-client-globals.ts +30 -0
  277. package/src/testing/internal/seed-vars.ts +54 -0
  278. package/src/testing/render-handler.ts +330 -0
  279. package/src/testing/render-route.tsx +566 -0
  280. package/src/testing/run-loader.ts +378 -0
  281. package/src/testing/run-middleware.ts +205 -0
  282. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  283. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  284. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  285. package/src/testing/vitest-stubs/version.ts +5 -0
  286. package/src/testing/vitest.ts +305 -0
  287. package/src/theme/ThemeProvider.tsx +0 -52
  288. package/src/theme/ThemeScript.tsx +0 -6
  289. package/src/theme/constants.ts +0 -12
  290. package/src/theme/index.ts +0 -7
  291. package/src/theme/theme-context.ts +1 -5
  292. package/src/theme/theme-script.ts +0 -14
  293. package/src/theme/use-theme.ts +0 -3
  294. package/src/types/boundaries.ts +0 -35
  295. package/src/types/cache-types.ts +13 -4
  296. package/src/types/error-types.ts +30 -90
  297. package/src/types/global-namespace.ts +54 -41
  298. package/src/types/handler-context.ts +97 -22
  299. package/src/types/index.ts +1 -10
  300. package/src/types/loader-types.ts +6 -3
  301. package/src/types/request-scope.ts +0 -19
  302. package/src/types/route-config.ts +6 -50
  303. package/src/types/route-entry.ts +0 -6
  304. package/src/types/segments.ts +18 -14
  305. package/src/urls/include-helper.ts +9 -56
  306. package/src/urls/index.ts +1 -11
  307. package/src/urls/path-helper-types.ts +19 -5
  308. package/src/urls/path-helper.ts +17 -106
  309. package/src/urls/pattern-types.ts +36 -19
  310. package/src/urls/response-types.ts +20 -19
  311. package/src/urls/type-extraction.ts +58 -139
  312. package/src/urls/urls-function.ts +1 -18
  313. package/src/use-loader.tsx +292 -107
  314. package/src/vite/debug.ts +1 -0
  315. package/src/vite/discovery/bundle-postprocess.ts +8 -7
  316. package/src/vite/discovery/discover-routers.ts +95 -82
  317. package/src/vite/discovery/discovery-errors.ts +194 -0
  318. package/src/vite/discovery/prerender-collection.ts +26 -34
  319. package/src/vite/discovery/route-types-writer.ts +40 -84
  320. package/src/vite/discovery/state.ts +39 -1
  321. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  322. package/src/vite/index.ts +4 -0
  323. package/src/vite/plugin-types.ts +185 -10
  324. package/src/vite/plugins/cjs-to-esm.ts +3 -18
  325. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  326. package/src/vite/plugins/client-ref-hashing.ts +12 -11
  327. package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
  328. package/src/vite/plugins/expose-action-id.ts +4 -75
  329. package/src/vite/plugins/expose-id-utils.ts +3 -54
  330. package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
  331. package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
  332. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
  333. package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
  334. package/src/vite/plugins/expose-internal-ids.ts +57 -67
  335. package/src/vite/plugins/performance-tracks.ts +9 -16
  336. package/src/vite/plugins/refresh-cmd.ts +1 -1
  337. package/src/vite/plugins/use-cache-transform.ts +26 -49
  338. package/src/vite/plugins/vercel-output.ts +258 -0
  339. package/src/vite/plugins/version-injector.ts +2 -32
  340. package/src/vite/plugins/version-plugin.ts +32 -23
  341. package/src/vite/plugins/virtual-entries.ts +35 -17
  342. package/src/vite/rango.ts +148 -115
  343. package/src/vite/router-discovery.ts +220 -68
  344. package/src/vite/utils/ast-handler-extract.ts +15 -31
  345. package/src/vite/utils/bundle-analysis.ts +10 -15
  346. package/src/vite/utils/client-chunks.ts +184 -0
  347. package/src/vite/utils/forward-user-plugins.ts +171 -0
  348. package/src/vite/utils/manifest-utils.ts +4 -59
  349. package/src/vite/utils/package-resolution.ts +1 -73
  350. package/src/vite/utils/prerender-utils.ts +0 -34
  351. package/src/vite/utils/shared-utils.ts +95 -43
  352. package/src/browser/action-response-classifier.ts +0 -99
  353. package/src/browser/react/use-client-cache.ts +0 -58
  354. package/src/browser/shallow.ts +0 -40
  355. package/src/handles/index.ts +0 -7
  356. package/src/router/middleware-cookies.ts +0 -55
package/README.md CHANGED
@@ -602,7 +602,7 @@ export function Nav({ home, post }: { home: string; post: string }) {
602
602
  }
603
603
  ```
604
604
 
605
- For client-side navigation to static paths (no named-route lookup), use `href()` — see below. For URLs tied to named routes, always generate on the server and pass the string in.
605
+ For client-side navigation to static paths (no named-route lookup), use `href()` — see below. For URLs tied to named routes, you have two options: import the per-module generated `routes` map and use `useReverse(routes)` for in-module names (see [`/links` skill](./skills/links/SKILL.md)), or generate the URL on the server and pass the string in for cross-module URLs.
606
606
 
607
607
  ### `href()` for Path Validation (Client Components)
608
608
 
@@ -943,9 +943,9 @@ import { createHostRouter } from "@rangojs/router/host";
943
943
 
944
944
  const hostRouter = createHostRouter();
945
945
 
946
- hostRouter.host(["*.localhost"]).map(() => import("./apps/admin/handler.js"));
947
- hostRouter.host(["localhost"]).map(() => import("./apps/site/handler.js"));
948
- hostRouter.fallback().map(() => import("./apps/site/handler.js"));
946
+ hostRouter.host(["*.localhost"]).lazy(() => import("./apps/admin/handler.js"));
947
+ hostRouter.host(["localhost"]).lazy(() => import("./apps/site/handler.js"));
948
+ hostRouter.fallback().lazy(() => import("./apps/site/handler.js"));
949
949
 
950
950
  export default {
951
951
  async fetch(request, env, ctx) {
@@ -954,7 +954,22 @@ export default {
954
954
  };
955
955
  ```
956
956
 
957
- Each sub-app has its own `createRouter()` and `urls()`. The host router lazily imports the matched app's handler. Patterns are matched in registration order — register more specific patterns (subdomains) before catch-alls.
957
+ Use `.lazy(() => import("./sub-app"))` to mount a lazily-imported sub-app (a module whose `default` export is a handler or nested host router), and `.map((request) => Response)` for an inline request handler. Only `.lazy()` mounts are imported during build-time discovery; `.map(() => import(...))` is a type error. Each sub-app has its own `createRouter()` and `urls()`. Patterns are matched in registration order — register more specific patterns (subdomains) before catch-alls.
958
+
959
+ The example above is the **Cloudflare** shape, where you own the worker entry. On the **node/vercel** presets rango owns the served entry, so export the `HostRouter` instance instead of a `{ fetch }` object, and point `rango()` at it (a host app has several `createRouter()` sub-apps, so set `host`; rango also auto-detects a lone `createHostRouter()` file):
960
+
961
+ ```tsx
962
+ // worker.rsc.tsx
963
+ export const hostRouter = createHostRouter();
964
+ hostRouter.host(["admin.*"]).lazy(() => import("./apps/admin/handler.js"));
965
+ hostRouter.host(["."]).lazy(() => import("./apps/site/handler.js"));
966
+ export default hostRouter; // the instance — the generated entry calls match()
967
+
968
+ // vite.config.ts
969
+ rango({ preset: "vercel", host: "./src/worker.rsc.tsx" });
970
+ ```
971
+
972
+ On Vercel this is a single function running `hostRouter.match()` for every request. See the `host-router` and `vercel` skills.
958
973
 
959
974
  ## Meta Tags
960
975
 
@@ -993,16 +1008,16 @@ Auto-detects file type:
993
1008
 
994
1009
  ## Type Safety
995
1010
 
996
- The Vite plugin automatically generates a `router.named-routes.gen.ts` file that globally registers route names, patterns, and search schemas via `RSCRouter.GeneratedRouteMap`. This powers server-side named-route typing such as `Handler<"name">`, `ctx.reverse()`, `getRequestContext().reverse()`, and `RouteParams<"name">` without any manual route registration. The gen file is updated on dev server startup, HMR, and production builds.
1011
+ The Vite plugin automatically generates a `router.named-routes.gen.ts` file that globally registers route names, patterns, and search schemas via `Rango.GeneratedRouteMap`. This powers server-side named-route typing such as `Handler<"name">`, `ctx.reverse()`, `getRequestContext().reverse()`, and `RouteParams<"name">` without any manual route registration. The gen file is updated on dev server startup, HMR, and production builds.
997
1012
 
998
- Use the generated map by default. Augment `RSCRouter.RegisteredRoutes` only when you need the richer `typeof router.routeMap` shape globally, especially for response-aware and path-based utilities.
1013
+ Use the generated map by default. Augment `Rango.RegisteredRoutes` only when you need the richer `typeof router.routeMap` shape globally, especially for response-aware and path-based utilities.
999
1014
 
1000
1015
  ```typescript
1001
1016
  // router.tsx
1002
1017
  const router = createRouter<AppBindings>({}).routes(urlpatterns);
1003
1018
 
1004
1019
  declare global {
1005
- namespace RSCRouter {
1020
+ namespace Rango {
1006
1021
  interface Env extends AppEnv {}
1007
1022
  interface Vars extends AppVars {}
1008
1023
  interface RegisteredRoutes extends typeof router.routeMap {}
@@ -1014,7 +1029,7 @@ Quick rule of thumb:
1014
1029
 
1015
1030
  - `GeneratedRouteMap` (auto-generated) — use for server-side named-route typing: `Handler<"name">`, `ctx.reverse()`, `Prerender<"name">`
1016
1031
  - `typeof router.routeMap` — use when you need route entries with response metadata
1017
- - `RegisteredRoutes` (manual augmentation) — use to expose `typeof router.routeMap` globally for `href()`, `PathResponse`, `ValidPaths`, and other path/response-aware utilities
1032
+ - `RegisteredRoutes` (manual augmentation) — use to expose `typeof router.routeMap` globally for `href()`, `Rango.Path`, `Rango.PathResponse`, and other path/response-aware utilities
1018
1033
 
1019
1034
  For extracted reusable loaders or middleware, prefer global dotted names on
1020
1035
  `ctx.reverse()` by default. If you want type-safe local names for a specific
package/dist/bin/rango.js CHANGED
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __esm = (fn, res) => function __init() {
5
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ var __esm = (fn, res, err) => function __init() {
5
+ if (err) throw err[0];
6
+ try {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ } catch (e) {
9
+ throw err = [e], e;
10
+ }
6
11
  };
7
12
  var __export = (target, all) => {
8
13
  for (var name in all)
@@ -22,10 +27,10 @@ function extractParamsFromPattern(pattern) {
22
27
  function formatRouteEntry(key, pattern, _params, search) {
23
28
  const hasSearch = search && Object.keys(search).length > 0;
24
29
  if (!hasSearch) {
25
- return ` ${key}: "${pattern}",`;
30
+ return ` ${key}: ${JSON.stringify(pattern)},`;
26
31
  }
27
- const searchBody = Object.entries(search).map(([k, v]) => `${k}: "${v}"`).join(", ");
28
- return ` ${key}: { path: "${pattern}", search: { ${searchBody} } },`;
32
+ const searchBody = Object.entries(search).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ");
33
+ return ` ${key}: { path: ${JSON.stringify(pattern)}, search: { ${searchBody} } },`;
29
34
  }
30
35
  var init_param_extraction = __esm({
31
36
  "src/build/route-types/param-extraction.ts"() {
@@ -139,7 +144,7 @@ function generatePerModuleTypesSource(routes) {
139
144
  const valid = routes.filter(({ name }) => {
140
145
  if (!name || /["'\\`\n\r]/.test(name)) {
141
146
  console.warn(
142
- `[rsc-router] Skipping route with invalid name: ${JSON.stringify(name)}`
147
+ `[rango] Skipping route with invalid name: ${JSON.stringify(name)}`
143
148
  );
144
149
  return false;
145
150
  }
@@ -149,7 +154,7 @@ function generatePerModuleTypesSource(routes) {
149
154
  for (const { name, pattern, params, search } of valid) {
150
155
  if (deduped.has(name)) {
151
156
  console.warn(
152
- `[rsc-router] Duplicate route name "${name}" \u2014 keeping first definition`
157
+ `[rango] Duplicate route name "${name}" \u2014 keeping first definition`
153
158
  );
154
159
  continue;
155
160
  }
@@ -186,7 +191,7 @@ ${objectBody}
186
191
  } as const;
187
192
 
188
193
  declare global {
189
- namespace RSCRouter {
194
+ namespace Rango {
190
195
  interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
191
196
  }
192
197
  }
@@ -211,7 +216,7 @@ function findTsFiles(dir, filter) {
211
216
  entries = readdirSync(dir, { withFileTypes: true });
212
217
  } catch (err) {
213
218
  console.warn(
214
- `[rsc-router] Failed to scan directory ${dir}: ${err.message}`
219
+ `[rango] Failed to scan directory ${dir}: ${err.message}`
215
220
  );
216
221
  return results;
217
222
  }
@@ -456,7 +461,7 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
456
461
  const realPath = resolve(filePath);
457
462
  const key = variableName ? `${realPath}:${variableName}` : realPath;
458
463
  if (visited.has(key)) {
459
- console.warn(`[rsc-router] Circular include detected, skipping: ${key}`);
464
+ console.warn(`[rango] Circular include detected, skipping: ${key}`);
460
465
  return { routes: {}, searchSchemas: {} };
461
466
  }
462
467
  visited.add(key);
@@ -543,12 +548,12 @@ function writePerModuleRouteTypesForFile(filePath) {
543
548
  } else {
544
549
  routes = extractRoutesFromSource(source);
545
550
  }
546
- const genPath = filePath.replace(/\.(tsx?)$/, ".gen.ts");
551
+ const genPath = filePath.replace(/\.(tsx?|jsx?)$/, ".gen.ts");
547
552
  if (routes.length === 0) {
548
553
  if (varNames.length > 0 && !existsSync2(genPath)) {
549
554
  writeFileSync(genPath, generatePerModuleTypesSource([]));
550
555
  console.log(
551
- `[rsc-router] Generated route types (placeholder) -> ${genPath}`
556
+ `[rango] Generated route types (placeholder) -> ${genPath}`
552
557
  );
553
558
  }
554
559
  return;
@@ -557,11 +562,11 @@ function writePerModuleRouteTypesForFile(filePath) {
557
562
  const existing = existsSync2(genPath) ? readFileSync2(genPath, "utf-8") : null;
558
563
  if (existing !== genSource) {
559
564
  writeFileSync(genPath, genSource);
560
- console.log(`[rsc-router] Generated route types -> ${genPath}`);
565
+ console.log(`[rango] Generated route types -> ${genPath}`);
561
566
  }
562
567
  } catch (err) {
563
568
  console.warn(
564
- `[rsc-router] Failed to generate route types for ${filePath}: ${err.message}`
569
+ `[rango] Failed to generate route types for ${filePath}: ${err.message}`
565
570
  );
566
571
  }
567
572
  }
@@ -576,6 +581,75 @@ var init_per_module_writer = __esm({
576
581
  }
577
582
  });
578
583
 
584
+ // src/build/route-types/source-scan.ts
585
+ function isLineTerminator(ch) {
586
+ const c = ch.charCodeAt(0);
587
+ return c === 10 || c === 13 || c === 8232 || c === 8233;
588
+ }
589
+ function makeCodeClassifier(code) {
590
+ const n = code.length;
591
+ let i = 0;
592
+ let skipStart = -1;
593
+ let skipEnd = -1;
594
+ return (q) => {
595
+ if (q >= skipStart && q < skipEnd) return false;
596
+ while (i < n && i <= q) {
597
+ const c = code[i];
598
+ const d = i + 1 < n ? code[i + 1] : "";
599
+ let end = -1;
600
+ if (c === "/" && d === "/") {
601
+ let j = i + 2;
602
+ while (j < n && !isLineTerminator(code[j])) j++;
603
+ end = j;
604
+ } else if (c === "/" && d === "*") {
605
+ let j = i + 2;
606
+ while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++;
607
+ end = Math.min(n, j + 2);
608
+ } else if (c === '"' || c === "'" || c === "`") {
609
+ let j = i + 1;
610
+ while (j < n) {
611
+ if (code[j] === "\\") {
612
+ j += 2;
613
+ continue;
614
+ }
615
+ if (code[j] === c) {
616
+ j++;
617
+ break;
618
+ }
619
+ j++;
620
+ }
621
+ end = j;
622
+ }
623
+ if (end >= 0) {
624
+ if (q < end) {
625
+ skipStart = i;
626
+ skipEnd = end;
627
+ return false;
628
+ }
629
+ i = end;
630
+ } else {
631
+ i++;
632
+ }
633
+ }
634
+ return true;
635
+ };
636
+ }
637
+ function firstCodeMatchIndex(code, pattern) {
638
+ const inCode = makeCodeClassifier(code);
639
+ pattern.lastIndex = 0;
640
+ let m;
641
+ while ((m = pattern.exec(code)) !== null) {
642
+ if (inCode(m.index)) return m.index;
643
+ if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
644
+ }
645
+ return -1;
646
+ }
647
+ var init_source_scan = __esm({
648
+ "src/build/route-types/source-scan.ts"() {
649
+ "use strict";
650
+ }
651
+ });
652
+
579
653
  // src/build/route-types/router-processing.ts
580
654
  import {
581
655
  readFileSync as readFileSync3,
@@ -612,7 +686,7 @@ function findRouterFilesRecursive(dir, filter, results) {
612
686
  entries = readdirSync2(dir, { withFileTypes: true });
613
687
  } catch (err) {
614
688
  console.warn(
615
- `[rsc-router] Failed to scan directory ${dir}: ${err.message}`
689
+ `[rango] Failed to scan directory ${dir}: ${err.message}`
616
690
  );
617
691
  return;
618
692
  }
@@ -630,7 +704,7 @@ function findRouterFilesRecursive(dir, filter, results) {
630
704
  if (filter && !filter(fullPath)) continue;
631
705
  try {
632
706
  const source = readFileSync3(fullPath, "utf-8");
633
- if (ROUTER_CALL_PATTERN.test(source)) {
707
+ if (ROUTER_CALL_PATTERN.test(source) && firstCodeMatchIndex(source, ROUTER_CALL_PATTERN_G) >= 0) {
634
708
  routerFilesInDir.push(fullPath);
635
709
  }
636
710
  } catch {
@@ -668,7 +742,7 @@ function findNestedRouterConflict(routerFiles) {
668
742
  }
669
743
  return null;
670
744
  }
671
- function formatNestedRouterConflictError(conflict, prefix = "[rsc-router]") {
745
+ function formatNestedRouterConflictError(conflict, prefix = "[rango]") {
672
746
  return `${prefix} Nested router roots are not supported.
673
747
  Router root: ${conflict.ancestor}
674
748
  Nested router: ${conflict.nested}
@@ -764,19 +838,38 @@ function extractBasenameFromRouter(code) {
764
838
  visit(sourceFile);
765
839
  return result;
766
840
  }
767
- function applyBasenameToRoutes(result, basename2) {
841
+ function applyBasenameToRoutes(result, basename) {
768
842
  const prefixed = {};
769
843
  for (const [name, pattern] of Object.entries(result.routes)) {
770
844
  if (pattern === "/") {
771
- prefixed[name] = basename2;
772
- } else if (basename2.endsWith("/") && pattern.startsWith("/")) {
773
- prefixed[name] = basename2 + pattern.slice(1);
845
+ prefixed[name] = basename;
846
+ } else if (basename.endsWith("/") && pattern.startsWith("/")) {
847
+ prefixed[name] = basename + pattern.slice(1);
774
848
  } else {
775
- prefixed[name] = basename2 + pattern;
849
+ prefixed[name] = basename + pattern;
776
850
  }
777
851
  }
778
852
  return { routes: prefixed, searchSchemas: result.searchSchemas };
779
853
  }
854
+ function genFileTsPath(sourceFile) {
855
+ const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
856
+ return join2(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
857
+ }
858
+ function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
859
+ if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
860
+ return runtimeSchemas;
861
+ }
862
+ const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
863
+ if (Object.keys(staticParsed.searchSchemas).length === 0) {
864
+ return runtimeSchemas;
865
+ }
866
+ const filtered = {};
867
+ for (const name of publicRouteNames) {
868
+ const schema = staticParsed.searchSchemas[name];
869
+ if (schema) filtered[name] = schema;
870
+ }
871
+ return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
872
+ }
780
873
  function buildCombinedRouteMapForRouterFile(routerFilePath) {
781
874
  let routerSource;
782
875
  try {
@@ -789,7 +882,7 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
789
882
  return { routes: {}, searchSchemas: {} };
790
883
  }
791
884
  const rawBasename = extractBasenameFromRouter(routerSource);
792
- const basename2 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
885
+ const basename = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
793
886
  let result;
794
887
  if (extraction.kind === "inline") {
795
888
  result = buildCombinedRouteMapWithSearch(
@@ -814,8 +907,8 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
814
907
  result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
815
908
  }
816
909
  }
817
- if (basename2) {
818
- result = applyBasenameToRoutes(result, basename2);
910
+ if (basename) {
911
+ result = applyBasenameToRoutes(result, basename);
819
912
  }
820
913
  return result;
821
914
  }
@@ -897,7 +990,7 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
897
990
  if (existsSync3(oldCombinedPath)) {
898
991
  unlinkSync(oldCombinedPath);
899
992
  console.log(
900
- `[rsc-router] Removed stale combined route types: ${oldCombinedPath}`
993
+ `[rango] Removed stale combined route types: ${oldCombinedPath}`
901
994
  );
902
995
  }
903
996
  } catch {
@@ -919,18 +1012,12 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
919
1012
  }
920
1013
  if (!extractUrlsFromRouter(routerSource)) continue;
921
1014
  }
922
- const routerBasename = pathBasename(routerFilePath).replace(
923
- /\.(tsx?|jsx?)$/,
924
- ""
925
- );
926
- const outPath = join2(
927
- dirname2(routerFilePath),
928
- `${routerBasename}.named-routes.gen.ts`
929
- );
1015
+ const outPath = genFileTsPath(routerFilePath);
930
1016
  const existing = existsSync3(outPath) ? readFileSync3(outPath, "utf-8") : null;
931
1017
  if (Object.keys(result.routes).length === 0) {
932
1018
  if (!existing) {
933
1019
  const emptySource = generateRouteTypesSource({});
1020
+ opts?.onWrite?.(outPath, emptySource);
934
1021
  writeFileSync2(outPath, emptySource);
935
1022
  }
936
1023
  continue;
@@ -950,22 +1037,25 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
950
1037
  continue;
951
1038
  }
952
1039
  }
1040
+ opts?.onWrite?.(outPath, source);
953
1041
  writeFileSync2(outPath, source);
954
1042
  console.log(
955
- `[rsc-router] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
1043
+ `[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
956
1044
  );
957
1045
  }
958
1046
  }
959
1047
  }
960
- var ROUTER_CALL_PATTERN;
1048
+ var ROUTER_CALL_PATTERN, ROUTER_CALL_PATTERN_G;
961
1049
  var init_router_processing = __esm({
962
1050
  "src/build/route-types/router-processing.ts"() {
963
1051
  "use strict";
964
1052
  init_codegen();
1053
+ init_source_scan();
965
1054
  init_include_resolution();
966
1055
  init_per_module_writer();
967
1056
  init_route_name();
968
1057
  ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
1058
+ ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
969
1059
  }
970
1060
  });
971
1061
 
@@ -1003,7 +1093,7 @@ import {
1003
1093
  import { createElement, StrictMode } from "react";
1004
1094
  import { hydrateRoot } from "react-dom/client";
1005
1095
  import { rscStream } from "@rangojs/router/internal/deps/html-stream-client";
1006
- import { initBrowserApp, RSCRouter } from "@rangojs/router/browser";
1096
+ import { initBrowserApp, Rango } from "@rangojs/router/browser";
1007
1097
 
1008
1098
  async function initializeApp() {
1009
1099
  const deps = {
@@ -1018,7 +1108,7 @@ async function initializeApp() {
1018
1108
 
1019
1109
  hydrateRoot(
1020
1110
  document,
1021
- createElement(StrictMode, null, createElement(RSCRouter))
1111
+ createElement(StrictMode, null, createElement(Rango))
1022
1112
  );
1023
1113
  }
1024
1114
 
@@ -1050,7 +1140,8 @@ export const renderHTML = createSSRHandler({
1050
1140
  // src/vite/plugins/version-plugin.ts
1051
1141
  var version_plugin_exports = {};
1052
1142
  __export(version_plugin_exports, {
1053
- createVersionPlugin: () => createVersionPlugin
1143
+ createVersionPlugin: () => createVersionPlugin,
1144
+ isViteDepCachePath: () => isViteDepCachePath
1054
1145
  });
1055
1146
  import { parseAst } from "vite";
1056
1147
  function isCodeModule(id) {
@@ -1062,7 +1153,7 @@ function normalizeModuleId(id) {
1062
1153
  function getClientModuleSignature(source) {
1063
1154
  let program;
1064
1155
  try {
1065
- program = parseAst(source, { jsx: true });
1156
+ program = parseAst(source, { lang: "tsx" });
1066
1157
  } catch {
1067
1158
  return void 0;
1068
1159
  }
@@ -1145,11 +1236,12 @@ function createVersionPlugin() {
1145
1236
  let currentVersion = buildVersion;
1146
1237
  let isDev = false;
1147
1238
  let server = null;
1239
+ let resolvedCacheDir;
1148
1240
  const clientModuleSignatures = /* @__PURE__ */ new Map();
1149
1241
  let versionCounter = 0;
1150
1242
  const bumpVersion = (reason) => {
1151
1243
  currentVersion = Date.now().toString(16) + String(++versionCounter);
1152
- console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
1244
+ console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
1153
1245
  const rscEnv = server?.environments?.rsc;
1154
1246
  const versionMod = rscEnv?.moduleGraph?.getModuleById(
1155
1247
  "\0" + VIRTUAL_IDS.version
@@ -1163,6 +1255,7 @@ function createVersionPlugin() {
1163
1255
  enforce: "pre",
1164
1256
  configResolved(config) {
1165
1257
  isDev = config.command === "serve";
1258
+ resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
1166
1259
  },
1167
1260
  configureServer(devServer) {
1168
1261
  server = devServer;
@@ -1199,11 +1292,11 @@ function createVersionPlugin() {
1199
1292
  }
1200
1293
  return null;
1201
1294
  },
1202
- // Track RSC module changes and update version
1203
1295
  async hotUpdate(ctx) {
1204
1296
  if (!isDev) return;
1205
1297
  const isRscModule = this.environment?.name === "rsc";
1206
1298
  if (!isRscModule) return;
1299
+ if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
1207
1300
  if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
1208
1301
  return;
1209
1302
  }
@@ -1233,6 +1326,17 @@ function createVersionPlugin() {
1233
1326
  }
1234
1327
  };
1235
1328
  }
1329
+ function isViteDepCachePath(filePath, cacheDir) {
1330
+ if (!filePath) return false;
1331
+ const normalized = filePath.replace(/\\/g, "/");
1332
+ if (cacheDir) {
1333
+ const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
1334
+ if (normalized === normalizedCacheDir || normalized.startsWith(normalizedCacheDir + "/")) {
1335
+ return true;
1336
+ }
1337
+ }
1338
+ return /\/node_modules\/\.vite[^/]*\//.test(normalized) || normalized.includes("/.vite-isolated/");
1339
+ }
1236
1340
  var init_version_plugin = __esm({
1237
1341
  "src/vite/plugins/version-plugin.ts"() {
1238
1342
  "use strict";
@@ -1278,7 +1382,7 @@ var runtime_discovery_exports = {};
1278
1382
  __export(runtime_discovery_exports, {
1279
1383
  discoverAndWriteRouteTypes: () => discoverAndWriteRouteTypes
1280
1384
  });
1281
- import { dirname as dirname3, join as join3, basename, resolve as resolve3 } from "node:path";
1385
+ import { resolve as resolve3 } from "node:path";
1282
1386
  import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
1283
1387
  async function discoverAndWriteRouteTypes(opts) {
1284
1388
  let createViteServer;
@@ -1388,22 +1492,12 @@ This means createRouter() stack trace parsing matched an internal frame.
1388
1492
  Set an explicit \`id\` on createRouter() or check the call site.`
1389
1493
  );
1390
1494
  }
1391
- if (!routeSearchSchemas || Object.keys(routeSearchSchemas).length === 0) {
1392
- const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
1393
- if (Object.keys(staticParsed.searchSchemas).length > 0) {
1394
- const filtered = {};
1395
- for (const name of Object.keys(routeManifest)) {
1396
- const schema = staticParsed.searchSchemas[name];
1397
- if (schema) filtered[name] = schema;
1398
- }
1399
- if (Object.keys(filtered).length > 0) {
1400
- routeSearchSchemas = filtered;
1401
- }
1402
- }
1403
- }
1404
- const routerDir = dirname3(sourceFile);
1405
- const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
1406
- const outPath = join3(routerDir, `${routerBasename}.named-routes.gen.ts`);
1495
+ routeSearchSchemas = resolveSearchSchemas(
1496
+ Object.keys(routeManifest),
1497
+ routeSearchSchemas,
1498
+ sourceFile
1499
+ );
1500
+ const outPath = genFileTsPath(sourceFile);
1407
1501
  const source = generateRouteTypesSource(
1408
1502
  routeManifest,
1409
1503
  routeSearchSchemas && Object.keys(routeSearchSchemas).length > 0 ? routeSearchSchemas : void 0
@@ -1440,7 +1534,7 @@ var init_runtime_discovery = __esm({
1440
1534
 
1441
1535
  // src/bin/rango.ts
1442
1536
  init_generate_route_types();
1443
- import { resolve as resolve4, dirname as dirname4 } from "node:path";
1537
+ import { resolve as resolve4, dirname as dirname3 } from "node:path";
1444
1538
  import { readFileSync as readFileSync5, statSync, existsSync as existsSync5 } from "node:fs";
1445
1539
  var [command, ...rawArgs] = process.argv.slice(2);
1446
1540
  if (command === "generate") {
@@ -1511,12 +1605,12 @@ Examples:
1511
1605
  );
1512
1606
  }
1513
1607
  function findProjectRoot(fromPath) {
1514
- let dir = dirname4(resolve4(fromPath));
1515
- while (dir !== dirname4(dir)) {
1608
+ let dir = dirname3(resolve4(fromPath));
1609
+ while (dir !== dirname3(dir)) {
1516
1610
  if (existsSync5(resolve4(dir, "package.json")) || existsSync5(resolve4(dir, "vite.config.ts")) || existsSync5(resolve4(dir, "vite.config.js"))) {
1517
1611
  return dir;
1518
1612
  }
1519
- dir = dirname4(dir);
1613
+ dir = dirname3(dir);
1520
1614
  }
1521
1615
  return process.cwd();
1522
1616
  }
@@ -0,0 +1,82 @@
1
+ // src/testing/vitest.ts
2
+ import { fileURLToPath } from "node:url";
3
+ function here(relativeFromRoot) {
4
+ return fileURLToPath(new URL(`../../${relativeFromRoot}`, import.meta.url));
5
+ }
6
+ function rangoTestAliases(opts = {}) {
7
+ const aliases = [
8
+ // Real impls (index.rsc.ts) for the bare specifier ONLY — exact regex so
9
+ // subpaths (/testing, /client, /cache, ...) are untouched. React stays the
10
+ // client build, so createContext and "use client" modules work.
11
+ { find: /^@rangojs\/router$/, replacement: here("src/index.rsc.ts") },
12
+ {
13
+ find: "@rangojs/router:version",
14
+ replacement: here("src/testing/vitest-stubs/version.ts")
15
+ },
16
+ {
17
+ find: /^@vitejs\/plugin-rsc\/rsc$/,
18
+ replacement: here("src/testing/vitest-stubs/plugin-rsc.ts")
19
+ }
20
+ ];
21
+ if (opts.preset === "cloudflare") {
22
+ aliases.push(
23
+ {
24
+ find: "cloudflare:workers",
25
+ replacement: here("src/testing/vitest-stubs/cloudflare-workers.ts")
26
+ },
27
+ {
28
+ find: "cloudflare:email",
29
+ replacement: here("src/testing/vitest-stubs/cloudflare-email.ts")
30
+ }
31
+ );
32
+ }
33
+ return aliases;
34
+ }
35
+ var rangoInlineDeps = [/@rangojs[/\\]router/];
36
+ function rangoTestConfig(opts = {}) {
37
+ return {
38
+ alias: rangoTestAliases(opts),
39
+ // fresh copy so the shared rangoInlineDeps const is never aliased into (or
40
+ // mutated through) a consumer's resolved config
41
+ server: { deps: { inline: [...rangoInlineDeps] } }
42
+ };
43
+ }
44
+ function rangoUseClientTransform() {
45
+ return {
46
+ name: "rango:testing-use-client",
47
+ async transform(code, id) {
48
+ if (id.includes("/node_modules/")) return void 0;
49
+ if (!code.includes("use client")) return void 0;
50
+ const { parseAstAsync } = await import("vite");
51
+ const { hasDirective, transformDirectiveProxyExport } = await import("@vitejs/plugin-rsc/transforms");
52
+ let ast;
53
+ try {
54
+ ast = await parseAstAsync(code);
55
+ } catch {
56
+ return void 0;
57
+ }
58
+ if (!hasDirective(ast.body, "use client")) return void 0;
59
+ const result = transformDirectiveProxyExport(ast, {
60
+ directive: "use client",
61
+ code,
62
+ runtime: (name) => `$$RangoRSD.registerClientReference(() => { throw new Error("client reference " + ${JSON.stringify(name)} + " is not callable on the server"); }, ${JSON.stringify(id)}, ${JSON.stringify(name)})`
63
+ });
64
+ if (!result) return void 0;
65
+ const { output } = result;
66
+ output.prepend(
67
+ `import * as $$RangoRSD from "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge";
68
+ `
69
+ );
70
+ return {
71
+ code: output.toString(),
72
+ map: output.generateMap({ hires: true })
73
+ };
74
+ }
75
+ };
76
+ }
77
+ export {
78
+ rangoInlineDeps,
79
+ rangoTestAliases,
80
+ rangoTestConfig,
81
+ rangoUseClientTransform
82
+ };