@rangojs/router 0.0.0-experimental.31 → 0.0.0-experimental.3232cd17

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 (376) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +198 -44
  3. package/dist/bin/rango.js +287 -105
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3248 -1117
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +73 -21
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +107 -1
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +245 -21
  12. package/skills/caching/SKILL.md +302 -6
  13. package/skills/composability/SKILL.md +27 -2
  14. package/skills/css/SKILL.md +76 -0
  15. package/skills/document-cache/SKILL.md +78 -55
  16. package/skills/handler-use/SKILL.md +364 -0
  17. package/skills/hooks/SKILL.md +270 -30
  18. package/skills/host-router/SKILL.md +82 -22
  19. package/skills/i18n/SKILL.md +276 -0
  20. package/skills/intercept/SKILL.md +49 -5
  21. package/skills/layout/SKILL.md +35 -9
  22. package/skills/links/SKILL.md +249 -17
  23. package/skills/loader/SKILL.md +294 -30
  24. package/skills/middleware/SKILL.md +52 -13
  25. package/skills/migrate-nextjs/SKILL.md +584 -0
  26. package/skills/migrate-react-router/SKILL.md +769 -0
  27. package/skills/mime-routes/SKILL.md +27 -0
  28. package/skills/observability/SKILL.md +137 -0
  29. package/skills/parallel/SKILL.md +203 -7
  30. package/skills/prerender/SKILL.md +123 -100
  31. package/skills/rango/SKILL.md +250 -22
  32. package/skills/react-compiler/SKILL.md +168 -0
  33. package/skills/response-routes/SKILL.md +122 -47
  34. package/skills/route/SKILL.md +97 -5
  35. package/skills/router-setup/SKILL.md +90 -5
  36. package/skills/server-actions/SKILL.md +775 -0
  37. package/skills/streams-and-websockets/SKILL.md +283 -0
  38. package/skills/tailwind/SKILL.md +27 -3
  39. package/skills/testing/SKILL.md +129 -0
  40. package/skills/testing/bindings.md +89 -0
  41. package/skills/testing/cache-prerender.md +124 -0
  42. package/skills/testing/client-components.md +122 -0
  43. package/skills/testing/e2e-parity.md +125 -0
  44. package/skills/testing/flight.md +92 -0
  45. package/skills/testing/handles.md +129 -0
  46. package/skills/testing/loader.md +128 -0
  47. package/skills/testing/middleware.md +99 -0
  48. package/skills/testing/render-handler.md +121 -0
  49. package/skills/testing/response-routes.md +95 -0
  50. package/skills/testing/reverse-and-types.md +84 -0
  51. package/skills/testing/server-actions.md +107 -0
  52. package/skills/testing/server-tree.md +128 -0
  53. package/skills/testing/setup.md +120 -0
  54. package/skills/typesafety/SKILL.md +329 -27
  55. package/skills/use-cache/SKILL.md +36 -5
  56. package/skills/view-transitions/SKILL.md +294 -0
  57. package/src/__augment-tests__/augment.ts +81 -0
  58. package/src/__augment-tests__/augmented.check.ts +116 -0
  59. package/src/__internal.ts +67 -40
  60. package/src/browser/action-coordinator.ts +53 -36
  61. package/src/browser/action-fence.ts +47 -0
  62. package/src/browser/app-shell.ts +39 -0
  63. package/src/browser/app-version.ts +14 -0
  64. package/src/browser/cookie-name.ts +140 -0
  65. package/src/browser/event-controller.ts +86 -147
  66. package/src/browser/history-state.ts +21 -0
  67. package/src/browser/index.ts +3 -3
  68. package/src/browser/invalidate-client-cache.ts +52 -0
  69. package/src/browser/link-interceptor.ts +4 -0
  70. package/src/browser/navigation-bridge.ts +148 -19
  71. package/src/browser/navigation-client.ts +187 -67
  72. package/src/browser/navigation-store-handle.ts +38 -0
  73. package/src/browser/navigation-store.ts +76 -67
  74. package/src/browser/navigation-transaction.ts +18 -66
  75. package/src/browser/partial-update.ts +123 -94
  76. package/src/browser/prefetch/cache.ts +214 -36
  77. package/src/browser/prefetch/fetch.ts +260 -38
  78. package/src/browser/prefetch/policy.ts +6 -0
  79. package/src/browser/prefetch/queue.ts +126 -20
  80. package/src/browser/prefetch/resource-ready.ts +77 -0
  81. package/src/browser/rango-state.ts +158 -76
  82. package/src/browser/react/Link.tsx +93 -11
  83. package/src/browser/react/NavigationProvider.tsx +115 -34
  84. package/src/browser/react/ScrollRestoration.tsx +10 -6
  85. package/src/browser/react/context.ts +7 -2
  86. package/src/browser/react/filter-segment-order.ts +49 -7
  87. package/src/browser/react/index.ts +0 -48
  88. package/src/browser/react/location-state-shared.ts +166 -8
  89. package/src/browser/react/location-state.ts +39 -14
  90. package/src/browser/react/use-action.ts +6 -15
  91. package/src/browser/react/use-handle.ts +23 -69
  92. package/src/browser/react/use-link-status.ts +0 -4
  93. package/src/browser/react/use-navigation.ts +22 -5
  94. package/src/browser/react/use-params.ts +20 -10
  95. package/src/browser/react/use-reverse.ts +106 -0
  96. package/src/browser/react/use-router.ts +46 -11
  97. package/src/browser/react/use-search-params.ts +0 -5
  98. package/src/browser/react/use-segments.ts +11 -21
  99. package/src/browser/response-adapter.ts +52 -1
  100. package/src/browser/rsc-router.tsx +215 -76
  101. package/src/browser/scroll-restoration.ts +46 -39
  102. package/src/browser/segment-reconciler.ts +36 -9
  103. package/src/browser/segment-structure-assert.ts +2 -2
  104. package/src/browser/server-action-bridge.ts +176 -50
  105. package/src/browser/types.ts +95 -11
  106. package/src/browser/validate-redirect-origin.ts +43 -16
  107. package/src/build/collect-fallback-refs.ts +107 -0
  108. package/src/build/generate-manifest.ts +65 -40
  109. package/src/build/generate-route-types.ts +5 -0
  110. package/src/build/index.ts +8 -2
  111. package/src/build/prefix-tree-utils.ts +123 -0
  112. package/src/build/route-trie.ts +137 -32
  113. package/src/build/route-types/codegen.ts +4 -4
  114. package/src/build/route-types/include-resolution.ts +9 -2
  115. package/src/build/route-types/param-extraction.ts +6 -3
  116. package/src/build/route-types/per-module-writer.ts +7 -4
  117. package/src/build/route-types/router-processing.ts +278 -96
  118. package/src/build/route-types/scan-filter.ts +9 -2
  119. package/src/build/route-types/source-scan.ts +118 -0
  120. package/src/build/runtime-discovery.ts +9 -20
  121. package/src/cache/cache-error.ts +104 -0
  122. package/src/cache/cache-policy.ts +68 -28
  123. package/src/cache/cache-runtime.ts +149 -43
  124. package/src/cache/cache-scope.ts +148 -81
  125. package/src/cache/cache-tag.ts +98 -0
  126. package/src/cache/cf/cf-cache-store.ts +2550 -93
  127. package/src/cache/cf/index.ts +11 -17
  128. package/src/cache/document-cache.ts +78 -27
  129. package/src/cache/handle-snapshot.ts +63 -0
  130. package/src/cache/index.ts +23 -20
  131. package/src/cache/memory-segment-store.ts +136 -37
  132. package/src/cache/profile-registry.ts +6 -30
  133. package/src/cache/read-through-swr.ts +41 -11
  134. package/src/cache/segment-codec.ts +0 -16
  135. package/src/cache/tag-invalidation.ts +230 -0
  136. package/src/cache/taint.ts +55 -0
  137. package/src/cache/types.ts +33 -100
  138. package/src/cache/vercel/index.ts +11 -0
  139. package/src/cache/vercel/vercel-cache-store.ts +799 -0
  140. package/src/client.rsc.tsx +6 -21
  141. package/src/client.tsx +108 -290
  142. package/src/component-utils.ts +19 -0
  143. package/src/context-var.ts +84 -2
  144. package/src/debug.ts +2 -2
  145. package/src/decode-loader-results.ts +36 -0
  146. package/src/defer.ts +196 -0
  147. package/src/deps/ssr.ts +0 -1
  148. package/src/errors.ts +30 -4
  149. package/src/handle.ts +70 -22
  150. package/src/handles/MetaTags.tsx +0 -14
  151. package/src/handles/breadcrumbs.ts +16 -5
  152. package/src/handles/meta.ts +0 -39
  153. package/src/host/cookie-handler.ts +0 -36
  154. package/src/host/errors.ts +0 -24
  155. package/src/host/index.ts +8 -2
  156. package/src/host/pattern-matcher.ts +7 -50
  157. package/src/host/router.ts +107 -99
  158. package/src/host/testing.ts +40 -27
  159. package/src/host/types.ts +37 -4
  160. package/src/host/utils.ts +1 -1
  161. package/src/href-client.ts +137 -22
  162. package/src/index.rsc.ts +52 -26
  163. package/src/index.ts +100 -38
  164. package/src/internal-debug.ts +2 -4
  165. package/src/loader-store.ts +500 -0
  166. package/src/loader.rsc.ts +20 -13
  167. package/src/loader.ts +12 -11
  168. package/src/missing-id-error.ts +68 -0
  169. package/src/network-error-thrower.tsx +1 -6
  170. package/src/outlet-context.ts +1 -1
  171. package/src/outlet-provider.tsx +1 -5
  172. package/src/prerender/param-hash.ts +10 -11
  173. package/src/prerender/store.ts +37 -41
  174. package/src/prerender.ts +198 -82
  175. package/src/redirect-origin.ts +100 -0
  176. package/src/response-utils.ts +37 -0
  177. package/src/reverse.ts +65 -15
  178. package/src/root-error-boundary.tsx +1 -19
  179. package/src/route-content-wrapper.tsx +7 -72
  180. package/src/route-definition/dsl-helpers.ts +437 -274
  181. package/src/route-definition/helper-factories.ts +29 -139
  182. package/src/route-definition/helpers-types.ts +113 -37
  183. package/src/route-definition/index.ts +3 -0
  184. package/src/route-definition/redirect.ts +52 -10
  185. package/src/route-definition/resolve-handler-use.ts +161 -0
  186. package/src/route-definition/use-item-types.ts +32 -0
  187. package/src/route-map-builder.ts +7 -17
  188. package/src/route-types.ts +37 -41
  189. package/src/router/basename.ts +14 -0
  190. package/src/router/content-negotiation.ts +108 -9
  191. package/src/router/error-handling.ts +13 -17
  192. package/src/router/find-match.ts +45 -22
  193. package/src/router/handler-context.ts +83 -41
  194. package/src/router/intercept-resolution.ts +25 -23
  195. package/src/router/lazy-includes.ts +19 -53
  196. package/src/router/loader-resolution.ts +213 -30
  197. package/src/router/logging.ts +5 -8
  198. package/src/router/manifest.ts +49 -45
  199. package/src/router/match-api.ts +121 -205
  200. package/src/router/match-context.ts +0 -22
  201. package/src/router/match-handlers.ts +58 -58
  202. package/src/router/match-middleware/background-revalidation.ts +27 -6
  203. package/src/router/match-middleware/cache-lookup.ts +205 -249
  204. package/src/router/match-middleware/cache-store.ts +45 -32
  205. package/src/router/match-middleware/intercept-resolution.ts +8 -28
  206. package/src/router/match-middleware/segment-resolution.ts +52 -18
  207. package/src/router/match-pipelines.ts +1 -42
  208. package/src/router/match-result.ts +104 -40
  209. package/src/router/metrics.ts +5 -34
  210. package/src/router/middleware-types.ts +13 -142
  211. package/src/router/middleware.ts +173 -143
  212. package/src/router/navigation-snapshot.ts +131 -0
  213. package/src/router/params-util.ts +23 -0
  214. package/src/router/pattern-matching.ts +109 -63
  215. package/src/router/prerender-match.ts +192 -54
  216. package/src/router/preview-match.ts +32 -102
  217. package/src/router/request-classification.ts +276 -0
  218. package/src/router/revalidation.ts +63 -55
  219. package/src/router/route-snapshot.ts +244 -0
  220. package/src/router/router-context.ts +6 -28
  221. package/src/router/router-interfaces.ts +100 -35
  222. package/src/router/router-options.ts +91 -11
  223. package/src/router/router-registry.ts +2 -5
  224. package/src/router/segment-resolution/fresh.ts +242 -75
  225. package/src/router/segment-resolution/helpers.ts +64 -25
  226. package/src/router/segment-resolution/loader-cache.ts +41 -37
  227. package/src/router/segment-resolution/revalidation.ts +456 -372
  228. package/src/router/segment-resolution/static-store.ts +19 -5
  229. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  230. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  231. package/src/router/segment-resolution.ts +4 -1
  232. package/src/router/segment-wrappers.ts +2 -3
  233. package/src/router/state-cookie-name.ts +33 -0
  234. package/src/router/substitute-pattern-params.ts +56 -0
  235. package/src/router/telemetry-otel.ts +0 -20
  236. package/src/router/telemetry.ts +96 -19
  237. package/src/router/timeout.ts +0 -20
  238. package/src/router/trie-matching.ts +91 -46
  239. package/src/router/types.ts +10 -63
  240. package/src/router/url-params.ts +44 -0
  241. package/src/router.ts +134 -43
  242. package/src/rsc/handler-context.ts +3 -2
  243. package/src/rsc/handler.ts +492 -383
  244. package/src/rsc/helpers.ts +162 -46
  245. package/src/rsc/index.ts +1 -1
  246. package/src/rsc/json-route-result.ts +38 -0
  247. package/src/rsc/loader-fetch.ts +23 -3
  248. package/src/rsc/manifest-init.ts +33 -42
  249. package/src/rsc/origin-guard.ts +39 -25
  250. package/src/rsc/progressive-enhancement.ts +30 -3
  251. package/src/rsc/redirect-guard.ts +99 -0
  252. package/src/rsc/response-error.ts +79 -12
  253. package/src/rsc/response-route-handler.ts +90 -63
  254. package/src/rsc/rsc-rendering.ts +56 -54
  255. package/src/rsc/runtime-warnings.ts +23 -10
  256. package/src/rsc/server-action.ts +74 -67
  257. package/src/rsc/ssr-setup.ts +18 -2
  258. package/src/rsc/types.ts +25 -6
  259. package/src/runtime-env.ts +18 -0
  260. package/src/search-params.ts +4 -20
  261. package/src/segment-content-promise.ts +67 -0
  262. package/src/segment-loader-promise.ts +134 -0
  263. package/src/segment-system.tsx +272 -129
  264. package/src/serialize.ts +243 -0
  265. package/src/server/context.ts +309 -61
  266. package/src/server/cookie-store.ts +80 -5
  267. package/src/server/handle-store.ts +26 -24
  268. package/src/server/loader-registry.ts +10 -28
  269. package/src/server/request-context.ts +348 -128
  270. package/src/ssr/index.tsx +23 -15
  271. package/src/static-handler.ts +27 -18
  272. package/src/testing/cache-status.ts +162 -0
  273. package/src/testing/collect-handle.ts +40 -0
  274. package/src/testing/dispatch.ts +618 -0
  275. package/src/testing/dom.entry.ts +22 -0
  276. package/src/testing/e2e/fixture.ts +188 -0
  277. package/src/testing/e2e/index.ts +128 -0
  278. package/src/testing/e2e/matchers.ts +35 -0
  279. package/src/testing/e2e/page-helpers.ts +272 -0
  280. package/src/testing/e2e/parity.ts +387 -0
  281. package/src/testing/e2e/server.ts +195 -0
  282. package/src/testing/flight-matchers.ts +97 -0
  283. package/src/testing/flight-normalize.ts +11 -0
  284. package/src/testing/flight-runtime.d.ts +57 -0
  285. package/src/testing/flight-tree.ts +682 -0
  286. package/src/testing/flight.entry.ts +52 -0
  287. package/src/testing/flight.ts +232 -0
  288. package/src/testing/generated-routes.ts +183 -0
  289. package/src/testing/index.ts +99 -0
  290. package/src/testing/internal/context.ts +348 -0
  291. package/src/testing/internal/flight-client-globals.ts +30 -0
  292. package/src/testing/internal/seed-vars.ts +54 -0
  293. package/src/testing/render-handler.ts +330 -0
  294. package/src/testing/render-route.tsx +566 -0
  295. package/src/testing/run-loader.ts +378 -0
  296. package/src/testing/run-middleware.ts +205 -0
  297. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  298. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  299. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  300. package/src/testing/vitest-stubs/version.ts +5 -0
  301. package/src/testing/vitest.ts +305 -0
  302. package/src/theme/ThemeProvider.tsx +0 -52
  303. package/src/theme/ThemeScript.tsx +0 -6
  304. package/src/theme/constants.ts +0 -12
  305. package/src/theme/index.ts +0 -7
  306. package/src/theme/theme-context.ts +1 -5
  307. package/src/theme/theme-script.ts +0 -14
  308. package/src/theme/use-theme.ts +0 -3
  309. package/src/types/boundaries.ts +0 -35
  310. package/src/types/cache-types.ts +17 -8
  311. package/src/types/error-types.ts +30 -90
  312. package/src/types/global-namespace.ts +54 -41
  313. package/src/types/handler-context.ts +233 -81
  314. package/src/types/index.ts +1 -10
  315. package/src/types/loader-types.ts +44 -15
  316. package/src/types/request-scope.ts +107 -0
  317. package/src/types/route-config.ts +6 -50
  318. package/src/types/route-entry.ts +19 -7
  319. package/src/types/segments.ts +37 -14
  320. package/src/urls/include-helper.ts +33 -70
  321. package/src/urls/index.ts +1 -11
  322. package/src/urls/path-helper-types.ts +58 -11
  323. package/src/urls/path-helper.ts +57 -111
  324. package/src/urls/pattern-types.ts +48 -19
  325. package/src/urls/response-types.ts +25 -22
  326. package/src/urls/type-extraction.ts +58 -139
  327. package/src/urls/urls-function.ts +1 -18
  328. package/src/use-loader.tsx +346 -89
  329. package/src/vite/debug.ts +185 -0
  330. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  331. package/src/vite/discovery/discover-routers.ts +130 -85
  332. package/src/vite/discovery/discovery-errors.ts +194 -0
  333. package/src/vite/discovery/gate-state.ts +171 -0
  334. package/src/vite/discovery/prerender-collection.ts +192 -99
  335. package/src/vite/discovery/route-types-writer.ts +40 -84
  336. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  337. package/src/vite/discovery/state.ts +51 -6
  338. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  339. package/src/vite/index.ts +8 -0
  340. package/src/vite/plugin-types.ts +187 -69
  341. package/src/vite/plugins/cjs-to-esm.ts +8 -18
  342. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  343. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  344. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  345. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  346. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  347. package/src/vite/plugins/expose-action-id.ts +49 -98
  348. package/src/vite/plugins/expose-id-utils.ts +11 -50
  349. package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
  350. package/src/vite/plugins/expose-ids/handler-transform.ts +10 -48
  351. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
  352. package/src/vite/plugins/expose-ids/router-transform.ts +20 -16
  353. package/src/vite/plugins/expose-internal-ids.ts +554 -317
  354. package/src/vite/plugins/performance-tracks.ts +89 -0
  355. package/src/vite/plugins/refresh-cmd.ts +89 -27
  356. package/src/vite/plugins/use-cache-transform.ts +73 -83
  357. package/src/vite/plugins/vercel-output.ts +258 -0
  358. package/src/vite/plugins/version-injector.ts +21 -25
  359. package/src/vite/plugins/version-plugin.ts +41 -20
  360. package/src/vite/plugins/virtual-entries.ts +2 -17
  361. package/src/vite/rango.ts +257 -289
  362. package/src/vite/router-discovery.ts +930 -140
  363. package/src/vite/utils/ast-handler-extract.ts +15 -31
  364. package/src/vite/utils/banner.ts +4 -4
  365. package/src/vite/utils/bundle-analysis.ts +10 -15
  366. package/src/vite/utils/client-chunks.ts +184 -0
  367. package/src/vite/utils/forward-user-plugins.ts +171 -0
  368. package/src/vite/utils/manifest-utils.ts +4 -59
  369. package/src/vite/utils/package-resolution.ts +20 -52
  370. package/src/vite/utils/prerender-utils.ts +27 -29
  371. package/src/vite/utils/shared-utils.ts +92 -42
  372. package/src/browser/action-response-classifier.ts +0 -99
  373. package/src/browser/react/use-client-cache.ts +0 -58
  374. package/src/browser/shallow.ts +0 -40
  375. package/src/handles/index.ts +0 -7
  376. package/src/router/middleware-cookies.ts +0 -55
@@ -1,5 +1,5 @@
1
1
  import MagicString from "magic-string";
2
- import { hashId } from "../expose-id-utils.js";
2
+ import { makeStubId } from "../expose-id-utils.js";
3
3
  import type { HandlerTransformConfig, CreateExportBinding } from "./types.js";
4
4
  import { isExportOnlyFile } from "./export-analysis.js";
5
5
 
@@ -28,9 +28,7 @@ export function transformHandles(
28
28
  binding.callCloseParenPos,
29
29
  );
30
30
 
31
- const handleId = isBuild
32
- ? hashId(filePath, exportName)
33
- : `${filePath}#${exportName}`;
31
+ const handleId = makeStubId(filePath, exportName, isBuild);
34
32
 
35
33
  let paramInjection: string;
36
34
  if (!args.hasArgs) {
@@ -58,9 +56,7 @@ export function transformLocationState(
58
56
  for (const binding of bindings) {
59
57
  const exportName = binding.exportNames[0];
60
58
 
61
- const stateKey = isBuild
62
- ? hashId(filePath, exportName)
63
- : `${filePath}#${exportName}`;
59
+ const stateKey = makeStubId(filePath, exportName, isBuild);
64
60
 
65
61
  // Key is injected as a property assignment (not as a function argument).
66
62
  // This allows createLocationState to accept options like { flash: true }
@@ -73,10 +69,6 @@ export function transformLocationState(
73
69
  return hasChanges;
74
70
  }
75
71
 
76
- /**
77
- * Replace the entire file with lightweight stubs when ALL non-type exports are
78
- * handler calls of the given type. Returns null for files with mixed exports.
79
- */
80
72
  export function generateWholeFileStubs(
81
73
  cfg: HandlerTransformConfig,
82
74
  bindings: CreateExportBinding[],
@@ -88,35 +80,24 @@ export function generateWholeFileStubs(
88
80
 
89
81
  const exportNames = bindings.flatMap((b) => b.exportNames);
90
82
  const stubs = exportNames.map((name) => {
91
- const handlerId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
83
+ const handlerId = makeStubId(filePath, name, isBuild);
92
84
  return `export const ${name} = { __brand: "${cfg.brand}", $$id: "${handlerId}" };`;
93
85
  });
94
86
 
95
87
  return { code: stubs.join("\n") + "\n", map: null };
96
88
  }
97
89
 
98
- /**
99
- * Replace handler call expressions with lightweight stub objects in non-RSC
100
- * environments. Other exports, imports, and module-level code remain untouched.
101
- */
102
- export function generateExprStubs(
90
+ export function stubHandlerExprs(
103
91
  cfg: HandlerTransformConfig,
104
92
  bindings: CreateExportBinding[],
105
- code: string,
93
+ s: MagicString,
106
94
  filePath: string,
107
- sourceId: string,
108
95
  isBuild: boolean,
109
- ): { code: string; map: ReturnType<MagicString["generateMap"]> } | null {
110
- if (bindings.length === 0) return null;
111
-
112
- const s = new MagicString(code);
96
+ ): boolean {
113
97
  let hasChanges = false;
114
-
115
98
  for (const binding of bindings) {
116
99
  const exportName = binding.exportNames[0];
117
- const handlerId = isBuild
118
- ? hashId(filePath, exportName)
119
- : `${filePath}#${exportName}`;
100
+ const handlerId = makeStubId(filePath, exportName, isBuild);
120
101
 
121
102
  s.overwrite(
122
103
  binding.callExprStart,
@@ -125,22 +106,9 @@ export function generateExprStubs(
125
106
  );
126
107
  hasChanges = true;
127
108
  }
128
-
129
- if (!hasChanges) return null;
130
-
131
- return {
132
- code: s.toString(),
133
- map: s.generateMap({
134
- source: sourceId,
135
- includeContent: true,
136
- hires: "boundary",
137
- }),
138
- };
109
+ return hasChanges;
139
110
  }
140
111
 
141
- /**
142
- * Inject $$id into export const handler calls in RSC environments.
143
- */
144
112
  export function transformHandlerIds(
145
113
  cfg: HandlerTransformConfig,
146
114
  bindings: CreateExportBinding[],
@@ -152,14 +120,8 @@ export function transformHandlerIds(
152
120
  for (const binding of bindings) {
153
121
  const exportName = binding.exportNames[0];
154
122
 
155
- const handlerId = isBuild
156
- ? hashId(filePath, exportName)
157
- : `${filePath}#${exportName}`;
123
+ const handlerId = makeStubId(filePath, exportName, isBuild);
158
124
 
159
- // Injection strategy matches the runtime overload signatures:
160
- // 0 args -> inject undefined, "id"
161
- // 1 arg (handler) -> inject , undefined, "id"
162
- // 2+ args -> inject , "id"
163
125
  let paramInjection: string;
164
126
  if (binding.argCount === 0) {
165
127
  paramInjection = `undefined, "${handlerId}"`;
@@ -1,5 +1,5 @@
1
1
  import type MagicString from "magic-string";
2
- import { hashId } from "../expose-id-utils.js";
2
+ import { makeStubId } from "../expose-id-utils.js";
3
3
  import type { CreateExportBinding } from "./types.js";
4
4
  import { isExportOnlyFile } from "./export-analysis.js";
5
5
 
@@ -9,18 +9,6 @@ export function hasCreateLoaderImport(code: string): boolean {
9
9
  );
10
10
  }
11
11
 
12
- /**
13
- * Generate lightweight client stubs for loader files.
14
- *
15
- * When a loader file is imported from a client component (e.g., for useLoader()),
16
- * the client only needs { __brand: "loader", $$id: "..." } objects.
17
- * This function replaces the entire file contents with just those stub exports,
18
- * preventing server-only data (constants, DB queries, etc.) from leaking into
19
- * the client bundle.
20
- *
21
- * Only applies when ALL named exports are createLoader() calls (plus type exports
22
- * which are erased at compile time). Files with mixed exports are left untouched.
23
- */
24
12
  export function generateClientLoaderStubs(
25
13
  bindings: CreateExportBinding[],
26
14
  code: string,
@@ -33,7 +21,7 @@ export function generateClientLoaderStubs(
33
21
 
34
22
  for (const binding of bindings) {
35
23
  for (const name of binding.exportNames) {
36
- const loaderId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
24
+ const loaderId = makeStubId(filePath, name, isBuild);
37
25
  lines.push(
38
26
  `export const ${name} = { __brand: "loader", $$id: "${loaderId}" };`,
39
27
  );
@@ -54,13 +42,8 @@ export function transformLoaders(
54
42
  for (const binding of bindings) {
55
43
  const exportName = binding.exportNames[0];
56
44
 
57
- const loaderId = isBuild
58
- ? hashId(filePath, exportName)
59
- : `${filePath}#${exportName}`;
45
+ const loaderId = makeStubId(filePath, exportName, isBuild);
60
46
 
61
- // Inject $$id as hidden third parameter.
62
- // createLoader(fn) -> createLoader(fn, undefined, "id")
63
- // createLoader(fn, true) -> createLoader(fn, true, "id")
64
47
  const paramInjection =
65
48
  binding.argCount === 1 ? `, undefined, "${loaderId}"` : `, "${loaderId}"`;
66
49
  s.appendLeft(binding.callCloseParenPos, paramInjection);
@@ -4,6 +4,9 @@ import path from "node:path";
4
4
  import { createHash } from "node:crypto";
5
5
  import { normalizePath, findMatchingParen } from "../expose-id-utils.js";
6
6
  import { getImportedFnNames } from "./export-analysis.js";
7
+ import { createRangoDebugger, createCounter, NS } from "../../debug.js";
8
+
9
+ const debug = createRangoDebugger(NS.transform);
7
10
 
8
11
  export function transformRouter(
9
12
  code: string,
@@ -29,15 +32,11 @@ export function transformRouter(
29
32
  const callStart = match.index;
30
33
  const parenPos = match.index + match[0].length - 1;
31
34
 
32
- // Scope the $$id check to within this call's arguments only,
33
- // not the entire remaining file.
34
35
  const closeParen = findMatchingParen(code, parenPos + 1);
35
36
  const callArgs = code.slice(parenPos + 1, closeParen);
36
37
 
37
- // Skip if $$id is already present in this call
38
38
  if (callArgs.includes("$$id")) continue;
39
39
 
40
- // Compute line number for this call
41
40
  const lineNumber = code.slice(0, callStart).split("\n").length;
42
41
  const hash = createHash("sha256")
43
42
  .update(`${filePath}:${lineNumber}`)
@@ -45,9 +44,6 @@ export function transformRouter(
45
44
  .slice(0, 8);
46
45
 
47
46
  changed = true;
48
- // $$sourceFile uses the absolute path so that downstream consumers
49
- // (virtual-module-codegen, runtime-discovery) can resolve gen file
50
- // imports correctly via path.dirname / path.join.
51
47
  const sourceFilePath = absolutePath ?? filePath;
52
48
  const injected = ` $$id: "${hash}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
53
49
 
@@ -62,8 +58,6 @@ export function transformRouter(
62
58
 
63
59
  if (!changed) return null;
64
60
 
65
- // Prepend the static import as the first line. MagicString tracks the
66
- // offset so all downstream source maps remain correct.
67
61
  s.prepend(
68
62
  `import { NamedRoutes as ${routeNamesVar} } from "${routeNamesImport}";\n`,
69
63
  );
@@ -82,17 +76,17 @@ export function transformRouter(
82
76
  */
83
77
  export function exposeRouterId(): Plugin {
84
78
  let projectRoot = "";
79
+ const counter = createCounter(debug, "expose-router-id");
85
80
  return {
86
81
  name: "@rangojs/router:expose-router-id",
87
82
  configResolved(config) {
88
83
  projectRoot = config.root;
89
84
  },
85
+ buildEnd() {
86
+ counter?.flush();
87
+ },
90
88
  transform(code, id) {
91
89
  if (!code.includes("createRouter")) return null;
92
- // Accepts both @rangojs/router and @rangojs/router/server subpath.
93
- // NOTE: detectImports in expose-id-utils has a stricter check that
94
- // excludes /server for its router flag -- that's intentional since
95
- // detectImports is only used in exposeInternalIds, not here.
96
90
  if (
97
91
  !/import\s*\{[^}]*\bcreateRouter\b[^}]*\}\s*from\s*["']@rangojs\/router(?:\/server)?["']/.test(
98
92
  code,
@@ -102,9 +96,19 @@ export function exposeRouterId(): Plugin {
102
96
  }
103
97
  if (id.includes("node_modules")) return null;
104
98
 
105
- const filePath = normalizePath(path.relative(projectRoot, id));
106
- const routerFnNames = getImportedFnNames(code, "createRouter");
107
- return transformRouter(code, filePath, routerFnNames, normalizePath(id));
99
+ const start = counter ? performance.now() : 0;
100
+ try {
101
+ const filePath = normalizePath(path.relative(projectRoot, id));
102
+ const routerFnNames = getImportedFnNames(code, "createRouter");
103
+ return transformRouter(
104
+ code,
105
+ filePath,
106
+ routerFnNames,
107
+ normalizePath(id),
108
+ );
109
+ } finally {
110
+ counter?.record(id, performance.now() - start);
111
+ }
108
112
  },
109
113
  };
110
114
  }