@rangojs/router 0.0.0-experimental.9eb4192e → 0.0.0-experimental.a014d2b7

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 (1191) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +123 -15
  3. package/dist/__internal.d.ts +83 -0
  4. package/dist/__internal.d.ts.map +1 -0
  5. package/dist/__internal.js +19 -0
  6. package/dist/__internal.js.map +1 -0
  7. package/dist/__mocks__/version.d.ts +7 -0
  8. package/dist/__mocks__/version.d.ts.map +1 -0
  9. package/dist/__mocks__/version.js +7 -0
  10. package/dist/__mocks__/version.js.map +1 -0
  11. package/dist/__tests__/client-href.test.d.ts +2 -0
  12. package/dist/__tests__/client-href.test.d.ts.map +1 -0
  13. package/dist/__tests__/client-href.test.js +74 -0
  14. package/dist/__tests__/client-href.test.js.map +1 -0
  15. package/dist/__tests__/component-utils.test.d.ts +2 -0
  16. package/dist/__tests__/component-utils.test.d.ts.map +1 -0
  17. package/dist/__tests__/component-utils.test.js +51 -0
  18. package/dist/__tests__/component-utils.test.js.map +1 -0
  19. package/dist/__tests__/event-controller.test.d.ts +2 -0
  20. package/dist/__tests__/event-controller.test.d.ts.map +1 -0
  21. package/dist/__tests__/event-controller.test.js +538 -0
  22. package/dist/__tests__/event-controller.test.js.map +1 -0
  23. package/dist/__tests__/helpers/route-tree.d.ts +118 -0
  24. package/dist/__tests__/helpers/route-tree.d.ts.map +1 -0
  25. package/dist/__tests__/helpers/route-tree.js +374 -0
  26. package/dist/__tests__/helpers/route-tree.js.map +1 -0
  27. package/dist/__tests__/match-result.test.d.ts +2 -0
  28. package/dist/__tests__/match-result.test.d.ts.map +1 -0
  29. package/dist/__tests__/match-result.test.js +154 -0
  30. package/dist/__tests__/match-result.test.js.map +1 -0
  31. package/dist/__tests__/navigation-store.test.d.ts +2 -0
  32. package/dist/__tests__/navigation-store.test.d.ts.map +1 -0
  33. package/dist/__tests__/navigation-store.test.js +440 -0
  34. package/dist/__tests__/navigation-store.test.js.map +1 -0
  35. package/dist/__tests__/partial-update.test.d.ts +2 -0
  36. package/dist/__tests__/partial-update.test.d.ts.map +1 -0
  37. package/dist/__tests__/partial-update.test.js +1009 -0
  38. package/dist/__tests__/partial-update.test.js.map +1 -0
  39. package/dist/__tests__/reverse-types.test.d.ts +8 -0
  40. package/dist/__tests__/reverse-types.test.d.ts.map +1 -0
  41. package/dist/__tests__/reverse-types.test.js +656 -0
  42. package/dist/__tests__/reverse-types.test.js.map +1 -0
  43. package/dist/__tests__/route-definition.test.d.ts +2 -0
  44. package/dist/__tests__/route-definition.test.d.ts.map +1 -0
  45. package/dist/__tests__/route-definition.test.js +55 -0
  46. package/dist/__tests__/route-definition.test.js.map +1 -0
  47. package/dist/__tests__/router-helpers.test.d.ts +2 -0
  48. package/dist/__tests__/router-helpers.test.d.ts.map +1 -0
  49. package/dist/__tests__/router-helpers.test.js +377 -0
  50. package/dist/__tests__/router-helpers.test.js.map +1 -0
  51. package/dist/__tests__/router-integration-2.test.d.ts +2 -0
  52. package/dist/__tests__/router-integration-2.test.d.ts.map +1 -0
  53. package/dist/__tests__/router-integration-2.test.js +426 -0
  54. package/dist/__tests__/router-integration-2.test.js.map +1 -0
  55. package/dist/__tests__/router-integration.test.d.ts +2 -0
  56. package/dist/__tests__/router-integration.test.d.ts.map +1 -0
  57. package/dist/__tests__/router-integration.test.js +1051 -0
  58. package/dist/__tests__/router-integration.test.js.map +1 -0
  59. package/dist/__tests__/search-params.test.d.ts +5 -0
  60. package/dist/__tests__/search-params.test.d.ts.map +1 -0
  61. package/dist/__tests__/search-params.test.js +306 -0
  62. package/dist/__tests__/search-params.test.js.map +1 -0
  63. package/dist/__tests__/segment-system.test.d.ts +2 -0
  64. package/dist/__tests__/segment-system.test.d.ts.map +1 -0
  65. package/dist/__tests__/segment-system.test.js +627 -0
  66. package/dist/__tests__/segment-system.test.js.map +1 -0
  67. package/dist/__tests__/static-handler-types.test.d.ts +8 -0
  68. package/dist/__tests__/static-handler-types.test.d.ts.map +1 -0
  69. package/dist/__tests__/static-handler-types.test.js +63 -0
  70. package/dist/__tests__/static-handler-types.test.js.map +1 -0
  71. package/dist/__tests__/urls.test.d.ts +2 -0
  72. package/dist/__tests__/urls.test.d.ts.map +1 -0
  73. package/dist/__tests__/urls.test.js +421 -0
  74. package/dist/__tests__/urls.test.js.map +1 -0
  75. package/dist/__tests__/use-mount.test.d.ts +2 -0
  76. package/dist/__tests__/use-mount.test.d.ts.map +1 -0
  77. package/dist/__tests__/use-mount.test.js +35 -0
  78. package/dist/__tests__/use-mount.test.js.map +1 -0
  79. package/dist/bin/rango.d.ts +2 -0
  80. package/dist/bin/rango.d.ts.map +1 -0
  81. package/dist/bin/rango.js +319 -95
  82. package/dist/bin/rango.js.map +1 -0
  83. package/dist/browser/event-controller.d.ts +191 -0
  84. package/dist/browser/event-controller.d.ts.map +1 -0
  85. package/dist/browser/event-controller.js +559 -0
  86. package/dist/browser/event-controller.js.map +1 -0
  87. package/dist/browser/index.d.ts +2 -0
  88. package/dist/browser/index.d.ts.map +1 -0
  89. package/dist/browser/index.js +14 -0
  90. package/dist/browser/index.js.map +1 -0
  91. package/dist/browser/link-interceptor.d.ts +38 -0
  92. package/dist/browser/link-interceptor.d.ts.map +1 -0
  93. package/dist/browser/link-interceptor.js +99 -0
  94. package/dist/browser/link-interceptor.js.map +1 -0
  95. package/dist/browser/logging.d.ts +10 -0
  96. package/dist/browser/logging.d.ts.map +1 -0
  97. package/dist/browser/logging.js +29 -0
  98. package/dist/browser/logging.js.map +1 -0
  99. package/dist/browser/lru-cache.d.ts +17 -0
  100. package/dist/browser/lru-cache.d.ts.map +1 -0
  101. package/dist/browser/lru-cache.js +50 -0
  102. package/dist/browser/lru-cache.js.map +1 -0
  103. package/dist/browser/merge-segment-loaders.d.ts +39 -0
  104. package/dist/browser/merge-segment-loaders.d.ts.map +1 -0
  105. package/dist/browser/merge-segment-loaders.js +102 -0
  106. package/dist/browser/merge-segment-loaders.js.map +1 -0
  107. package/dist/browser/navigation-bridge.d.ts +102 -0
  108. package/dist/browser/navigation-bridge.d.ts.map +1 -0
  109. package/dist/browser/navigation-bridge.js +708 -0
  110. package/dist/browser/navigation-bridge.js.map +1 -0
  111. package/dist/browser/navigation-client.d.ts +25 -0
  112. package/dist/browser/navigation-client.d.ts.map +1 -0
  113. package/dist/browser/navigation-client.js +157 -0
  114. package/dist/browser/navigation-client.js.map +1 -0
  115. package/dist/browser/navigation-store.d.ts +101 -0
  116. package/dist/browser/navigation-store.d.ts.map +1 -0
  117. package/dist/browser/navigation-store.js +625 -0
  118. package/dist/browser/navigation-store.js.map +1 -0
  119. package/dist/browser/partial-update.d.ts +75 -0
  120. package/dist/browser/partial-update.d.ts.map +1 -0
  121. package/dist/browser/partial-update.js +426 -0
  122. package/dist/browser/partial-update.js.map +1 -0
  123. package/dist/browser/react/Link.d.ts +86 -0
  124. package/dist/browser/react/Link.d.ts.map +1 -0
  125. package/dist/browser/react/Link.js +128 -0
  126. package/dist/browser/react/Link.js.map +1 -0
  127. package/dist/browser/react/NavigationProvider.d.ts +63 -0
  128. package/dist/browser/react/NavigationProvider.d.ts.map +1 -0
  129. package/dist/browser/react/NavigationProvider.js +216 -0
  130. package/dist/browser/react/NavigationProvider.js.map +1 -0
  131. package/dist/browser/react/ScrollRestoration.d.ts +75 -0
  132. package/dist/browser/react/ScrollRestoration.d.ts.map +1 -0
  133. package/dist/browser/react/ScrollRestoration.js +57 -0
  134. package/dist/browser/react/ScrollRestoration.js.map +1 -0
  135. package/dist/browser/react/context.d.ts +46 -0
  136. package/dist/browser/react/context.d.ts.map +1 -0
  137. package/dist/browser/react/context.js +10 -0
  138. package/dist/browser/react/context.js.map +1 -0
  139. package/dist/browser/react/index.d.ts +11 -0
  140. package/dist/browser/react/index.d.ts.map +1 -0
  141. package/dist/browser/react/index.js +22 -0
  142. package/dist/browser/react/index.js.map +1 -0
  143. package/dist/browser/react/location-state-shared.d.ts +63 -0
  144. package/dist/browser/react/location-state-shared.d.ts.map +1 -0
  145. package/dist/browser/react/location-state-shared.js +81 -0
  146. package/dist/browser/react/location-state-shared.js.map +1 -0
  147. package/dist/browser/react/location-state.d.ts +23 -0
  148. package/dist/browser/react/location-state.d.ts.map +1 -0
  149. package/dist/browser/react/location-state.js +29 -0
  150. package/dist/browser/react/location-state.js.map +1 -0
  151. package/dist/browser/react/mount-context.d.ts +24 -0
  152. package/dist/browser/react/mount-context.d.ts.map +1 -0
  153. package/dist/browser/react/mount-context.js +24 -0
  154. package/dist/browser/react/mount-context.js.map +1 -0
  155. package/dist/browser/react/use-action.d.ts +64 -0
  156. package/dist/browser/react/use-action.d.ts.map +1 -0
  157. package/dist/browser/react/use-action.js +134 -0
  158. package/dist/browser/react/use-action.js.map +1 -0
  159. package/dist/browser/react/use-client-cache.d.ts +41 -0
  160. package/dist/browser/react/use-client-cache.d.ts.map +1 -0
  161. package/{src/browser/react/use-client-cache.ts → dist/browser/react/use-client-cache.js} +9 -28
  162. package/dist/browser/react/use-client-cache.js.map +1 -0
  163. package/dist/browser/react/use-handle.d.ts +31 -0
  164. package/dist/browser/react/use-handle.d.ts.map +1 -0
  165. package/dist/browser/react/use-handle.js +144 -0
  166. package/dist/browser/react/use-handle.js.map +1 -0
  167. package/dist/browser/react/use-href.d.ts +33 -0
  168. package/dist/browser/react/use-href.d.ts.map +1 -0
  169. package/dist/browser/react/use-href.js +39 -0
  170. package/dist/browser/react/use-href.js.map +1 -0
  171. package/dist/browser/react/use-link-status.d.ts +37 -0
  172. package/dist/browser/react/use-link-status.d.ts.map +1 -0
  173. package/dist/browser/react/use-link-status.js +99 -0
  174. package/dist/browser/react/use-link-status.js.map +1 -0
  175. package/dist/browser/react/use-mount.d.ts +25 -0
  176. package/dist/browser/react/use-mount.d.ts.map +1 -0
  177. package/dist/browser/react/use-mount.js +30 -0
  178. package/dist/browser/react/use-mount.js.map +1 -0
  179. package/dist/browser/react/use-navigation.d.ts +27 -0
  180. package/dist/browser/react/use-navigation.d.ts.map +1 -0
  181. package/dist/browser/react/use-navigation.js +87 -0
  182. package/dist/browser/react/use-navigation.js.map +1 -0
  183. package/dist/browser/react/use-segments.d.ts +38 -0
  184. package/dist/browser/react/use-segments.d.ts.map +1 -0
  185. package/dist/browser/react/use-segments.js +130 -0
  186. package/dist/browser/react/use-segments.js.map +1 -0
  187. package/dist/browser/request-controller.d.ts +26 -0
  188. package/dist/browser/request-controller.d.ts.map +1 -0
  189. package/dist/browser/request-controller.js +147 -0
  190. package/dist/browser/request-controller.js.map +1 -0
  191. package/dist/browser/rsc-router.d.ts +129 -0
  192. package/dist/browser/rsc-router.d.ts.map +1 -0
  193. package/dist/browser/rsc-router.js +195 -0
  194. package/dist/browser/rsc-router.js.map +1 -0
  195. package/dist/browser/scroll-restoration.d.ts +93 -0
  196. package/dist/browser/scroll-restoration.d.ts.map +1 -0
  197. package/dist/browser/scroll-restoration.js +321 -0
  198. package/dist/browser/scroll-restoration.js.map +1 -0
  199. package/dist/browser/segment-structure-assert.d.ts +17 -0
  200. package/dist/browser/segment-structure-assert.d.ts.map +1 -0
  201. package/dist/browser/segment-structure-assert.js +59 -0
  202. package/dist/browser/segment-structure-assert.js.map +1 -0
  203. package/dist/browser/server-action-bridge.d.ts +26 -0
  204. package/dist/browser/server-action-bridge.d.ts.map +1 -0
  205. package/dist/browser/server-action-bridge.js +668 -0
  206. package/dist/browser/server-action-bridge.js.map +1 -0
  207. package/dist/browser/shallow.d.ts +12 -0
  208. package/dist/browser/shallow.d.ts.map +1 -0
  209. package/dist/browser/shallow.js +34 -0
  210. package/dist/browser/shallow.js.map +1 -0
  211. package/dist/browser/types.d.ts +369 -0
  212. package/dist/browser/types.d.ts.map +1 -0
  213. package/dist/browser/types.js +2 -0
  214. package/dist/browser/types.js.map +1 -0
  215. package/dist/build/__tests__/generate-cli.test.d.ts +2 -0
  216. package/dist/build/__tests__/generate-cli.test.d.ts.map +1 -0
  217. package/dist/build/__tests__/generate-cli.test.js +237 -0
  218. package/dist/build/__tests__/generate-cli.test.js.map +1 -0
  219. package/dist/build/__tests__/generate-manifest.test.d.ts +2 -0
  220. package/dist/build/__tests__/generate-manifest.test.d.ts.map +1 -0
  221. package/dist/build/__tests__/generate-manifest.test.js +119 -0
  222. package/dist/build/__tests__/generate-manifest.test.js.map +1 -0
  223. package/dist/build/__tests__/generate-route-types.test.d.ts +2 -0
  224. package/dist/build/__tests__/generate-route-types.test.d.ts.map +1 -0
  225. package/dist/build/__tests__/generate-route-types.test.js +620 -0
  226. package/dist/build/__tests__/generate-route-types.test.js.map +1 -0
  227. package/dist/build/__tests__/per-router-manifest.test.d.ts +2 -0
  228. package/dist/build/__tests__/per-router-manifest.test.d.ts.map +1 -0
  229. package/dist/build/__tests__/per-router-manifest.test.js +308 -0
  230. package/dist/build/__tests__/per-router-manifest.test.js.map +1 -0
  231. package/dist/build/generate-manifest.d.ts +81 -0
  232. package/dist/build/generate-manifest.d.ts.map +1 -0
  233. package/dist/build/generate-manifest.js +276 -0
  234. package/dist/build/generate-manifest.js.map +1 -0
  235. package/dist/build/generate-route-types.d.ts +115 -0
  236. package/dist/build/generate-route-types.d.ts.map +1 -0
  237. package/dist/build/generate-route-types.js +740 -0
  238. package/dist/build/generate-route-types.js.map +1 -0
  239. package/dist/build/index.d.ts +21 -0
  240. package/dist/build/index.d.ts.map +1 -0
  241. package/dist/build/index.js +21 -0
  242. package/dist/build/index.js.map +1 -0
  243. package/dist/build/route-trie.d.ts +71 -0
  244. package/dist/build/route-trie.d.ts.map +1 -0
  245. package/dist/build/route-trie.js +175 -0
  246. package/dist/build/route-trie.js.map +1 -0
  247. package/dist/cache/__tests__/cache-scope.test.d.ts +2 -0
  248. package/dist/cache/__tests__/cache-scope.test.d.ts.map +1 -0
  249. package/dist/cache/__tests__/cache-scope.test.js +208 -0
  250. package/dist/cache/__tests__/cache-scope.test.js.map +1 -0
  251. package/dist/cache/__tests__/document-cache.test.d.ts +2 -0
  252. package/dist/cache/__tests__/document-cache.test.d.ts.map +1 -0
  253. package/dist/cache/__tests__/document-cache.test.js +345 -0
  254. package/dist/cache/__tests__/document-cache.test.js.map +1 -0
  255. package/dist/cache/__tests__/memory-segment-store.test.d.ts +2 -0
  256. package/dist/cache/__tests__/memory-segment-store.test.d.ts.map +1 -0
  257. package/dist/cache/__tests__/memory-segment-store.test.js +425 -0
  258. package/dist/cache/__tests__/memory-segment-store.test.js.map +1 -0
  259. package/dist/cache/__tests__/memory-store.test.d.ts +2 -0
  260. package/dist/cache/__tests__/memory-store.test.d.ts.map +1 -0
  261. package/dist/cache/__tests__/memory-store.test.js +367 -0
  262. package/dist/cache/__tests__/memory-store.test.js.map +1 -0
  263. package/dist/cache/cache-scope.d.ts +102 -0
  264. package/dist/cache/cache-scope.d.ts.map +1 -0
  265. package/dist/cache/cache-scope.js +440 -0
  266. package/dist/cache/cache-scope.js.map +1 -0
  267. package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts +2 -0
  268. package/dist/cache/cf/__tests__/cf-cache-store.test.d.ts.map +1 -0
  269. package/dist/cache/cf/__tests__/cf-cache-store.test.js +330 -0
  270. package/dist/cache/cf/__tests__/cf-cache-store.test.js.map +1 -0
  271. package/dist/cache/cf/cf-cache-store.d.ts +165 -0
  272. package/dist/cache/cf/cf-cache-store.d.ts.map +1 -0
  273. package/dist/cache/cf/cf-cache-store.js +242 -0
  274. package/dist/cache/cf/cf-cache-store.js.map +1 -0
  275. package/dist/cache/cf/index.d.ts +14 -0
  276. package/dist/cache/cf/index.d.ts.map +1 -0
  277. package/dist/cache/cf/index.js +17 -0
  278. package/dist/cache/cf/index.js.map +1 -0
  279. package/dist/cache/document-cache.d.ts +64 -0
  280. package/dist/cache/document-cache.d.ts.map +1 -0
  281. package/dist/cache/document-cache.js +228 -0
  282. package/dist/cache/document-cache.js.map +1 -0
  283. package/dist/cache/index.d.ts +19 -0
  284. package/dist/cache/index.d.ts.map +1 -0
  285. package/dist/cache/index.js +21 -0
  286. package/dist/cache/index.js.map +1 -0
  287. package/dist/cache/memory-segment-store.d.ts +110 -0
  288. package/dist/cache/memory-segment-store.d.ts.map +1 -0
  289. package/dist/cache/memory-segment-store.js +117 -0
  290. package/dist/cache/memory-segment-store.js.map +1 -0
  291. package/dist/cache/memory-store.d.ts +41 -0
  292. package/dist/cache/memory-store.d.ts.map +1 -0
  293. package/dist/cache/memory-store.js +191 -0
  294. package/dist/cache/memory-store.js.map +1 -0
  295. package/dist/cache/types.d.ts +317 -0
  296. package/dist/cache/types.d.ts.map +1 -0
  297. package/dist/cache/types.js +12 -0
  298. package/dist/cache/types.js.map +1 -0
  299. package/dist/client.d.ts +248 -0
  300. package/dist/client.d.ts.map +1 -0
  301. package/dist/client.js +367 -0
  302. package/dist/client.js.map +1 -0
  303. package/dist/client.rsc.d.ts +26 -0
  304. package/dist/client.rsc.d.ts.map +1 -0
  305. package/dist/client.rsc.js +46 -0
  306. package/dist/client.rsc.js.map +1 -0
  307. package/dist/component-utils.d.ts +36 -0
  308. package/dist/component-utils.d.ts.map +1 -0
  309. package/dist/component-utils.js +61 -0
  310. package/dist/component-utils.js.map +1 -0
  311. package/dist/components/DefaultDocument.d.ts +13 -0
  312. package/dist/components/DefaultDocument.d.ts.map +1 -0
  313. package/dist/components/DefaultDocument.js +15 -0
  314. package/dist/components/DefaultDocument.js.map +1 -0
  315. package/dist/debug.d.ts +58 -0
  316. package/dist/debug.d.ts.map +1 -0
  317. package/dist/debug.js +157 -0
  318. package/dist/debug.js.map +1 -0
  319. package/dist/default-error-boundary.d.ts +11 -0
  320. package/dist/default-error-boundary.d.ts.map +1 -0
  321. package/dist/default-error-boundary.js +45 -0
  322. package/dist/default-error-boundary.js.map +1 -0
  323. package/dist/deps/browser.d.ts +2 -0
  324. package/dist/deps/browser.d.ts.map +1 -0
  325. package/dist/deps/browser.js +3 -0
  326. package/dist/deps/browser.js.map +1 -0
  327. package/dist/deps/html-stream-client.d.ts +2 -0
  328. package/dist/deps/html-stream-client.d.ts.map +1 -0
  329. package/dist/deps/html-stream-client.js +3 -0
  330. package/dist/deps/html-stream-client.js.map +1 -0
  331. package/dist/deps/html-stream-server.d.ts +2 -0
  332. package/dist/deps/html-stream-server.d.ts.map +1 -0
  333. package/dist/deps/html-stream-server.js +3 -0
  334. package/dist/deps/html-stream-server.js.map +1 -0
  335. package/dist/deps/rsc.d.ts +2 -0
  336. package/dist/deps/rsc.d.ts.map +1 -0
  337. package/dist/deps/rsc.js +4 -0
  338. package/dist/deps/rsc.js.map +1 -0
  339. package/dist/deps/ssr.d.ts +2 -0
  340. package/dist/deps/ssr.d.ts.map +1 -0
  341. package/dist/deps/ssr.js +3 -0
  342. package/dist/deps/ssr.js.map +1 -0
  343. package/dist/errors.d.ts +174 -0
  344. package/dist/errors.d.ts.map +1 -0
  345. package/dist/errors.js +241 -0
  346. package/dist/errors.js.map +1 -0
  347. package/dist/handle.d.ts +78 -0
  348. package/dist/handle.d.ts.map +1 -0
  349. package/dist/handle.js +82 -0
  350. package/dist/handle.js.map +1 -0
  351. package/dist/handles/MetaTags.d.ts +14 -0
  352. package/dist/handles/MetaTags.d.ts.map +1 -0
  353. package/dist/handles/MetaTags.js +136 -0
  354. package/dist/handles/MetaTags.js.map +1 -0
  355. package/{src/handles/index.ts → dist/handles/index.d.ts} +1 -2
  356. package/dist/handles/index.d.ts.map +1 -0
  357. package/dist/handles/index.js +6 -0
  358. package/dist/handles/index.js.map +1 -0
  359. package/dist/handles/meta.d.ts +39 -0
  360. package/dist/handles/meta.d.ts.map +1 -0
  361. package/dist/handles/meta.js +202 -0
  362. package/dist/handles/meta.js.map +1 -0
  363. package/dist/host/__tests__/errors.test.d.ts +2 -0
  364. package/dist/host/__tests__/errors.test.d.ts.map +1 -0
  365. package/dist/host/__tests__/errors.test.js +76 -0
  366. package/dist/host/__tests__/errors.test.js.map +1 -0
  367. package/dist/host/__tests__/pattern-comprehensive.test.d.ts +2 -0
  368. package/dist/host/__tests__/pattern-comprehensive.test.d.ts.map +1 -0
  369. package/dist/host/__tests__/pattern-comprehensive.test.js +732 -0
  370. package/dist/host/__tests__/pattern-comprehensive.test.js.map +1 -0
  371. package/dist/host/__tests__/pattern-matcher.test.d.ts +2 -0
  372. package/dist/host/__tests__/pattern-matcher.test.d.ts.map +1 -0
  373. package/dist/host/__tests__/pattern-matcher.test.js +251 -0
  374. package/dist/host/__tests__/pattern-matcher.test.js.map +1 -0
  375. package/dist/host/__tests__/router.test.d.ts +2 -0
  376. package/dist/host/__tests__/router.test.d.ts.map +1 -0
  377. package/dist/host/__tests__/router.test.js +241 -0
  378. package/dist/host/__tests__/router.test.js.map +1 -0
  379. package/dist/host/__tests__/testing.test.d.ts +2 -0
  380. package/dist/host/__tests__/testing.test.d.ts.map +1 -0
  381. package/dist/host/__tests__/testing.test.js +64 -0
  382. package/dist/host/__tests__/testing.test.js.map +1 -0
  383. package/dist/host/__tests__/utils.test.d.ts +2 -0
  384. package/dist/host/__tests__/utils.test.d.ts.map +1 -0
  385. package/dist/host/__tests__/utils.test.js +29 -0
  386. package/dist/host/__tests__/utils.test.js.map +1 -0
  387. package/dist/host/cookie-handler.d.ts +34 -0
  388. package/dist/host/cookie-handler.d.ts.map +1 -0
  389. package/dist/host/cookie-handler.js +124 -0
  390. package/dist/host/cookie-handler.js.map +1 -0
  391. package/dist/host/errors.d.ts +56 -0
  392. package/dist/host/errors.d.ts.map +1 -0
  393. package/dist/host/errors.js +79 -0
  394. package/dist/host/errors.js.map +1 -0
  395. package/dist/host/index.d.ts +29 -0
  396. package/dist/host/index.d.ts.map +1 -0
  397. package/dist/host/index.js +32 -0
  398. package/dist/host/index.js.map +1 -0
  399. package/dist/host/pattern-matcher.d.ts +36 -0
  400. package/dist/host/pattern-matcher.d.ts.map +1 -0
  401. package/dist/host/pattern-matcher.js +172 -0
  402. package/dist/host/pattern-matcher.js.map +1 -0
  403. package/dist/host/router.d.ts +26 -0
  404. package/dist/host/router.d.ts.map +1 -0
  405. package/dist/host/router.js +218 -0
  406. package/dist/host/router.js.map +1 -0
  407. package/dist/host/testing.d.ts +36 -0
  408. package/dist/host/testing.d.ts.map +1 -0
  409. package/dist/host/testing.js +55 -0
  410. package/dist/host/testing.js.map +1 -0
  411. package/dist/host/types.d.ts +115 -0
  412. package/dist/host/types.d.ts.map +1 -0
  413. package/dist/host/types.js +7 -0
  414. package/dist/host/types.js.map +1 -0
  415. package/dist/host/utils.d.ts +21 -0
  416. package/dist/host/utils.d.ts.map +1 -0
  417. package/dist/host/utils.js +23 -0
  418. package/dist/host/utils.js.map +1 -0
  419. package/dist/href-client.d.ts +131 -0
  420. package/dist/href-client.d.ts.map +1 -0
  421. package/dist/href-client.js +64 -0
  422. package/dist/href-client.js.map +1 -0
  423. package/dist/href-context.d.ts +29 -0
  424. package/dist/href-context.d.ts.map +1 -0
  425. package/dist/href-context.js +21 -0
  426. package/dist/href-context.js.map +1 -0
  427. package/dist/index.d.ts +73 -0
  428. package/dist/index.d.ts.map +1 -0
  429. package/dist/index.js +91 -0
  430. package/dist/index.js.map +1 -0
  431. package/dist/index.rsc.d.ts +32 -0
  432. package/dist/index.rsc.d.ts.map +1 -0
  433. package/dist/index.rsc.js +40 -0
  434. package/dist/index.rsc.js.map +1 -0
  435. package/dist/internal-debug.d.ts +2 -0
  436. package/dist/internal-debug.d.ts.map +1 -0
  437. package/dist/internal-debug.js +5 -0
  438. package/dist/internal-debug.js.map +1 -0
  439. package/dist/loader.d.ts +14 -0
  440. package/dist/loader.d.ts.map +1 -0
  441. package/dist/loader.js +20 -0
  442. package/dist/loader.js.map +1 -0
  443. package/dist/loader.rsc.d.ts +19 -0
  444. package/dist/loader.rsc.d.ts.map +1 -0
  445. package/dist/loader.rsc.js +99 -0
  446. package/dist/loader.rsc.js.map +1 -0
  447. package/{src/network-error-thrower.tsx → dist/network-error-thrower.d.ts} +4 -10
  448. package/dist/network-error-thrower.d.ts.map +1 -0
  449. package/dist/network-error-thrower.js +14 -0
  450. package/dist/network-error-thrower.js.map +1 -0
  451. package/dist/outlet-context.d.ts +13 -0
  452. package/dist/outlet-context.d.ts.map +1 -0
  453. package/dist/outlet-context.js +3 -0
  454. package/dist/outlet-context.js.map +1 -0
  455. package/dist/prerender/__tests__/param-hash.test.d.ts +2 -0
  456. package/dist/prerender/__tests__/param-hash.test.d.ts.map +1 -0
  457. package/dist/prerender/__tests__/param-hash.test.js +148 -0
  458. package/dist/prerender/__tests__/param-hash.test.js.map +1 -0
  459. package/dist/prerender/param-hash.d.ts +16 -0
  460. package/dist/prerender/param-hash.d.ts.map +1 -0
  461. package/dist/prerender/param-hash.js +36 -0
  462. package/dist/prerender/param-hash.js.map +1 -0
  463. package/dist/prerender/store.d.ts +38 -0
  464. package/dist/prerender/store.d.ts.map +1 -0
  465. package/dist/prerender/store.js +61 -0
  466. package/dist/prerender/store.js.map +1 -0
  467. package/dist/prerender.d.ts +66 -0
  468. package/dist/prerender.d.ts.map +1 -0
  469. package/dist/prerender.js +57 -0
  470. package/dist/prerender.js.map +1 -0
  471. package/dist/reverse.d.ts +196 -0
  472. package/dist/reverse.d.ts.map +1 -0
  473. package/dist/reverse.js +78 -0
  474. package/dist/reverse.js.map +1 -0
  475. package/dist/root-error-boundary.d.ts +33 -0
  476. package/dist/root-error-boundary.d.ts.map +1 -0
  477. package/dist/root-error-boundary.js +165 -0
  478. package/dist/root-error-boundary.js.map +1 -0
  479. package/dist/route-content-wrapper.d.ts +46 -0
  480. package/dist/route-content-wrapper.d.ts.map +1 -0
  481. package/dist/route-content-wrapper.js +77 -0
  482. package/dist/route-content-wrapper.js.map +1 -0
  483. package/dist/route-definition.d.ts +421 -0
  484. package/dist/route-definition.d.ts.map +1 -0
  485. package/dist/route-definition.js +868 -0
  486. package/dist/route-definition.js.map +1 -0
  487. package/dist/route-map-builder.d.ts +155 -0
  488. package/dist/route-map-builder.d.ts.map +1 -0
  489. package/dist/route-map-builder.js +237 -0
  490. package/dist/route-map-builder.js.map +1 -0
  491. package/dist/route-types.d.ts +165 -0
  492. package/dist/route-types.d.ts.map +1 -0
  493. package/dist/route-types.js +7 -0
  494. package/dist/route-types.js.map +1 -0
  495. package/dist/router/__tests__/handler-context.test.d.ts +2 -0
  496. package/dist/router/__tests__/handler-context.test.d.ts.map +1 -0
  497. package/dist/router/__tests__/handler-context.test.js +65 -0
  498. package/dist/router/__tests__/handler-context.test.js.map +1 -0
  499. package/dist/router/__tests__/loader-cycle-detection.test.d.ts +2 -0
  500. package/dist/router/__tests__/loader-cycle-detection.test.d.ts.map +1 -0
  501. package/dist/router/__tests__/loader-cycle-detection.test.js +221 -0
  502. package/dist/router/__tests__/loader-cycle-detection.test.js.map +1 -0
  503. package/dist/router/__tests__/match-context.test.d.ts +2 -0
  504. package/dist/router/__tests__/match-context.test.d.ts.map +1 -0
  505. package/dist/router/__tests__/match-context.test.js +92 -0
  506. package/dist/router/__tests__/match-context.test.js.map +1 -0
  507. package/dist/router/__tests__/match-pipelines.test.d.ts +2 -0
  508. package/dist/router/__tests__/match-pipelines.test.d.ts.map +1 -0
  509. package/dist/router/__tests__/match-pipelines.test.js +417 -0
  510. package/dist/router/__tests__/match-pipelines.test.js.map +1 -0
  511. package/dist/router/__tests__/match-result.test.d.ts +2 -0
  512. package/dist/router/__tests__/match-result.test.d.ts.map +1 -0
  513. package/dist/router/__tests__/match-result.test.js +457 -0
  514. package/dist/router/__tests__/match-result.test.js.map +1 -0
  515. package/dist/router/__tests__/on-error.test.d.ts +2 -0
  516. package/dist/router/__tests__/on-error.test.d.ts.map +1 -0
  517. package/dist/router/__tests__/on-error.test.js +678 -0
  518. package/dist/router/__tests__/on-error.test.js.map +1 -0
  519. package/dist/router/__tests__/pattern-matching.test.d.ts +2 -0
  520. package/dist/router/__tests__/pattern-matching.test.d.ts.map +1 -0
  521. package/dist/router/__tests__/pattern-matching.test.js +629 -0
  522. package/dist/router/__tests__/pattern-matching.test.js.map +1 -0
  523. package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts +2 -0
  524. package/dist/router/__tests__/segment-resolution-parallel-loading.test.d.ts.map +1 -0
  525. package/dist/router/__tests__/segment-resolution-parallel-loading.test.js +155 -0
  526. package/dist/router/__tests__/segment-resolution-parallel-loading.test.js.map +1 -0
  527. package/dist/router/error-handling.d.ts +77 -0
  528. package/dist/router/error-handling.d.ts.map +1 -0
  529. package/dist/router/error-handling.js +202 -0
  530. package/dist/router/error-handling.js.map +1 -0
  531. package/dist/router/handler-context.d.ts +20 -0
  532. package/dist/router/handler-context.d.ts.map +1 -0
  533. package/dist/router/handler-context.js +198 -0
  534. package/dist/router/handler-context.js.map +1 -0
  535. package/dist/router/intercept-resolution.d.ts +66 -0
  536. package/dist/router/intercept-resolution.d.ts.map +1 -0
  537. package/dist/router/intercept-resolution.js +246 -0
  538. package/dist/router/intercept-resolution.js.map +1 -0
  539. package/dist/router/loader-resolution.d.ts +64 -0
  540. package/dist/router/loader-resolution.d.ts.map +1 -0
  541. package/dist/router/loader-resolution.js +284 -0
  542. package/dist/router/loader-resolution.js.map +1 -0
  543. package/dist/router/logging.d.ts +15 -0
  544. package/dist/router/logging.d.ts.map +1 -0
  545. package/dist/router/logging.js +99 -0
  546. package/dist/router/logging.js.map +1 -0
  547. package/dist/router/manifest.d.ts +22 -0
  548. package/dist/router/manifest.d.ts.map +1 -0
  549. package/dist/router/manifest.js +181 -0
  550. package/dist/router/manifest.js.map +1 -0
  551. package/dist/router/match-api.d.ts +35 -0
  552. package/dist/router/match-api.d.ts.map +1 -0
  553. package/dist/router/match-api.js +406 -0
  554. package/dist/router/match-api.js.map +1 -0
  555. package/dist/router/match-context.d.ts +206 -0
  556. package/dist/router/match-context.d.ts.map +1 -0
  557. package/dist/router/match-context.js +17 -0
  558. package/dist/router/match-context.js.map +1 -0
  559. package/dist/router/match-middleware/background-revalidation.d.ts +127 -0
  560. package/dist/router/match-middleware/background-revalidation.d.ts.map +1 -0
  561. package/dist/router/match-middleware/background-revalidation.js +75 -0
  562. package/dist/router/match-middleware/background-revalidation.js.map +1 -0
  563. package/dist/router/match-middleware/cache-lookup.d.ts +112 -0
  564. package/dist/router/match-middleware/cache-lookup.d.ts.map +1 -0
  565. package/dist/router/match-middleware/cache-lookup.js +257 -0
  566. package/dist/router/match-middleware/cache-lookup.js.map +1 -0
  567. package/dist/router/match-middleware/cache-store.d.ts +113 -0
  568. package/dist/router/match-middleware/cache-store.d.ts.map +1 -0
  569. package/dist/router/match-middleware/cache-store.js +108 -0
  570. package/dist/router/match-middleware/cache-store.js.map +1 -0
  571. package/dist/router/match-middleware/index.d.ts +81 -0
  572. package/dist/router/match-middleware/index.d.ts.map +1 -0
  573. package/dist/router/match-middleware/index.js +80 -0
  574. package/dist/router/match-middleware/index.js.map +1 -0
  575. package/dist/router/match-middleware/intercept-resolution.d.ts +117 -0
  576. package/dist/router/match-middleware/intercept-resolution.d.ts.map +1 -0
  577. package/dist/router/match-middleware/intercept-resolution.js +134 -0
  578. package/dist/router/match-middleware/intercept-resolution.js.map +1 -0
  579. package/dist/router/match-middleware/segment-resolution.d.ts +99 -0
  580. package/dist/router/match-middleware/segment-resolution.d.ts.map +1 -0
  581. package/dist/router/match-middleware/segment-resolution.js +53 -0
  582. package/dist/router/match-middleware/segment-resolution.js.map +1 -0
  583. package/dist/router/match-pipelines.d.ts +147 -0
  584. package/dist/router/match-pipelines.d.ts.map +1 -0
  585. package/dist/router/match-pipelines.js +82 -0
  586. package/dist/router/match-pipelines.js.map +1 -0
  587. package/dist/router/match-result.d.ts +126 -0
  588. package/dist/router/match-result.d.ts.map +1 -0
  589. package/dist/router/match-result.js +93 -0
  590. package/dist/router/match-result.js.map +1 -0
  591. package/dist/router/metrics.d.ts +20 -0
  592. package/dist/router/metrics.d.ts.map +1 -0
  593. package/dist/router/metrics.js +47 -0
  594. package/dist/router/metrics.js.map +1 -0
  595. package/dist/router/middleware.d.ts +249 -0
  596. package/dist/router/middleware.d.ts.map +1 -0
  597. package/dist/router/middleware.js +434 -0
  598. package/dist/router/middleware.js.map +1 -0
  599. package/dist/router/middleware.test.d.ts +2 -0
  600. package/dist/router/middleware.test.d.ts.map +1 -0
  601. package/dist/router/middleware.test.js +816 -0
  602. package/dist/router/middleware.test.js.map +1 -0
  603. package/dist/router/pattern-matching.d.ts +149 -0
  604. package/dist/router/pattern-matching.d.ts.map +1 -0
  605. package/dist/router/pattern-matching.js +349 -0
  606. package/dist/router/pattern-matching.js.map +1 -0
  607. package/dist/router/revalidation.d.ts +44 -0
  608. package/dist/router/revalidation.d.ts.map +1 -0
  609. package/dist/router/revalidation.js +147 -0
  610. package/dist/router/revalidation.js.map +1 -0
  611. package/dist/router/router-context.d.ts +135 -0
  612. package/dist/router/router-context.d.ts.map +1 -0
  613. package/dist/router/router-context.js +36 -0
  614. package/dist/router/router-context.js.map +1 -0
  615. package/dist/router/segment-resolution.d.ts +127 -0
  616. package/dist/router/segment-resolution.d.ts.map +1 -0
  617. package/dist/router/segment-resolution.js +919 -0
  618. package/dist/router/segment-resolution.js.map +1 -0
  619. package/dist/router/trie-matching.d.ts +40 -0
  620. package/dist/router/trie-matching.d.ts.map +1 -0
  621. package/dist/router/trie-matching.js +127 -0
  622. package/dist/router/trie-matching.js.map +1 -0
  623. package/dist/router/types.d.ts +136 -0
  624. package/dist/router/types.d.ts.map +1 -0
  625. package/dist/router/types.js +7 -0
  626. package/dist/router/types.js.map +1 -0
  627. package/dist/router.d.ts +753 -0
  628. package/dist/router.d.ts.map +1 -0
  629. package/dist/router.gen.d.ts +6 -0
  630. package/dist/router.gen.d.ts.map +1 -0
  631. package/dist/router.gen.js +6 -0
  632. package/dist/router.gen.js.map +1 -0
  633. package/dist/router.js +1304 -0
  634. package/dist/router.js.map +1 -0
  635. package/dist/rsc/__tests__/helpers.test.d.ts +2 -0
  636. package/dist/rsc/__tests__/helpers.test.d.ts.map +1 -0
  637. package/dist/rsc/__tests__/helpers.test.js +140 -0
  638. package/dist/rsc/__tests__/helpers.test.js.map +1 -0
  639. package/dist/rsc/handler.d.ts +45 -0
  640. package/dist/rsc/handler.d.ts.map +1 -0
  641. package/dist/rsc/handler.js +1172 -0
  642. package/dist/rsc/handler.js.map +1 -0
  643. package/dist/rsc/helpers.d.ts +16 -0
  644. package/dist/rsc/helpers.d.ts.map +1 -0
  645. package/dist/rsc/helpers.js +55 -0
  646. package/dist/rsc/helpers.js.map +1 -0
  647. package/dist/rsc/index.d.ts +22 -0
  648. package/dist/rsc/index.d.ts.map +1 -0
  649. package/dist/rsc/index.js +23 -0
  650. package/dist/rsc/index.js.map +1 -0
  651. package/dist/rsc/nonce.d.ts +9 -0
  652. package/dist/rsc/nonce.d.ts.map +1 -0
  653. package/dist/rsc/nonce.js +18 -0
  654. package/dist/rsc/nonce.js.map +1 -0
  655. package/dist/rsc/types.d.ts +206 -0
  656. package/dist/rsc/types.d.ts.map +1 -0
  657. package/dist/rsc/types.js +8 -0
  658. package/dist/rsc/types.js.map +1 -0
  659. package/dist/search-params.d.ts +103 -0
  660. package/dist/search-params.d.ts.map +1 -0
  661. package/dist/search-params.js +74 -0
  662. package/dist/search-params.js.map +1 -0
  663. package/dist/segment-system.d.ts +75 -0
  664. package/dist/segment-system.d.ts.map +1 -0
  665. package/dist/segment-system.js +336 -0
  666. package/dist/segment-system.js.map +1 -0
  667. package/dist/server/context.d.ts +245 -0
  668. package/dist/server/context.d.ts.map +1 -0
  669. package/dist/server/context.js +197 -0
  670. package/dist/server/context.js.map +1 -0
  671. package/dist/server/fetchable-loader-store.d.ts +18 -0
  672. package/dist/server/fetchable-loader-store.d.ts.map +1 -0
  673. package/dist/server/fetchable-loader-store.js +18 -0
  674. package/dist/server/fetchable-loader-store.js.map +1 -0
  675. package/dist/server/handle-store.d.ts +85 -0
  676. package/dist/server/handle-store.d.ts.map +1 -0
  677. package/dist/server/handle-store.js +142 -0
  678. package/dist/server/handle-store.js.map +1 -0
  679. package/dist/server/loader-registry.d.ts +55 -0
  680. package/dist/server/loader-registry.d.ts.map +1 -0
  681. package/dist/server/loader-registry.js +132 -0
  682. package/dist/server/loader-registry.js.map +1 -0
  683. package/dist/server/request-context.d.ts +226 -0
  684. package/dist/server/request-context.d.ts.map +1 -0
  685. package/dist/server/request-context.js +290 -0
  686. package/dist/server/request-context.js.map +1 -0
  687. package/dist/server/root-layout.d.ts +4 -0
  688. package/dist/server/root-layout.d.ts.map +1 -0
  689. package/dist/server/root-layout.js +5 -0
  690. package/dist/server/root-layout.js.map +1 -0
  691. package/dist/server.d.ts +15 -0
  692. package/dist/server.d.ts.map +1 -0
  693. package/dist/server.js +20 -0
  694. package/dist/server.js.map +1 -0
  695. package/dist/ssr/__tests__/ssr-handler.test.d.ts +2 -0
  696. package/dist/ssr/__tests__/ssr-handler.test.d.ts.map +1 -0
  697. package/dist/ssr/__tests__/ssr-handler.test.js +132 -0
  698. package/dist/ssr/__tests__/ssr-handler.test.js.map +1 -0
  699. package/dist/ssr/index.d.ts +98 -0
  700. package/dist/ssr/index.d.ts.map +1 -0
  701. package/dist/ssr/index.js +158 -0
  702. package/dist/ssr/index.js.map +1 -0
  703. package/dist/static-handler.d.ts +50 -0
  704. package/dist/static-handler.d.ts.map +1 -0
  705. package/dist/static-handler.gen.d.ts +5 -0
  706. package/dist/static-handler.gen.d.ts.map +1 -0
  707. package/dist/static-handler.gen.js +5 -0
  708. package/dist/static-handler.gen.js.map +1 -0
  709. package/dist/static-handler.js +29 -0
  710. package/dist/static-handler.js.map +1 -0
  711. package/dist/testing/vitest.js +82 -0
  712. package/dist/theme/ThemeProvider.d.ts +20 -0
  713. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  714. package/dist/theme/ThemeProvider.js +240 -0
  715. package/dist/theme/ThemeProvider.js.map +1 -0
  716. package/dist/theme/ThemeScript.d.ts +48 -0
  717. package/dist/theme/ThemeScript.d.ts.map +1 -0
  718. package/dist/theme/ThemeScript.js +13 -0
  719. package/dist/theme/ThemeScript.js.map +1 -0
  720. package/dist/theme/__tests__/theme.test.d.ts +2 -0
  721. package/dist/theme/__tests__/theme.test.d.ts.map +1 -0
  722. package/dist/theme/__tests__/theme.test.js +103 -0
  723. package/dist/theme/__tests__/theme.test.js.map +1 -0
  724. package/dist/theme/constants.d.ts +29 -0
  725. package/dist/theme/constants.d.ts.map +1 -0
  726. package/dist/theme/constants.js +48 -0
  727. package/dist/theme/constants.js.map +1 -0
  728. package/dist/theme/index.d.ts +31 -0
  729. package/dist/theme/index.d.ts.map +1 -0
  730. package/dist/theme/index.js +36 -0
  731. package/dist/theme/index.js.map +1 -0
  732. package/dist/theme/theme-context.d.ts +40 -0
  733. package/dist/theme/theme-context.d.ts.map +1 -0
  734. package/dist/theme/theme-context.js +60 -0
  735. package/dist/theme/theme-context.js.map +1 -0
  736. package/dist/theme/theme-script.d.ts +27 -0
  737. package/dist/theme/theme-script.d.ts.map +1 -0
  738. package/dist/theme/theme-script.js +147 -0
  739. package/dist/theme/theme-script.js.map +1 -0
  740. package/dist/theme/types.d.ts +163 -0
  741. package/dist/theme/types.d.ts.map +1 -0
  742. package/dist/theme/types.js +11 -0
  743. package/dist/theme/types.js.map +1 -0
  744. package/dist/theme/use-theme.d.ts +12 -0
  745. package/dist/theme/use-theme.d.ts.map +1 -0
  746. package/dist/theme/use-theme.js +40 -0
  747. package/dist/theme/use-theme.js.map +1 -0
  748. package/dist/types.d.ts +1479 -0
  749. package/dist/types.d.ts.map +1 -0
  750. package/dist/types.js +10 -0
  751. package/dist/types.js.map +1 -0
  752. package/dist/urls.d.ts +441 -0
  753. package/dist/urls.d.ts.map +1 -0
  754. package/dist/urls.gen.d.ts +8 -0
  755. package/dist/urls.gen.d.ts.map +1 -0
  756. package/dist/urls.gen.js +8 -0
  757. package/dist/urls.gen.js.map +1 -0
  758. package/dist/urls.js +443 -0
  759. package/dist/urls.js.map +1 -0
  760. package/dist/use-loader.d.ts +127 -0
  761. package/dist/use-loader.d.ts.map +1 -0
  762. package/dist/use-loader.js +237 -0
  763. package/dist/use-loader.js.map +1 -0
  764. package/dist/vite/__tests__/ast-handler-extract.test.d.ts +2 -0
  765. package/dist/vite/__tests__/ast-handler-extract.test.d.ts.map +1 -0
  766. package/dist/vite/__tests__/ast-handler-extract.test.js +294 -0
  767. package/dist/vite/__tests__/ast-handler-extract.test.js.map +1 -0
  768. package/dist/vite/__tests__/expose-id-utils.test.d.ts +2 -0
  769. package/dist/vite/__tests__/expose-id-utils.test.d.ts.map +1 -0
  770. package/dist/vite/__tests__/expose-id-utils.test.js +224 -0
  771. package/dist/vite/__tests__/expose-id-utils.test.js.map +1 -0
  772. package/dist/vite/__tests__/expose-internal-ids.test.d.ts +2 -0
  773. package/dist/vite/__tests__/expose-internal-ids.test.d.ts.map +1 -0
  774. package/dist/vite/__tests__/expose-internal-ids.test.js +647 -0
  775. package/dist/vite/__tests__/expose-internal-ids.test.js.map +1 -0
  776. package/dist/vite/__tests__/expose-router-id.test.d.ts +2 -0
  777. package/dist/vite/__tests__/expose-router-id.test.d.ts.map +1 -0
  778. package/dist/vite/__tests__/expose-router-id.test.js +39 -0
  779. package/dist/vite/__tests__/expose-router-id.test.js.map +1 -0
  780. package/dist/vite/ast-handler-extract.d.ts +49 -0
  781. package/dist/vite/ast-handler-extract.d.ts.map +1 -0
  782. package/dist/vite/ast-handler-extract.js +249 -0
  783. package/dist/vite/ast-handler-extract.js.map +1 -0
  784. package/dist/vite/expose-action-id.d.ts +19 -0
  785. package/dist/vite/expose-action-id.d.ts.map +1 -0
  786. package/dist/vite/expose-action-id.js +250 -0
  787. package/dist/vite/expose-action-id.js.map +1 -0
  788. package/dist/vite/expose-id-utils.d.ts +69 -0
  789. package/dist/vite/expose-id-utils.d.ts.map +1 -0
  790. package/dist/vite/expose-id-utils.js +289 -0
  791. package/dist/vite/expose-id-utils.js.map +1 -0
  792. package/dist/vite/expose-internal-ids.d.ts +22 -0
  793. package/dist/vite/expose-internal-ids.d.ts.map +1 -0
  794. package/dist/vite/expose-internal-ids.js +886 -0
  795. package/dist/vite/expose-internal-ids.js.map +1 -0
  796. package/dist/vite/index.d.ts +149 -0
  797. package/dist/vite/index.d.ts.map +1 -0
  798. package/dist/vite/index.js +2011 -783
  799. package/dist/vite/index.js.bak +5448 -0
  800. package/dist/vite/index.js.map +1 -0
  801. package/dist/vite/index.named-routes.gen.ts +103 -0
  802. package/dist/vite/package-resolution.d.ts +43 -0
  803. package/dist/vite/package-resolution.d.ts.map +1 -0
  804. package/dist/vite/package-resolution.js +112 -0
  805. package/dist/vite/package-resolution.js.map +1 -0
  806. package/dist/vite/virtual-entries.d.ts +25 -0
  807. package/dist/vite/virtual-entries.d.ts.map +1 -0
  808. package/dist/vite/virtual-entries.js +110 -0
  809. package/dist/vite/virtual-entries.js.map +1 -0
  810. package/package.json +67 -15
  811. package/skills/api-client/SKILL.md +211 -0
  812. package/skills/breadcrumbs/SKILL.md +61 -1
  813. package/skills/bundle-analysis/SKILL.md +159 -0
  814. package/skills/cache-guide/SKILL.md +224 -32
  815. package/skills/caching/SKILL.md +279 -17
  816. package/skills/composability/SKILL.md +27 -3
  817. package/skills/css/SKILL.md +76 -0
  818. package/skills/debug-manifest/SKILL.md +4 -2
  819. package/skills/document-cache/SKILL.md +78 -55
  820. package/skills/handler-use/SKILL.md +11 -9
  821. package/skills/hooks/SKILL.md +240 -28
  822. package/skills/host-router/SKILL.md +83 -23
  823. package/skills/i18n/SKILL.md +276 -0
  824. package/skills/intercept/SKILL.md +68 -19
  825. package/skills/layout/SKILL.md +13 -9
  826. package/skills/links/SKILL.md +175 -17
  827. package/skills/loader/SKILL.md +217 -24
  828. package/skills/middleware/SKILL.md +18 -10
  829. package/skills/migrate-nextjs/SKILL.md +43 -19
  830. package/skills/migrate-react-router/SKILL.md +8 -2
  831. package/skills/mime-routes/SKILL.md +28 -1
  832. package/skills/observability/SKILL.md +172 -0
  833. package/skills/parallel/SKILL.md +18 -7
  834. package/skills/prerender/SKILL.md +65 -60
  835. package/skills/rango/SKILL.md +251 -24
  836. package/skills/react-compiler/SKILL.md +168 -0
  837. package/skills/response-routes/SKILL.md +115 -48
  838. package/skills/route/SKILL.md +46 -5
  839. package/skills/router-setup/SKILL.md +30 -8
  840. package/skills/scripts/SKILL.md +179 -0
  841. package/skills/server-actions/SKILL.md +775 -0
  842. package/skills/tailwind/SKILL.md +27 -3
  843. package/skills/testing/SKILL.md +130 -0
  844. package/skills/testing/bindings.md +103 -0
  845. package/skills/testing/cache-prerender.md +127 -0
  846. package/skills/testing/client-components.md +124 -0
  847. package/skills/testing/e2e-parity.md +125 -0
  848. package/skills/testing/flight.md +91 -0
  849. package/skills/testing/handles.md +129 -0
  850. package/skills/testing/loader.md +128 -0
  851. package/skills/testing/middleware.md +99 -0
  852. package/skills/testing/render-handler.md +122 -0
  853. package/skills/testing/response-routes.md +95 -0
  854. package/skills/testing/reverse-and-types.md +84 -0
  855. package/skills/testing/server-actions.md +107 -0
  856. package/skills/testing/server-tree.md +128 -0
  857. package/skills/testing/setup.md +123 -0
  858. package/skills/typesafety/SKILL.md +319 -28
  859. package/skills/use-cache/SKILL.md +57 -14
  860. package/skills/view-transitions/SKILL.md +337 -0
  861. package/src/__augment-tests__/augment.ts +81 -0
  862. package/src/__augment-tests__/augmented.check.ts +116 -0
  863. package/src/__internal.ts +0 -65
  864. package/src/browser/action-coordinator.ts +53 -36
  865. package/src/browser/action-fence.ts +47 -0
  866. package/src/browser/app-shell.ts +14 -27
  867. package/src/browser/connection-warmup.ts +134 -0
  868. package/src/browser/cookie-name.ts +140 -0
  869. package/src/browser/event-controller.ts +192 -150
  870. package/src/browser/history-state.ts +21 -0
  871. package/src/browser/index.ts +3 -3
  872. package/src/browser/invalidate-client-cache.ts +52 -0
  873. package/src/browser/navigation-bridge.ts +95 -75
  874. package/src/browser/navigation-client.ts +110 -84
  875. package/src/browser/navigation-store-handle.ts +38 -0
  876. package/src/browser/navigation-store.ts +114 -90
  877. package/src/browser/navigation-transaction.ts +9 -59
  878. package/src/browser/network-error-handler.ts +34 -7
  879. package/src/browser/partial-update.ts +147 -147
  880. package/src/browser/prefetch/cache.ts +107 -72
  881. package/src/browser/prefetch/fetch.ts +204 -34
  882. package/src/browser/prefetch/queue.ts +6 -3
  883. package/src/browser/rango-state.ts +157 -115
  884. package/src/browser/react/Link.tsx +30 -7
  885. package/src/browser/react/NavigationProvider.tsx +272 -142
  886. package/src/browser/react/ScrollRestoration.tsx +10 -6
  887. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  888. package/src/browser/react/filter-segment-order.ts +66 -7
  889. package/src/browser/react/index.ts +0 -48
  890. package/src/browser/react/location-state-shared.ts +178 -8
  891. package/src/browser/react/location-state.ts +39 -14
  892. package/src/browser/react/use-action.ts +6 -15
  893. package/src/browser/react/use-handle.ts +17 -14
  894. package/src/browser/react/use-href.tsx +8 -1
  895. package/src/browser/react/use-link-status.ts +33 -8
  896. package/src/browser/react/use-navigation.ts +10 -5
  897. package/src/browser/react/use-params.ts +11 -11
  898. package/src/browser/react/use-reverse.ts +106 -0
  899. package/src/browser/react/use-router.ts +20 -5
  900. package/src/browser/react/use-search-params.ts +0 -5
  901. package/src/browser/react/use-segments.ts +11 -21
  902. package/src/browser/response-adapter.ts +99 -8
  903. package/src/browser/rsc-router.tsx +73 -34
  904. package/src/browser/scroll-restoration.ts +30 -17
  905. package/src/browser/segment-structure-assert.ts +2 -2
  906. package/src/browser/server-action-bridge.ts +214 -55
  907. package/src/browser/types.ts +80 -22
  908. package/src/browser/validate-redirect-origin.ts +43 -16
  909. package/src/build/collect-fallback-refs.ts +107 -0
  910. package/src/build/generate-manifest.ts +60 -35
  911. package/src/build/generate-route-types.ts +2 -1
  912. package/src/build/index.ts +8 -2
  913. package/src/build/prefix-tree-utils.ts +123 -0
  914. package/src/build/route-trie.ts +117 -14
  915. package/src/build/route-types/ast-route-extraction.ts +15 -8
  916. package/src/build/route-types/codegen.ts +16 -5
  917. package/src/build/route-types/include-resolution.ts +117 -23
  918. package/src/build/route-types/param-extraction.ts +6 -3
  919. package/src/build/route-types/per-module-writer.ts +22 -6
  920. package/src/build/route-types/router-processing.ts +55 -28
  921. package/src/build/route-types/scan-filter.ts +1 -1
  922. package/src/build/route-types/source-scan.ts +216 -0
  923. package/src/build/runtime-discovery.ts +9 -20
  924. package/src/cache/cache-error.ts +104 -0
  925. package/src/cache/cache-key-utils.ts +29 -13
  926. package/src/cache/cache-policy.ts +108 -34
  927. package/src/cache/cache-runtime.ts +224 -41
  928. package/src/cache/cache-scope.ts +188 -82
  929. package/src/cache/cache-tag.ts +103 -0
  930. package/src/cache/cf/cf-base64.ts +33 -0
  931. package/src/cache/cf/cf-cache-constants.ts +127 -0
  932. package/src/cache/cf/cf-cache-store.ts +1990 -377
  933. package/src/cache/cf/cf-cache-types.ts +349 -0
  934. package/src/cache/cf/cf-kv-utils.ts +46 -0
  935. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  936. package/src/cache/cf/index.ts +6 -16
  937. package/src/cache/document-cache.ts +89 -21
  938. package/src/cache/handle-snapshot.ts +70 -0
  939. package/src/cache/index.ts +10 -20
  940. package/src/cache/memory-segment-store.ts +136 -37
  941. package/src/cache/profile-registry.ts +46 -31
  942. package/src/cache/read-through-swr.ts +56 -12
  943. package/src/cache/segment-codec.ts +9 -17
  944. package/src/cache/tag-invalidation.ts +230 -0
  945. package/src/cache/types.ts +37 -100
  946. package/src/client.rsc.tsx +44 -21
  947. package/src/client.tsx +36 -61
  948. package/src/cloudflare/index.ts +11 -0
  949. package/src/cloudflare/tracing.ts +109 -0
  950. package/src/component-utils.ts +19 -0
  951. package/src/components/DefaultDocument.tsx +8 -2
  952. package/src/context-var.ts +18 -6
  953. package/src/decode-loader-results.ts +52 -0
  954. package/src/defer.ts +196 -0
  955. package/src/deps/ssr.ts +0 -1
  956. package/src/encode-kv.ts +49 -0
  957. package/src/errors.ts +30 -4
  958. package/src/escape-script.ts +52 -0
  959. package/src/handle.ts +31 -23
  960. package/src/handles/MetaTags.tsx +62 -19
  961. package/src/handles/Scripts.tsx +183 -0
  962. package/src/handles/breadcrumbs.ts +37 -8
  963. package/src/handles/is-thenable.ts +19 -0
  964. package/src/handles/meta.ts +51 -40
  965. package/src/handles/script.ts +244 -0
  966. package/src/host/cookie-handler.ts +9 -60
  967. package/src/host/errors.ts +0 -24
  968. package/src/host/index.ts +8 -2
  969. package/src/host/pattern-matcher.ts +23 -52
  970. package/src/host/router.ts +107 -99
  971. package/src/host/testing.ts +40 -27
  972. package/src/host/types.ts +37 -4
  973. package/src/host/utils.ts +1 -1
  974. package/src/href-client.ts +137 -22
  975. package/src/index.rsc.ts +93 -12
  976. package/src/index.ts +91 -14
  977. package/src/internal-debug.ts +11 -10
  978. package/src/loader-store.ts +500 -0
  979. package/src/loader.rsc.ts +20 -13
  980. package/src/loader.ts +12 -11
  981. package/src/missing-id-error.ts +68 -0
  982. package/src/outlet-provider.tsx +1 -5
  983. package/src/prerender/param-hash.ts +16 -16
  984. package/src/prerender/store.ts +32 -37
  985. package/src/prerender.ts +61 -6
  986. package/src/redirect-origin.ts +100 -0
  987. package/src/regex-escape.ts +8 -0
  988. package/src/render-error-thrower.tsx +20 -0
  989. package/src/response-utils.ts +34 -0
  990. package/src/reverse.ts +65 -40
  991. package/src/root-error-boundary.tsx +1 -19
  992. package/src/route-content-wrapper.tsx +19 -77
  993. package/src/route-definition/dsl-helpers.ts +293 -311
  994. package/src/route-definition/helper-factories.ts +28 -140
  995. package/src/route-definition/helpers-types.ts +82 -55
  996. package/src/route-definition/index.ts +1 -2
  997. package/src/route-definition/redirect.ts +44 -11
  998. package/src/route-definition/resolve-handler-use.ts +6 -1
  999. package/src/route-definition/use-item-types.ts +29 -0
  1000. package/src/route-map-builder.ts +0 -16
  1001. package/src/route-types.ts +19 -46
  1002. package/src/router/basename.ts +14 -0
  1003. package/src/router/content-negotiation.ts +73 -25
  1004. package/src/router/error-handling.ts +45 -18
  1005. package/src/router/find-match.ts +44 -23
  1006. package/src/router/handler-context.ts +10 -42
  1007. package/src/router/instrument.ts +350 -0
  1008. package/src/router/intercept-resolution.ts +39 -20
  1009. package/src/router/lazy-includes.ts +9 -46
  1010. package/src/router/loader-resolution.ts +152 -72
  1011. package/src/router/logging.ts +0 -6
  1012. package/src/router/manifest.ts +18 -29
  1013. package/src/router/match-api.ts +6 -21
  1014. package/src/router/match-context.ts +0 -22
  1015. package/src/router/match-handlers.ts +58 -58
  1016. package/src/router/match-middleware/background-revalidation.ts +40 -24
  1017. package/src/router/match-middleware/cache-lookup.ts +159 -285
  1018. package/src/router/match-middleware/cache-store.ts +64 -52
  1019. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  1020. package/src/router/match-middleware/segment-resolution.ts +0 -22
  1021. package/src/router/match-pipelines.ts +1 -42
  1022. package/src/router/match-result.ts +44 -74
  1023. package/src/router/metrics.ts +0 -34
  1024. package/src/router/middleware-types.ts +5 -112
  1025. package/src/router/middleware.ts +237 -165
  1026. package/src/router/navigation-snapshot.ts +0 -51
  1027. package/src/router/params-util.ts +23 -0
  1028. package/src/router/pattern-matching.ts +85 -94
  1029. package/src/router/prefetch-cache-ttl.ts +51 -0
  1030. package/src/router/prerender-match.ts +104 -65
  1031. package/src/router/preview-match.ts +3 -1
  1032. package/src/router/request-classification.ts +28 -62
  1033. package/src/router/revalidation.ts +123 -73
  1034. package/src/router/route-snapshot.ts +0 -1
  1035. package/src/router/router-context.ts +3 -28
  1036. package/src/router/router-interfaces.ts +83 -35
  1037. package/src/router/router-options.ts +136 -5
  1038. package/src/router/router-registry.ts +2 -5
  1039. package/src/router/segment-resolution/fresh.ts +97 -84
  1040. package/src/router/segment-resolution/helpers.ts +86 -6
  1041. package/src/router/segment-resolution/loader-cache.ts +76 -39
  1042. package/src/router/segment-resolution/revalidation.ts +272 -320
  1043. package/src/router/segment-resolution/static-store.ts +19 -5
  1044. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  1045. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  1046. package/src/router/segment-resolution.ts +5 -1
  1047. package/src/router/segment-wrappers.ts +6 -5
  1048. package/src/router/state-cookie-name.ts +33 -0
  1049. package/src/router/substitute-pattern-params.ts +56 -0
  1050. package/src/router/telemetry-otel.ts +161 -199
  1051. package/src/router/telemetry.ts +96 -19
  1052. package/src/router/timeout.ts +0 -20
  1053. package/src/router/tracing.ts +206 -0
  1054. package/src/router/trie-matching.ts +162 -64
  1055. package/src/router/types.ts +9 -63
  1056. package/src/router/url-params.ts +0 -5
  1057. package/src/router.ts +109 -53
  1058. package/src/rsc/handler-context.ts +3 -2
  1059. package/src/rsc/handler.ts +262 -219
  1060. package/src/rsc/helpers.ts +100 -6
  1061. package/src/rsc/index.ts +2 -5
  1062. package/src/rsc/json-route-result.ts +38 -0
  1063. package/src/rsc/loader-fetch.ts +114 -38
  1064. package/src/rsc/manifest-init.ts +28 -41
  1065. package/src/rsc/origin-guard.ts +39 -25
  1066. package/src/rsc/progressive-enhancement.ts +117 -11
  1067. package/src/rsc/redirect-guard.ts +99 -0
  1068. package/src/rsc/response-cache-serve.ts +238 -0
  1069. package/src/rsc/response-error.ts +79 -12
  1070. package/src/rsc/response-route-handler.ts +85 -188
  1071. package/src/rsc/rsc-rendering.ts +98 -76
  1072. package/src/rsc/runtime-warnings.ts +23 -10
  1073. package/src/rsc/server-action.ts +281 -117
  1074. package/src/rsc/ssr-setup.ts +16 -0
  1075. package/src/rsc/transition-gate.ts +89 -0
  1076. package/src/rsc/types.ts +23 -5
  1077. package/src/runtime-env.ts +18 -0
  1078. package/src/search-params.ts +35 -30
  1079. package/src/segment-loader-promise.ts +31 -4
  1080. package/src/segment-system.tsx +227 -143
  1081. package/src/serialize.ts +243 -0
  1082. package/src/server/context.ts +163 -51
  1083. package/src/server/cookie-parse.ts +32 -0
  1084. package/src/server/cookie-store.ts +80 -5
  1085. package/src/server/handle-store.ts +21 -38
  1086. package/src/server/loader-registry.ts +33 -42
  1087. package/src/server/request-context.ts +277 -136
  1088. package/src/ssr/index.tsx +21 -16
  1089. package/src/static-handler.ts +10 -13
  1090. package/src/testing/cache-status.ts +162 -0
  1091. package/src/testing/collect-handle.ts +40 -0
  1092. package/src/testing/dispatch.ts +701 -0
  1093. package/src/testing/dom.entry.ts +22 -0
  1094. package/src/testing/e2e/fixture.ts +188 -0
  1095. package/src/testing/e2e/index.ts +128 -0
  1096. package/src/testing/e2e/matchers.ts +35 -0
  1097. package/src/testing/e2e/page-helpers.ts +272 -0
  1098. package/src/testing/e2e/parity.ts +387 -0
  1099. package/src/testing/e2e/server.ts +195 -0
  1100. package/src/testing/flight-matchers.ts +97 -0
  1101. package/src/testing/flight-normalize.ts +11 -0
  1102. package/src/testing/flight-runtime.d.ts +57 -0
  1103. package/src/testing/flight-tree.ts +682 -0
  1104. package/src/testing/flight.entry.ts +52 -0
  1105. package/src/testing/flight.ts +257 -0
  1106. package/src/testing/generated-routes.ts +183 -0
  1107. package/src/testing/index.ts +105 -0
  1108. package/src/testing/internal/context.ts +371 -0
  1109. package/src/testing/internal/flight-client-globals.ts +30 -0
  1110. package/src/testing/internal/seed-vars.ts +54 -0
  1111. package/src/testing/render-handler.ts +357 -0
  1112. package/src/testing/render-route.tsx +581 -0
  1113. package/src/testing/run-loader.ts +385 -0
  1114. package/src/testing/run-middleware.ts +205 -0
  1115. package/src/testing/run-transition-when.ts +164 -0
  1116. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  1117. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  1118. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  1119. package/src/testing/vitest-stubs/version.ts +5 -0
  1120. package/src/testing/vitest.ts +305 -0
  1121. package/src/theme/ThemeProvider.tsx +20 -58
  1122. package/src/theme/ThemeScript.tsx +7 -9
  1123. package/src/theme/constants.ts +52 -13
  1124. package/src/theme/index.ts +0 -7
  1125. package/src/theme/theme-context.ts +1 -5
  1126. package/src/theme/theme-script.ts +22 -21
  1127. package/src/theme/use-theme.ts +0 -3
  1128. package/src/types/boundaries.ts +0 -35
  1129. package/src/types/cache-types.ts +13 -4
  1130. package/src/types/error-types.ts +30 -90
  1131. package/src/types/global-namespace.ts +54 -41
  1132. package/src/types/handler-context.ts +108 -28
  1133. package/src/types/index.ts +3 -10
  1134. package/src/types/loader-types.ts +6 -3
  1135. package/src/types/request-scope.ts +8 -22
  1136. package/src/types/route-config.ts +6 -50
  1137. package/src/types/route-entry.ts +0 -6
  1138. package/src/types/segments.ts +135 -14
  1139. package/src/urls/include-helper.ts +9 -56
  1140. package/src/urls/index.ts +1 -11
  1141. package/src/urls/path-helper-types.ts +29 -12
  1142. package/src/urls/path-helper.ts +17 -106
  1143. package/src/urls/pattern-types.ts +36 -19
  1144. package/src/urls/response-types.ts +20 -19
  1145. package/src/urls/type-extraction.ts +58 -139
  1146. package/src/urls/urls-function.ts +1 -19
  1147. package/src/use-loader.tsx +292 -107
  1148. package/src/vite/debug.ts +58 -13
  1149. package/src/vite/discovery/bundle-postprocess.ts +8 -7
  1150. package/src/vite/discovery/discover-routers.ts +97 -84
  1151. package/src/vite/discovery/discovery-errors.ts +194 -0
  1152. package/src/vite/discovery/gate-state.ts +171 -0
  1153. package/src/vite/discovery/prerender-collection.ts +50 -69
  1154. package/src/vite/discovery/route-types-writer.ts +40 -84
  1155. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  1156. package/src/vite/discovery/state.ts +44 -0
  1157. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  1158. package/src/vite/index.ts +2 -0
  1159. package/src/vite/inject-client-debug.ts +36 -0
  1160. package/src/vite/plugin-types.ts +126 -8
  1161. package/src/vite/plugins/cjs-to-esm.ts +14 -28
  1162. package/src/vite/plugins/client-ref-dedup.ts +5 -21
  1163. package/src/vite/plugins/client-ref-hashing.ts +14 -13
  1164. package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
  1165. package/src/vite/plugins/expose-action-id.ts +6 -77
  1166. package/src/vite/plugins/expose-id-utils.ts +88 -55
  1167. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  1168. package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
  1169. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  1170. package/src/vite/plugins/expose-ids/router-transform.ts +100 -28
  1171. package/src/vite/plugins/expose-internal-ids.ts +59 -70
  1172. package/src/vite/plugins/performance-tracks.ts +11 -18
  1173. package/src/vite/plugins/refresh-cmd.ts +1 -1
  1174. package/src/vite/plugins/use-cache-transform.ts +28 -52
  1175. package/src/vite/plugins/version-injector.ts +40 -29
  1176. package/src/vite/plugins/version-plugin.ts +37 -40
  1177. package/src/vite/plugins/virtual-entries.ts +39 -25
  1178. package/src/vite/rango.ts +62 -106
  1179. package/src/vite/router-discovery.ts +591 -122
  1180. package/src/vite/utils/ast-handler-extract.ts +26 -35
  1181. package/src/vite/utils/bundle-analysis.ts +10 -15
  1182. package/src/vite/utils/client-chunks.ts +184 -0
  1183. package/src/vite/utils/directive-prologue.ts +40 -0
  1184. package/src/vite/utils/forward-user-plugins.ts +171 -0
  1185. package/src/vite/utils/manifest-utils.ts +4 -59
  1186. package/src/vite/utils/package-resolution.ts +1 -73
  1187. package/src/vite/utils/prerender-utils.ts +54 -39
  1188. package/src/vite/utils/shared-utils.ts +90 -41
  1189. package/src/browser/action-response-classifier.ts +0 -99
  1190. package/src/browser/shallow.ts +0 -40
  1191. package/src/router/middleware-cookies.ts +0 -55
@@ -10,6 +10,13 @@ import fs from "node:fs";
10
10
  // src/vite/plugins/expose-id-utils.ts
11
11
  import path from "node:path";
12
12
  import crypto from "node:crypto";
13
+
14
+ // src/regex-escape.ts
15
+ function escapeRegExp(input) {
16
+ return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17
+ }
18
+
19
+ // src/vite/plugins/expose-id-utils.ts
13
20
  function normalizePath(p) {
14
21
  return p.split(path.sep).join("/");
15
22
  }
@@ -21,8 +28,8 @@ function hashId(filePath, exportName) {
21
28
  function makeStubId(filePath, exportName, isBuild) {
22
29
  return isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
23
30
  }
24
- function hashInlineId(filePath, lineNumber, index) {
25
- const input = index !== void 0 && index > 0 ? `${filePath}:${lineNumber}:${index}` : `${filePath}:${lineNumber}`;
31
+ function hashInlineId(filePath, fnName, index) {
32
+ const input = `${filePath}:${fnName}:${index}`;
26
33
  return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
27
34
  }
28
35
  function buildExportMap(program) {
@@ -158,7 +165,9 @@ function countArgs(code, startPos, endPos) {
158
165
  while (i < endPos) {
159
166
  const skipped = skipStringOrComment(code, i);
160
167
  if (skipped > i) {
161
- hasContent = true;
168
+ const ch = code[i];
169
+ const isComment = ch === "/" && i + 1 < code.length && (code[i + 1] === "/" || code[i + 1] === "*");
170
+ if (!isComment) hasContent = true;
162
171
  i = skipped;
163
172
  continue;
164
173
  }
@@ -187,12 +196,73 @@ function findStatementEnd(code, pos) {
187
196
  }
188
197
  return i;
189
198
  }
190
- function escapeRegExp(input) {
191
- return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
199
+ function findCallParenAfterGenerics(code, afterCalleeIndex) {
200
+ let i = afterCalleeIndex;
201
+ while (i < code.length) {
202
+ const skipped = skipStringOrComment(code, i);
203
+ if (skipped > i) {
204
+ i = skipped;
205
+ continue;
206
+ }
207
+ if (/\s/.test(code[i])) {
208
+ i++;
209
+ continue;
210
+ }
211
+ break;
212
+ }
213
+ if (i >= code.length) return -1;
214
+ if (code[i] === "(") return i;
215
+ if (code[i] === "<") {
216
+ let depth = 0;
217
+ while (i < code.length) {
218
+ const skipped = skipStringOrComment(code, i);
219
+ if (skipped > i) {
220
+ i = skipped;
221
+ continue;
222
+ }
223
+ const ch = code[i];
224
+ if (ch === "<") {
225
+ depth++;
226
+ } else if (ch === ">") {
227
+ depth--;
228
+ if (depth === 0) {
229
+ i++;
230
+ break;
231
+ }
232
+ }
233
+ i++;
234
+ }
235
+ if (depth !== 0) return -1;
236
+ while (i < code.length) {
237
+ const skipped = skipStringOrComment(code, i);
238
+ if (skipped > i) {
239
+ i = skipped;
240
+ continue;
241
+ }
242
+ if (/\s/.test(code[i])) {
243
+ i++;
244
+ continue;
245
+ }
246
+ break;
247
+ }
248
+ if (i < code.length && code[i] === "(") return i;
249
+ return -1;
250
+ }
251
+ return -1;
192
252
  }
193
253
 
194
254
  // src/vite/debug.ts
195
255
  import debugFactory from "debug";
256
+ var NS = {
257
+ config: "rango:config",
258
+ discovery: "rango:discovery",
259
+ routes: "rango:routes",
260
+ prerender: "rango:prerender",
261
+ build: "rango:build",
262
+ dev: "rango:dev",
263
+ transform: "rango:transform",
264
+ chunks: "rango:chunks"
265
+ };
196
266
  if (process.env.INTERNAL_RANGO_DEBUG) {
197
267
  const existing = debugFactory.disable();
198
268
  debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
@@ -228,19 +298,34 @@ function createCounter(debug11, label) {
228
298
  let totalMs = 0;
229
299
  let slowestMs = 0;
230
300
  let slowestFile = "";
231
- let flushed = false;
301
+ const record = (file, ms) => {
302
+ n++;
303
+ totalMs += ms;
304
+ if (ms > slowestMs) {
305
+ slowestMs = ms;
306
+ slowestFile = file;
307
+ }
308
+ };
232
309
  return {
233
- record(file, ms) {
234
- n++;
235
- totalMs += ms;
236
- if (ms > slowestMs) {
237
- slowestMs = ms;
238
- slowestFile = file;
310
+ record,
311
+ time(file, fn) {
312
+ const start = performance.now();
313
+ let out;
314
+ try {
315
+ out = fn();
316
+ } catch (err) {
317
+ record(file, performance.now() - start);
318
+ throw err;
319
+ }
320
+ if (out && typeof out.then === "function") {
321
+ return out.finally(
322
+ () => record(file, performance.now() - start)
323
+ );
239
324
  }
325
+ record(file, performance.now() - start);
326
+ return out;
240
327
  },
241
328
  flush() {
242
- if (flushed) return;
243
- flushed = true;
244
329
  if (n === 0) return;
245
330
  debug11(
246
331
  "%s: %d files, %sms total, slowest %sms %s",
@@ -250,12 +335,16 @@ function createCounter(debug11, label) {
250
335
  slowestMs.toFixed(1),
251
336
  slowestFile
252
337
  );
338
+ n = 0;
339
+ totalMs = 0;
340
+ slowestMs = 0;
341
+ slowestFile = "";
253
342
  }
254
343
  };
255
344
  }
256
345
 
257
346
  // src/vite/plugins/expose-action-id.ts
258
- var debug = createRangoDebugger("rango:transform");
347
+ var debug = createRangoDebugger(NS.transform);
259
348
  function getRscPluginApi(config) {
260
349
  let plugin = config.plugins.find((p) => p.name === "rsc:minimal");
261
350
  if (!plugin) {
@@ -264,7 +353,7 @@ function getRscPluginApi(config) {
264
353
  );
265
354
  if (plugin) {
266
355
  console.warn(
267
- `[rsc-router:expose-action-id] RSC plugin found by API structure (name: "${plugin.name}"). Consider updating the name lookup if the plugin was renamed.`
356
+ `[rango:expose-action-id] RSC plugin found by API structure (name: "${plugin.name}"). Consider updating the name lookup if the plugin was renamed.`
268
357
  );
269
358
  }
270
359
  }
@@ -365,7 +454,7 @@ function exposeActionId() {
365
454
  }
366
455
  if (!rscPluginApi) {
367
456
  throw new Error(
368
- "[rsc-router] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin, which is included automatically by rango()."
457
+ "[rango] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin, which is included automatically by rango()."
369
458
  );
370
459
  }
371
460
  if (!isBuild) return;
@@ -402,7 +491,6 @@ function exposeActionId() {
402
491
  counterTransform?.record(id, performance.now() - start);
403
492
  }
404
493
  },
405
- // Build mode: renderChunk runs after all transforms and bundling complete
406
494
  renderChunk(code, chunk) {
407
495
  const start = counterRender ? performance.now() : 0;
408
496
  try {
@@ -437,17 +525,17 @@ function exposeActionId() {
437
525
 
438
526
  // src/vite/plugins/expose-internal-ids.ts
439
527
  import { parseAst as parseAst2 } from "vite";
440
- import MagicString4 from "magic-string";
528
+ import MagicString3 from "magic-string";
441
529
  import path4 from "node:path";
442
530
 
443
531
  // src/vite/utils/ast-handler-extract.ts
444
532
  function isDirectivePrologueStatement(node) {
445
533
  return node?.type === "ExpressionStatement" && typeof node.directive === "string";
446
534
  }
447
- function findImportInsertionPos(code, parseAst4) {
535
+ function findImportInsertionPos(code, parseAst5) {
448
536
  let program;
449
537
  try {
450
- program = parseAst4(code, { jsx: true });
538
+ program = parseAst5(code, { lang: "tsx" });
451
539
  } catch {
452
540
  return 0;
453
541
  }
@@ -484,10 +572,10 @@ function walkNode(node, parent, ancestors, enter) {
484
572
  }
485
573
  ancestors.pop();
486
574
  }
487
- function findHandlerCalls(code, fnName, parseAst4) {
575
+ function findHandlerCalls(code, fnName, parseAst5) {
488
576
  let program;
489
577
  try {
490
- program = parseAst4(code, { jsx: true });
578
+ program = parseAst5(code, { lang: "tsx" });
491
579
  } catch {
492
580
  return [];
493
581
  }
@@ -559,18 +647,18 @@ function getImportedLocalNamesFromProgram(program, importedName) {
559
647
  }
560
648
  return localNames;
561
649
  }
562
- function getImportedLocalNames(code, importedName, parseAst4) {
650
+ function getImportedLocalNames(code, importedName, parseAst5) {
563
651
  try {
564
- const program = parseAst4(code, { jsx: true });
652
+ const program = parseAst5(code, { lang: "tsx" });
565
653
  return getImportedLocalNamesFromProgram(program, importedName);
566
654
  } catch {
567
655
  return /* @__PURE__ */ new Set();
568
656
  }
569
657
  }
570
- function extractImportDeclarations(code, parseAst4) {
658
+ function extractImportDeclarations(code, parseAst5) {
571
659
  let program;
572
660
  try {
573
- program = parseAst4(code, { jsx: true });
661
+ program = parseAst5(code, { lang: "tsx" });
574
662
  } catch {
575
663
  return [];
576
664
  }
@@ -594,13 +682,18 @@ function isInertExpression(node) {
594
682
  (e) => e === null || isInertExpression(e)
595
683
  );
596
684
  case "ObjectExpression":
597
- return (node.properties ?? []).every(
598
- (p) => p.type === "Property" && (!p.computed || isInertExpression(p.key)) && isInertExpression(p.value)
599
- );
685
+ return (node.properties ?? []).every((p) => {
686
+ if (p.type === "SpreadElement" || p.type === "RestElement") {
687
+ return isInertExpression(p.argument);
688
+ }
689
+ return p.type === "Property" && (!p.computed || isInertExpression(p.key)) && isInertExpression(p.value);
690
+ });
600
691
  case "UnaryExpression":
601
692
  return isInertExpression(node.argument);
602
693
  case "BinaryExpression":
603
694
  return isInertExpression(node.left) && isInertExpression(node.right);
695
+ case "LogicalExpression":
696
+ return isInertExpression(node.left) && isInertExpression(node.right);
604
697
  case "ConditionalExpression":
605
698
  return isInertExpression(node.test) && isInertExpression(node.consequent) && isInertExpression(node.alternate);
606
699
  case "SpreadElement":
@@ -622,10 +715,10 @@ function isSafeVariableDeclaration(node, handlerNames) {
622
715
  (d) => isSafeDeclaratorInit(d.init) && !(d.init?.type === "CallExpression" && d.init.callee?.type === "Identifier" && handlerNames.has(d.init.callee.name))
623
716
  );
624
717
  }
625
- function extractModuleLevelDeclarations(code, parseAst4, handlerNames) {
718
+ function extractModuleLevelDeclarations(code, parseAst5, handlerNames) {
626
719
  let program;
627
720
  try {
628
- program = parseAst4(code, { jsx: true });
721
+ program = parseAst5(code, { lang: "tsx" });
629
722
  } catch {
630
723
  return [];
631
724
  }
@@ -656,27 +749,25 @@ function extractModuleLevelDeclarations(code, parseAst4, handlerNames) {
656
749
  }
657
750
  return declarations;
658
751
  }
659
- function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst4) {
660
- const sites = findHandlerCalls(code, fnName, parseAst4);
752
+ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst5) {
753
+ const sites = findHandlerCalls(code, fnName, parseAst5);
661
754
  const inlineSites = sites.filter((site) => site.exportInfo === null);
662
755
  if (inlineSites.length === 0) return false;
663
- const imports = extractImportDeclarations(code, parseAst4);
664
- const staticNames = getImportedLocalNames(code, "Static", parseAst4);
665
- const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst4);
756
+ const imports = extractImportDeclarations(code, parseAst5);
757
+ const staticNames = getImportedLocalNames(code, "Static", parseAst5);
758
+ const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst5);
666
759
  const handlerNames = /* @__PURE__ */ new Set([...staticNames, ...prerenderNames]);
667
760
  const declarations = extractModuleLevelDeclarations(
668
761
  code,
669
- parseAst4,
762
+ parseAst5,
670
763
  handlerNames
671
764
  );
672
- const lineCounts = /* @__PURE__ */ new Map();
673
765
  const importStatements = [];
674
- for (const site of inlineSites) {
675
- const lineCount = lineCounts.get(site.lineNumber) ?? 0;
676
- lineCounts.set(site.lineNumber, lineCount + 1);
677
- const hash = hashInlineId(filePath, site.lineNumber, lineCount);
766
+ for (const [siteIndex, site] of inlineSites.entries()) {
767
+ const hash = hashInlineId(filePath, fnName, siteIndex);
678
768
  const exportName = `__sh_${hash}`;
679
- const virtualId = `\0${virtualPrefix}${filePath}:${site.lineNumber}${lineCount > 0 ? `:${lineCount}` : ""}`;
769
+ const idSuffix = `${filePath}:${fnName}:${siteIndex}`;
770
+ const virtualId = `\0${virtualPrefix}${idSuffix}`;
680
771
  const handlerCode = code.slice(site.callStart, site.callEnd);
681
772
  virtualRegistry.set(virtualId, {
682
773
  originalModuleId: moduleId,
@@ -686,12 +777,12 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
686
777
  exportName
687
778
  });
688
779
  s.overwrite(site.callStart, site.callEnd, exportName);
689
- const importId = `${virtualPrefix}${filePath}:${site.lineNumber}${lineCount > 0 ? `:${lineCount}` : ""}`;
780
+ const importId = `${virtualPrefix}${idSuffix}`;
690
781
  importStatements.push(`import { ${exportName} } from "${importId}";`);
691
782
  }
692
783
  if (importStatements.length > 0) {
693
784
  const importBlock = importStatements.join("\n") + "\n";
694
- const insertionPos = findImportInsertionPos(code, parseAst4);
785
+ const insertionPos = findImportInsertionPos(code, parseAst5);
695
786
  if (insertionPos === 0) {
696
787
  s.prepend(importBlock);
697
788
  } else {
@@ -718,6 +809,138 @@ var STRICT_CREATE_CONFIGS = [
718
809
 
719
810
  // src/vite/plugins/expose-ids/export-analysis.ts
720
811
  import { parseAst } from "vite";
812
+
813
+ // src/build/route-types/source-scan.ts
814
+ function isLineTerminator(ch) {
815
+ const c = ch.charCodeAt(0);
816
+ return c === 10 || c === 13 || c === 8232 || c === 8233;
817
+ }
818
+ var REGEX_PRECEDING_KEYWORDS = /* @__PURE__ */ new Set([
819
+ "return",
820
+ "typeof",
821
+ "instanceof",
822
+ "in",
823
+ "of",
824
+ "new",
825
+ "delete",
826
+ "void",
827
+ "do",
828
+ "else",
829
+ "yield",
830
+ "await",
831
+ "case",
832
+ "throw"
833
+ ]);
834
+ function isRegexPositionAt(code, slashPos, prevChar) {
835
+ if (prevChar === void 0) return true;
836
+ if (prevChar === ")" || prevChar === "]" || prevChar === "}") return false;
837
+ if (!/[\w$]/.test(prevChar)) return true;
838
+ let k = slashPos - 1;
839
+ while (k >= 0 && /\s/.test(code[k])) k--;
840
+ const wordEnd = k + 1;
841
+ while (k >= 0 && /[\w$]/.test(code[k])) k--;
842
+ return REGEX_PRECEDING_KEYWORDS.has(code.slice(k + 1, wordEnd));
843
+ }
844
+ function makeCodeClassifier(code) {
845
+ const n = code.length;
846
+ let i = 0;
847
+ let skipStart = -1;
848
+ let skipEnd = -1;
849
+ let lastSig;
850
+ return (q) => {
851
+ if (q >= skipStart && q < skipEnd) return false;
852
+ while (i < n && i <= q) {
853
+ const c = code[i];
854
+ const d = i + 1 < n ? code[i + 1] : "";
855
+ let end = -1;
856
+ let transparent = false;
857
+ if (c === "/" && d === "/") {
858
+ let j = i + 2;
859
+ while (j < n && !isLineTerminator(code[j])) j++;
860
+ end = j;
861
+ transparent = true;
862
+ } else if (c === "/" && d === "*") {
863
+ let j = i + 2;
864
+ while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++;
865
+ end = Math.min(n, j + 2);
866
+ transparent = true;
867
+ } else if (c === '"' || c === "'" || c === "`") {
868
+ let j = i + 1;
869
+ while (j < n) {
870
+ if (code[j] === "\\") {
871
+ j += 2;
872
+ continue;
873
+ }
874
+ if (code[j] === c) {
875
+ j++;
876
+ break;
877
+ }
878
+ j++;
879
+ }
880
+ end = j;
881
+ } else if (c === "/" && d !== "/" && d !== "*" && isRegexPositionAt(code, i, lastSig)) {
882
+ let j = i + 1;
883
+ let inClass = false;
884
+ let closed = false;
885
+ while (j < n && !isLineTerminator(code[j])) {
886
+ const r = code[j];
887
+ if (r === "\\") {
888
+ j += 2;
889
+ continue;
890
+ }
891
+ if (r === "[") inClass = true;
892
+ else if (r === "]") inClass = false;
893
+ else if (r === "/" && !inClass) {
894
+ j++;
895
+ closed = true;
896
+ break;
897
+ }
898
+ j++;
899
+ }
900
+ if (closed) {
901
+ while (j < n && /[a-z]/.test(code[j])) j++;
902
+ end = j;
903
+ }
904
+ }
905
+ if (end >= 0) {
906
+ if (q < end) {
907
+ skipStart = i;
908
+ skipEnd = end;
909
+ return false;
910
+ }
911
+ i = end;
912
+ if (!transparent) lastSig = "x";
913
+ } else {
914
+ if (!/\s/.test(c)) lastSig = c;
915
+ i++;
916
+ }
917
+ }
918
+ return true;
919
+ };
920
+ }
921
+ function firstCodeMatchIndex(code, pattern) {
922
+ const inCode = makeCodeClassifier(code);
923
+ pattern.lastIndex = 0;
924
+ let m;
925
+ while ((m = pattern.exec(code)) !== null) {
926
+ if (inCode(m.index)) return m.index;
927
+ if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
928
+ }
929
+ return -1;
930
+ }
931
+ function codeMatchIndices(code, pattern) {
932
+ const inCode = makeCodeClassifier(code);
933
+ const indices = [];
934
+ pattern.lastIndex = 0;
935
+ let m;
936
+ while ((m = pattern.exec(code)) !== null) {
937
+ if (inCode(m.index)) indices.push(m.index);
938
+ if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
939
+ }
940
+ return indices;
941
+ }
942
+
943
+ // src/vite/plugins/expose-ids/export-analysis.ts
721
944
  function isExportOnlyFile(code, bindings) {
722
945
  if (bindings.length === 0) return false;
723
946
  const knownLocals = /* @__PURE__ */ new Set();
@@ -746,12 +969,40 @@ function isExportOnlyFile(code, bindings) {
746
969
  }
747
970
  return true;
748
971
  }
749
- function countCreateCallsForNames(code, fnNames) {
750
- const pattern = new RegExp(
751
- `\\b(?:${fnNames.map(escapeRegExp).join("|")})\\s*(?:<[^>]*>\\s*)?\\(`,
752
- "g"
972
+ function createCallPattern(fnNames) {
973
+ return new RegExp(`\\b(?:${fnNames.map(escapeRegExp).join("|")})\\b`, "g");
974
+ }
975
+ function createCallStartIndices(code, fnNames) {
976
+ return codeMatchIndices(code, createCallPattern(fnNames)).filter(
977
+ (index) => findCallParenAfterGenerics(
978
+ code,
979
+ index + matchedNameLength(code, index)
980
+ ) !== -1
753
981
  );
754
- return (code.match(pattern) || []).length;
982
+ }
983
+ function matchedNameLength(code, index) {
984
+ let i = index;
985
+ while (i < code.length && /[A-Za-z0-9_$]/.test(code[i])) i++;
986
+ return i - index;
987
+ }
988
+ function countCreateCallsForNames(code, fnNames) {
989
+ return createCallStartIndices(code, fnNames).length;
990
+ }
991
+ function offsetToLineColumn(code, index) {
992
+ let line = 1;
993
+ let lineStart = 0;
994
+ const end = Math.min(index, code.length);
995
+ for (let i = 0; i < end; i++) {
996
+ if (code[i] === "\n") {
997
+ line++;
998
+ lineStart = i + 1;
999
+ }
1000
+ }
1001
+ return { line, column: index - lineStart + 1 };
1002
+ }
1003
+ function findUnsupportedCreateCallSites(code, fnNames, supportedBindings) {
1004
+ const supported = new Set(supportedBindings.map((b) => b.callExprStart));
1005
+ return createCallStartIndices(code, fnNames).filter((index) => !supported.has(index)).map((index) => offsetToLineColumn(code, index));
755
1006
  }
756
1007
  function getImportedFnNames(code, importedName) {
757
1008
  const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']@rangojs\/router(?:\/[^"']*)?["']/g;
@@ -782,6 +1033,17 @@ function getCalledIdentifierFromCall(callExpr) {
782
1033
  }
783
1034
  return null;
784
1035
  }
1036
+ function unwrapSignatureWrappedCall(init, fnNameSet) {
1037
+ if (init?.type !== "CallExpression") return init;
1038
+ const directId = getCalledIdentifierFromCall(init);
1039
+ if (directId && fnNameSet.has(directId)) return init;
1040
+ const firstArg = init.arguments?.[0];
1041
+ if (firstArg?.type === "CallExpression") {
1042
+ const innerId = getCalledIdentifierFromCall(firstArg);
1043
+ if (innerId && fnNameSet.has(innerId)) return firstArg;
1044
+ }
1045
+ return init;
1046
+ }
785
1047
  function collectCreateExportBindingsFallback(code, fnNames) {
786
1048
  const alternation = fnNames.map(escapeRegExp).join("|");
787
1049
  const exportConstPattern = new RegExp(
@@ -841,7 +1103,7 @@ function collectCreateExportBindingsFallback(code, fnNames) {
841
1103
  function collectCreateExportBindings(code, fnNames, program) {
842
1104
  if (!program) {
843
1105
  try {
844
- program = parseAst(code, { jsx: true });
1106
+ program = parseAst(code, { lang: "tsx" });
845
1107
  } catch {
846
1108
  return collectCreateExportBindingsFallback(code, fnNames);
847
1109
  }
@@ -854,16 +1116,16 @@ function collectCreateExportBindings(code, fnNames, program) {
854
1116
  return;
855
1117
  }
856
1118
  for (const decl of varDecl.declarations ?? []) {
857
- const calledIdentifier = getCalledIdentifierFromCall(decl?.init);
858
- if (decl?.id?.type !== "Identifier" || decl?.init?.type !== "CallExpression" || !calledIdentifier || !fnNameSet.has(calledIdentifier)) {
1119
+ const callExpr = unwrapSignatureWrappedCall(decl?.init, fnNameSet);
1120
+ const calledIdentifier = getCalledIdentifierFromCall(callExpr);
1121
+ if (decl?.id?.type !== "Identifier" || callExpr?.type !== "CallExpression" || !calledIdentifier || !fnNameSet.has(calledIdentifier)) {
859
1122
  continue;
860
1123
  }
861
1124
  const localName = decl.id.name;
862
1125
  const exportNames = exportMap.get(localName) ?? [];
863
1126
  if (exportNames.length === 0) continue;
864
- const callStart = decl.init.start;
865
- const callEnd = decl.init.end;
866
- const calleeEnd = decl.init.callee.end;
1127
+ const callEnd = callExpr.end;
1128
+ const calleeEnd = callExpr.callee.end;
867
1129
  let openParenPos = -1;
868
1130
  for (let i = calleeEnd; i < callEnd; i++) {
869
1131
  if (code[i] === "(") {
@@ -877,10 +1139,10 @@ function collectCreateExportBindings(code, fnNames, program) {
877
1139
  bindings.push({
878
1140
  localName,
879
1141
  exportNames,
880
- callExprStart: decl.init.start,
1142
+ callExprStart: callExpr.start,
881
1143
  callOpenParenPos: openParenPos,
882
1144
  callCloseParenPos: closeParenPos,
883
- argCount: decl.init.arguments?.length ?? 0,
1145
+ argCount: callExpr.arguments?.length ?? 0,
884
1146
  statementEnd
885
1147
  });
886
1148
  }
@@ -899,9 +1161,20 @@ function collectCreateExportBindings(code, fnNames, program) {
899
1161
  }
900
1162
  return bindings;
901
1163
  }
902
- function buildUnsupportedShapeWarning(filePath, fnName) {
903
- return [
904
- `[rsc-router] Unsupported ${fnName} shape in "${filePath}".`,
1164
+ function buildUnsupportedShapeWarning(filePath, fnName, sites = []) {
1165
+ const lines = [`[rango] Unsupported ${fnName} shape in "${filePath}".`];
1166
+ if (sites.length === 1) {
1167
+ const s = sites[0];
1168
+ lines.push(
1169
+ `The ${fnName}(...) call at ${filePath}:${s.line}:${s.column} has no stable $$id injected \u2014 it is not in a supported shape.`
1170
+ );
1171
+ } else if (sites.length > 1) {
1172
+ lines.push(
1173
+ `These ${fnName}(...) calls have no stable $$id injected \u2014 they are not in a supported shape:`
1174
+ );
1175
+ for (const s of sites) lines.push(` - ${filePath}:${s.line}:${s.column}`);
1176
+ }
1177
+ lines.push(
905
1178
  `Supported shapes are:`,
906
1179
  ` - export const X = ${fnName}(...)`,
907
1180
  ` - const X = ${fnName}(...); export { X }`,
@@ -909,7 +1182,8 @@ function buildUnsupportedShapeWarning(filePath, fnName) {
909
1182
  `Potentially unsupported forms include:`,
910
1183
  ` - export let/var X = ${fnName}(...)`,
911
1184
  ` - inline ${fnName}(...) calls`
912
- ].join("\n");
1185
+ );
1186
+ return lines.join("\n");
913
1187
  }
914
1188
 
915
1189
  // src/vite/plugins/expose-ids/loader-transform.ts
@@ -922,11 +1196,13 @@ function generateClientLoaderStubs(bindings, code, filePath, isBuild) {
922
1196
  if (!isExportOnlyFile(code, bindings)) return null;
923
1197
  const lines = [];
924
1198
  for (const binding of bindings) {
925
- for (const name of binding.exportNames) {
926
- const loaderId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
927
- lines.push(
928
- `export const ${name} = { __brand: "loader", $$id: "${loaderId}" };`
929
- );
1199
+ const primaryName = binding.exportNames[0];
1200
+ const loaderId = makeStubId(filePath, primaryName, isBuild);
1201
+ lines.push(
1202
+ `export const ${primaryName} = { __brand: "loader", $$id: "${loaderId}" };`
1203
+ );
1204
+ for (const alias of binding.exportNames.slice(1)) {
1205
+ lines.push(`export const ${alias} = ${primaryName};`);
930
1206
  }
931
1207
  }
932
1208
  return { code: lines.join("\n") + "\n" };
@@ -935,7 +1211,7 @@ function transformLoaders(bindings, s, filePath, isBuild) {
935
1211
  let hasChanges = false;
936
1212
  for (const binding of bindings) {
937
1213
  const exportName = binding.exportNames[0];
938
- const loaderId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1214
+ const loaderId = makeStubId(filePath, exportName, isBuild);
939
1215
  const paramInjection = binding.argCount === 1 ? `, undefined, "${loaderId}"` : `, "${loaderId}"`;
940
1216
  s.appendLeft(binding.callCloseParenPos, paramInjection);
941
1217
  const propInjection = `
@@ -947,23 +1223,13 @@ ${binding.localName}.$$id = "${loaderId}";`;
947
1223
  }
948
1224
 
949
1225
  // src/vite/plugins/expose-ids/handler-transform.ts
950
- import MagicString2 from "magic-string";
951
- function analyzeCreateHandleArgs(code, startPos, endPos) {
952
- const content = code.slice(startPos, endPos).trim();
953
- return { hasArgs: content.length > 0 };
954
- }
955
- function transformHandles(bindings, s, code, filePath, isBuild) {
1226
+ function transformHandles(bindings, s, filePath, isBuild) {
956
1227
  let hasChanges = false;
957
1228
  for (const binding of bindings) {
958
1229
  const exportName = binding.exportNames[0];
959
- const args = analyzeCreateHandleArgs(
960
- code,
961
- binding.callOpenParenPos + 1,
962
- binding.callCloseParenPos
963
- );
964
- const handleId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1230
+ const handleId = makeStubId(filePath, exportName, isBuild);
965
1231
  let paramInjection;
966
- if (!args.hasArgs) {
1232
+ if (binding.argCount === 0) {
967
1233
  paramInjection = `undefined, "${handleId}"`;
968
1234
  } else {
969
1235
  paramInjection = `, "${handleId}"`;
@@ -980,7 +1246,7 @@ function transformLocationState(bindings, s, filePath, isBuild) {
980
1246
  let hasChanges = false;
981
1247
  for (const binding of bindings) {
982
1248
  const exportName = binding.exportNames[0];
983
- const stateKey = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1249
+ const stateKey = makeStubId(filePath, exportName, isBuild);
984
1250
  const propInjection = `
985
1251
  ${binding.localName}.__rsc_ls_key = "__rsc_ls_${stateKey}";`;
986
1252
  s.appendRight(binding.statementEnd, propInjection);
@@ -992,7 +1258,7 @@ function generateWholeFileStubs(cfg, bindings, code, filePath, isBuild) {
992
1258
  if (!isExportOnlyFile(code, bindings)) return null;
993
1259
  const exportNames = bindings.flatMap((b) => b.exportNames);
994
1260
  const stubs = exportNames.map((name) => {
995
- const handlerId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
1261
+ const handlerId = makeStubId(filePath, name, isBuild);
996
1262
  return `export const ${name} = { __brand: "${cfg.brand}", $$id: "${handlerId}" };`;
997
1263
  });
998
1264
  return { code: stubs.join("\n") + "\n", map: null };
@@ -1001,7 +1267,7 @@ function stubHandlerExprs(cfg, bindings, s, filePath, isBuild) {
1001
1267
  let hasChanges = false;
1002
1268
  for (const binding of bindings) {
1003
1269
  const exportName = binding.exportNames[0];
1004
- const handlerId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1270
+ const handlerId = makeStubId(filePath, exportName, isBuild);
1005
1271
  s.overwrite(
1006
1272
  binding.callExprStart,
1007
1273
  binding.callCloseParenPos + 1,
@@ -1015,7 +1281,7 @@ function transformHandlerIds(cfg, bindings, s, filePath, isBuild) {
1015
1281
  let hasChanges = false;
1016
1282
  for (const binding of bindings) {
1017
1283
  const exportName = binding.exportNames[0];
1018
- const handlerId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1284
+ const handlerId = makeStubId(filePath, exportName, isBuild);
1019
1285
  let paramInjection;
1020
1286
  if (binding.argCount === 0) {
1021
1287
  paramInjection = `undefined, "${handlerId}"`;
@@ -1034,40 +1300,72 @@ ${binding.localName}.$$id = "${handlerId}";`;
1034
1300
  }
1035
1301
 
1036
1302
  // src/vite/plugins/expose-ids/router-transform.ts
1037
- import MagicString3 from "magic-string";
1303
+ import MagicString2 from "magic-string";
1038
1304
  import path3 from "node:path";
1039
1305
  import { createHash } from "node:crypto";
1040
- var debug2 = createRangoDebugger("rango:transform");
1041
- function transformRouter(code, filePath, routerFnNames, absolutePath) {
1306
+ var debug2 = createRangoDebugger(NS.transform);
1307
+ function skipLeadingTrivia(code, start, end) {
1308
+ let i = start;
1309
+ while (i < end) {
1310
+ const skipped = skipStringOrComment(code, i);
1311
+ if (skipped > i) {
1312
+ i = skipped;
1313
+ continue;
1314
+ }
1315
+ if (/\s/.test(code[i])) {
1316
+ i++;
1317
+ continue;
1318
+ }
1319
+ break;
1320
+ }
1321
+ return i;
1322
+ }
1323
+ function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
1042
1324
  const pat = new RegExp(
1043
- `\\b(?:${routerFnNames.map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\s*(?:<[^>]*>)?\\s*\\(`,
1325
+ `\\b(?:${routerFnNames.map(escapeRegExp).join("|")})\\b`,
1044
1326
  "g"
1045
1327
  );
1046
1328
  let match;
1047
- const s = new MagicString3(code);
1329
+ const s = new MagicString2(code);
1048
1330
  let changed = false;
1049
- const basename3 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
1050
- const routeNamesImport = `./${basename3}.named-routes.gen.js`;
1331
+ const unsupportedSites = [];
1332
+ const basename2 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
1333
+ const routeNamesImport = `./${basename2}.named-routes.gen.js`;
1051
1334
  const routeNamesVar = `__rsc_rn`;
1335
+ const codeOffsets = new Set(codeMatchIndices(code, pat));
1336
+ pat.lastIndex = 0;
1052
1337
  while ((match = pat.exec(code)) !== null) {
1338
+ if (!codeOffsets.has(match.index)) continue;
1053
1339
  const callStart = match.index;
1054
- const parenPos = match.index + match[0].length - 1;
1340
+ const calleeEnd = match.index + match[0].length;
1341
+ const parenPos = findCallParenAfterGenerics(code, calleeEnd);
1342
+ if (parenPos === -1) continue;
1055
1343
  const closeParen = findMatchingParen(code, parenPos + 1);
1056
1344
  const callArgs = code.slice(parenPos + 1, closeParen);
1057
- if (callArgs.includes("$$id")) continue;
1345
+ if (callArgs.includes(`$$routeNames: ${routeNamesVar}`)) continue;
1346
+ const sourceFilePath = absolutePath ?? filePath;
1058
1347
  const lineNumber = code.slice(0, callStart).split("\n").length;
1059
1348
  const hash = createHash("sha256").update(`${filePath}:${lineNumber}`).digest("hex").slice(0, 8);
1060
- changed = true;
1061
- const sourceFilePath = absolutePath ?? filePath;
1062
1349
  const injected = ` $$id: "${hash}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
1063
- const afterParen = callArgs.trimStart();
1064
- if (afterParen.startsWith("{")) {
1065
- const bracePos = code.indexOf("{", parenPos + 1);
1066
- s.appendRight(bracePos + 1, injected);
1067
- } else if (afterParen.startsWith(")")) {
1350
+ const argsContentStart = skipLeadingTrivia(code, parenPos + 1, closeParen);
1351
+ const firstArgChar = code[argsContentStart];
1352
+ if (firstArgChar === "{") {
1353
+ changed = true;
1354
+ s.appendRight(argsContentStart + 1, injected);
1355
+ } else if (argsContentStart >= closeParen - 1) {
1356
+ changed = true;
1068
1357
  s.appendRight(parenPos + 1, `{${injected} }`);
1358
+ } else {
1359
+ const lastNl = code.lastIndexOf("\n", callStart - 1);
1360
+ const column = callStart - (lastNl + 1) + 1;
1361
+ unsupportedSites.push({ line: lineNumber, column });
1069
1362
  }
1070
1363
  }
1364
+ if (unsupportedSites.length > 0 && warn) {
1365
+ warn(
1366
+ buildUnsupportedShapeWarning(filePath, "createRouter", unsupportedSites)
1367
+ );
1368
+ }
1071
1369
  if (!changed) return null;
1072
1370
  s.prepend(
1073
1371
  `import { NamedRoutes as ${routeNamesVar} } from "${routeNamesImport}";
@@ -1101,11 +1399,13 @@ function exposeRouterId() {
1101
1399
  try {
1102
1400
  const filePath = normalizePath(path3.relative(projectRoot, id));
1103
1401
  const routerFnNames = getImportedFnNames(code, "createRouter");
1402
+ const warn = typeof this.warn === "function" ? (message) => this.warn(message) : void 0;
1104
1403
  return transformRouter(
1105
1404
  code,
1106
1405
  filePath,
1107
1406
  routerFnNames,
1108
- normalizePath(id)
1407
+ normalizePath(id),
1408
+ warn
1109
1409
  );
1110
1410
  } finally {
1111
1411
  counter?.record(id, performance.now() - start);
@@ -1115,7 +1415,7 @@ function exposeRouterId() {
1115
1415
  }
1116
1416
 
1117
1417
  // src/vite/plugins/expose-internal-ids.ts
1118
- var debug3 = createRangoDebugger("rango:transform");
1418
+ var debug3 = createRangoDebugger(NS.transform);
1119
1419
  var VIRTUAL_LOADER_MANIFEST = "virtual:rsc-router/loader-manifest";
1120
1420
  var RESOLVED_VIRTUAL_LOADER_MANIFEST = "\0" + VIRTUAL_LOADER_MANIFEST;
1121
1421
  var VIRTUAL_HANDLER_PREFIX = "virtual:handler-extract:";
@@ -1201,6 +1501,7 @@ ${lazyImports.join(",\n")}
1201
1501
  // --------------- Loader pre-scan (build mode) ---------------
1202
1502
  async buildStart() {
1203
1503
  if (!isBuild) return;
1504
+ if (this.environment && this.environment.name !== "rsc") return;
1204
1505
  const fs2 = await import("node:fs/promises");
1205
1506
  const SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage"]);
1206
1507
  async function scanDir(dir) {
@@ -1307,7 +1608,7 @@ ${lazyImports.join(",\n")}
1307
1608
  }
1308
1609
  if (_cachedAst !== void 0 || _astParseFailed) return _cachedAst;
1309
1610
  try {
1310
- _cachedAst = parseAst2(code, { jsx: true });
1611
+ _cachedAst = parseAst2(code, { lang: "tsx" });
1311
1612
  } catch {
1312
1613
  _astParseFailed = true;
1313
1614
  }
@@ -1330,13 +1631,16 @@ ${lazyImports.join(",\n")}
1330
1631
  const hasCode = cfg.fnName === "createLoader" ? hasLoaderCode : cfg.fnName === "createHandle" ? hasHandleCode : hasLocationStateCode;
1331
1632
  if (!hasCode) continue;
1332
1633
  const fnNames = getFnNames(cfg.fnName);
1333
- const totalCalls = countCreateCallsForNames(code, fnNames);
1334
- const supportedBindings = getBindings(code, fnNames).length;
1335
- if (totalCalls <= supportedBindings) continue;
1634
+ const sites = findUnsupportedCreateCallSites(
1635
+ code,
1636
+ fnNames,
1637
+ getBindings(code, fnNames)
1638
+ );
1639
+ if (sites.length === 0) continue;
1336
1640
  const warnKey = `${id}::${cfg.fnName}`;
1337
1641
  if (unsupportedShapeWarnings.has(warnKey)) continue;
1338
1642
  unsupportedShapeWarnings.add(warnKey);
1339
- this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName));
1643
+ this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName, sites));
1340
1644
  }
1341
1645
  if (hasLoaderCode && isRscEnv) {
1342
1646
  const fnNames = getFnNames("createLoader");
@@ -1373,15 +1677,6 @@ ${lazyImports.join(",\n")}
1373
1677
  );
1374
1678
  if (wholeFile) return wholeFile;
1375
1679
  }
1376
- if (hasPrerenderHandlerCode && isRscEnv && isBuild) {
1377
- const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
1378
- const exportNames = getBindings(code, fnNames).map(
1379
- (b) => b.exportNames[0]
1380
- );
1381
- if (exportNames.length > 0) {
1382
- prerenderHandlerModules.set(id, exportNames);
1383
- }
1384
- }
1385
1680
  let changed = false;
1386
1681
  const handlerConfigs = [
1387
1682
  hasStaticHandlerCode && STATIC_CONFIG,
@@ -1394,7 +1689,7 @@ ${lazyImports.join(",\n")}
1394
1689
  const totalCalls = countCreateCallsForNames(code, fnNames);
1395
1690
  const supportedBindings = getBindings(code, fnNames).length;
1396
1691
  if (totalCalls > supportedBindings) {
1397
- const iterS = new MagicString4(code);
1692
+ const iterS = new MagicString3(code);
1398
1693
  const result = transformInlineHandlers(
1399
1694
  cfg.fnName,
1400
1695
  VIRTUAL_HANDLER_PREFIX,
@@ -1559,16 +1854,24 @@ ${lazyImports.join(",\n")}
1559
1854
  return { code: lines.join("\n") + "\n", map: null };
1560
1855
  }
1561
1856
  }
1562
- if (hasStaticHandlerCode && isRscEnv && isBuild) {
1563
- const fnNames = getFnNames(STATIC_CONFIG.fnName);
1564
- const exportNames = getBindings(code, fnNames).map(
1565
- (b) => b.exportNames[0]
1566
- );
1567
- if (exportNames.length > 0) {
1568
- staticHandlerModules.set(id, exportNames);
1857
+ if (isRscEnv && isBuild) {
1858
+ const trackTypes = [
1859
+ [
1860
+ hasPrerenderHandlerCode,
1861
+ PRERENDER_CONFIG,
1862
+ prerenderHandlerModules
1863
+ ],
1864
+ [hasStaticHandlerCode, STATIC_CONFIG, staticHandlerModules]
1865
+ ];
1866
+ for (const [has2, cfg, trackMap] of trackTypes) {
1867
+ if (!has2) continue;
1868
+ const exportNames = getBindings(code, getFnNames(cfg.fnName)).map(
1869
+ (b) => b.exportNames[0]
1870
+ );
1871
+ if (exportNames.length > 0) trackMap.set(id, exportNames);
1569
1872
  }
1570
1873
  }
1571
- const s = new MagicString4(code);
1874
+ const s = new MagicString3(code);
1572
1875
  if (hasLoaderCode) {
1573
1876
  const fnNames = getFnNames("createLoader");
1574
1877
  changed = transformLoaders(
@@ -1583,7 +1886,6 @@ ${lazyImports.join(",\n")}
1583
1886
  changed = transformHandles(
1584
1887
  getBindings(code, fnNames),
1585
1888
  s,
1586
- code,
1587
1889
  filePath,
1588
1890
  isBuild
1589
1891
  ) || changed;
@@ -1597,41 +1899,13 @@ ${lazyImports.join(",\n")}
1597
1899
  isBuild
1598
1900
  ) || changed;
1599
1901
  }
1600
- if (hasPrerenderHandlerCode) {
1601
- const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
1602
- const bindings = getBindings(code, fnNames);
1603
- if (isRscEnv) {
1604
- changed = transformHandlerIds(
1605
- PRERENDER_CONFIG,
1606
- bindings,
1607
- s,
1608
- filePath,
1609
- isBuild
1610
- ) || changed;
1611
- } else {
1612
- changed = stubHandlerExprs(
1613
- PRERENDER_CONFIG,
1614
- bindings,
1615
- s,
1616
- filePath,
1617
- isBuild
1618
- ) || changed;
1619
- }
1620
- }
1621
- if (hasStaticHandlerCode) {
1622
- const fnNames = getFnNames(STATIC_CONFIG.fnName);
1623
- const bindings = getBindings(code, fnNames);
1624
- if (isRscEnv) {
1625
- changed = transformHandlerIds(
1626
- STATIC_CONFIG,
1627
- bindings,
1628
- s,
1629
- filePath,
1630
- isBuild
1631
- ) || changed;
1632
- } else {
1633
- changed = stubHandlerExprs(STATIC_CONFIG, bindings, s, filePath, isBuild) || changed;
1634
- }
1902
+ const finalHandlerConfigs = [
1903
+ hasPrerenderHandlerCode && PRERENDER_CONFIG,
1904
+ hasStaticHandlerCode && STATIC_CONFIG
1905
+ ].filter((c) => !!c);
1906
+ for (const cfg of finalHandlerConfigs) {
1907
+ const bindings = getBindings(code, getFnNames(cfg.fnName));
1908
+ changed = (isRscEnv ? transformHandlerIds(cfg, bindings, s, filePath, isBuild) : stubHandlerExprs(cfg, bindings, s, filePath, isBuild)) || changed;
1635
1909
  }
1636
1910
  if (!changed) return;
1637
1911
  return {
@@ -1647,10 +1921,11 @@ ${lazyImports.join(",\n")}
1647
1921
 
1648
1922
  // src/vite/plugins/use-cache-transform.ts
1649
1923
  import path5 from "node:path";
1650
- import MagicString5 from "magic-string";
1651
- var debug4 = createRangoDebugger("rango:transform");
1924
+ import MagicString4 from "magic-string";
1925
+ var debug4 = createRangoDebugger(NS.transform);
1652
1926
  var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
1653
1927
  var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
1928
+ var USE_CACHE_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
1654
1929
  function useCacheTransform() {
1655
1930
  let projectRoot = "";
1656
1931
  let isBuild = false;
@@ -1687,8 +1962,8 @@ function useCacheTransform() {
1687
1962
  } = rscTransforms;
1688
1963
  let ast;
1689
1964
  try {
1690
- const { parseAst: parseAst4 } = await import("vite");
1691
- ast = parseAst4(code);
1965
+ const { parseAst: parseAst5 } = await import("vite");
1966
+ ast = parseAst5(code, { lang: "tsx" });
1692
1967
  } catch {
1693
1968
  return;
1694
1969
  }
@@ -1722,7 +1997,7 @@ function useCacheTransform() {
1722
1997
  };
1723
1998
  }
1724
1999
  function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport) {
1725
- const nonFunctionExports = [];
2000
+ const unconfirmedExports = [];
1726
2001
  const { exportNames, output } = transformWrapExport(code, ast, {
1727
2002
  runtime: (value, name) => {
1728
2003
  const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
@@ -1731,20 +2006,21 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
1731
2006
  rejectNonAsyncFunction: false,
1732
2007
  filter: (name, meta) => {
1733
2008
  if (name === "default" && isLayoutOrTemplate) return false;
1734
- if (meta.isFunction === false) {
1735
- nonFunctionExports.push(name);
2009
+ if (meta.isFunction !== true) {
2010
+ unconfirmedExports.push(name);
1736
2011
  return false;
1737
2012
  }
1738
2013
  return true;
1739
2014
  }
1740
2015
  });
1741
- if (nonFunctionExports.length > 0) {
2016
+ if (unconfirmedExports.length > 0) {
2017
+ const plural = unconfirmedExports.length > 1;
1742
2018
  throw new Error(
1743
- `[rango:use-cache] File-level "use cache" in ${sourceId} cannot wrap non-function export${nonFunctionExports.length > 1 ? "s" : ""}: ${nonFunctionExports.map((n) => `"${n}"`).join(", ")}. Only function exports can be cached. Either remove "use cache" from the file level and add it inside individual functions, or move the non-function exports to a separate module.`
2019
+ `[rango:use-cache] File-level "use cache" in ${sourceId} only wraps exports that are statically-confirmed functions. ${plural ? "These exports are" : "This export is"} not: ${unconfirmedExports.map((n) => `"${n}"`).join(", ")}. Declare them directly (export async function foo() {} or export const foo = async () => {}). A factory or otherwise statically-indeterminate initializer (export const foo = makeCached(fn)) is rejected even if it returns a function at runtime -- rewrite it as a direct async function, or move non-function exports to a separate module.`
1744
2020
  );
1745
2021
  }
1746
2022
  if (exportNames.length === 0) {
1747
- const s = new MagicString5(code);
2023
+ const s = new MagicString4(code);
1748
2024
  const directive2 = findFileLevelDirective(ast);
1749
2025
  if (directive2) {
1750
2026
  s.overwrite(
@@ -1779,7 +2055,7 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
1779
2055
  function transformFunctionLevelUseCache(code, ast, filePath, sourceId, isBuild, transformHoistInlineDirective) {
1780
2056
  try {
1781
2057
  const { output, names } = transformHoistInlineDirective(code, ast, {
1782
- directive: /^use cache(:\s*[\w-]+)?$/,
2058
+ directive: USE_CACHE_DIRECTIVE_RE,
1783
2059
  runtime: (value, name, meta) => {
1784
2060
  const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
1785
2061
  const profileMatch = meta.directiveMatch[1];
@@ -1809,14 +2085,13 @@ function findFileLevelDirective(ast) {
1809
2085
  }
1810
2086
  return null;
1811
2087
  }
1812
- var VALID_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
1813
2088
  var NEAR_MISS_RE = /^use cache:\s*.+$/;
1814
2089
  function warnOnNearMissDirectives(ast, fileId, warn) {
1815
2090
  const visit = (node) => {
1816
2091
  if (!node || typeof node !== "object") return;
1817
2092
  if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
1818
2093
  const value = node.expression.value;
1819
- if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !VALID_DIRECTIVE_RE.test(value)) {
2094
+ if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !USE_CACHE_DIRECTIVE_RE.test(value)) {
1820
2095
  const profilePart = value.slice("use cache:".length).trim();
1821
2096
  warn(
1822
2097
  `[rango:use-cache] "${value}" in ${fileId} has an invalid profile name "${profilePart}". Profile names must match [a-zA-Z0-9_-]+. This directive will be ignored.`
@@ -1840,7 +2115,7 @@ function warnOnNearMissDirectives(ast, fileId, warn) {
1840
2115
  }
1841
2116
 
1842
2117
  // src/vite/plugins/client-ref-dedup.ts
1843
- var debug5 = createRangoDebugger("rango:transform");
2118
+ var debug5 = createRangoDebugger(NS.transform);
1844
2119
  var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
1845
2120
  function extractPackageName(absolutePath) {
1846
2121
  const marker = "/node_modules/";
@@ -1857,7 +2132,6 @@ function extractPackageName(absolutePath) {
1857
2132
  }
1858
2133
  function clientRefDedup() {
1859
2134
  let clientExclude = [];
1860
- let hits = 0;
1861
2135
  const dedupedPackages = /* @__PURE__ */ new Set();
1862
2136
  return {
1863
2137
  name: "@rangojs/router:client-ref-dedup",
@@ -1868,10 +2142,9 @@ function clientRefDedup() {
1868
2142
  clientExclude = clientEnv?.optimizeDeps?.exclude ?? config.optimizeDeps?.exclude ?? [];
1869
2143
  },
1870
2144
  buildEnd() {
1871
- if (debug5 && hits > 0) {
2145
+ if (debug5 && dedupedPackages.size > 0) {
1872
2146
  debug5(
1873
- "client-ref-dedup: %d redirects across %d packages (%s)",
1874
- hits,
2147
+ "client-ref-dedup: redirected %d package(s) (%s)",
1875
2148
  dedupedPackages.size,
1876
2149
  [...dedupedPackages].join(",")
1877
2150
  );
@@ -1881,14 +2154,10 @@ function clientRefDedup() {
1881
2154
  if (this.environment?.name !== "client") return;
1882
2155
  if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
1883
2156
  if (!source.includes("/node_modules/")) return;
1884
- if (!importer) return;
1885
2157
  const packageName = extractPackageName(source);
1886
2158
  if (!packageName) return;
1887
2159
  if (clientExclude.includes(packageName)) return;
1888
- if (debug5) {
1889
- hits++;
1890
- dedupedPackages.add(packageName);
1891
- }
2160
+ if (debug5) dedupedPackages.add(packageName);
1892
2161
  return `\0rango:dedup/${packageName}`;
1893
2162
  },
1894
2163
  load(id) {
@@ -1915,7 +2184,7 @@ import {
1915
2184
  import { createElement, StrictMode } from "react";
1916
2185
  import { hydrateRoot } from "react-dom/client";
1917
2186
  import { rscStream } from "@rangojs/router/internal/deps/html-stream-client";
1918
- import { initBrowserApp, RSCRouter } from "@rangojs/router/browser";
2187
+ import { initBrowserApp, Rango } from "@rangojs/router/browser";
1919
2188
 
1920
2189
  async function initializeApp() {
1921
2190
  const deps = {
@@ -1926,11 +2195,16 @@ async function initializeApp() {
1926
2195
  createTemporaryReferenceSet,
1927
2196
  };
1928
2197
 
1929
- await initBrowserApp({ rscStream, deps });
2198
+ // initBrowserApp resolves the initial payload and returns the browser app
2199
+ // context, including strictMode (default true) from createRouter. StrictMode
2200
+ // is the default; createRouter({ strictMode: false }) ships the opt-out in the
2201
+ // payload metadata. StrictMode emits no DOM, so toggling never changes markup.
2202
+ const { strictMode } = await initBrowserApp({ rscStream, deps });
1930
2203
 
2204
+ const app = createElement(Rango);
1931
2205
  hydrateRoot(
1932
2206
  document,
1933
- createElement(StrictMode, null, createElement(RSCRouter))
2207
+ strictMode === false ? app : createElement(StrictMode, null, app)
1934
2208
  );
1935
2209
  }
1936
2210
 
@@ -1950,7 +2224,14 @@ export const renderHTML = createSSRHandler({
1950
2224
  import.meta.viteRsc.loadBootstrapScriptContent("index"),
1951
2225
  });
1952
2226
  `.trim();
2227
+ var RSC_ENTRY_BOOTSTRAP_IMPORTS = [
2228
+ "virtual:rsc-router/routes-manifest",
2229
+ "virtual:rsc-router/loader-manifest"
2230
+ ];
1953
2231
  function getVirtualEntryRSC(routerPath) {
2232
+ const bootstrapImports = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
2233
+ (id) => `import "${id}";`
2234
+ ).join("\n");
1954
2235
  return `
1955
2236
  import {
1956
2237
  renderToReadableStream,
@@ -1964,15 +2245,9 @@ import { router } from "${routerPath}";
1964
2245
  import { createRSCHandler } from "@rangojs/router/internal/rsc-handler";
1965
2246
  import { VERSION } from "@rangojs/router:version";
1966
2247
 
1967
- // Import loader manifest to ensure all fetchable loaders are registered at startup
1968
- // This is critical for serverless/multi-process deployments where the loader module
1969
- // might not be imported before a GET request arrives
1970
- import "virtual:rsc-router/loader-manifest";
1971
-
1972
- // Import pre-generated route manifest so href() works immediately on cold start.
1973
- // In build mode, this contains the full route map generated at build time.
1974
- // In dev mode, this is a no-op (manifest is populated in-memory by the discovery plugin).
1975
- import "virtual:rsc-router/routes-manifest";
2248
+ // Startup bootstrap imports (routes + loader manifests). See
2249
+ // RSC_ENTRY_BOOTSTRAP_IMPORTS \u2014 the same list the custom-entry injector uses.
2250
+ ${bootstrapImports}
1976
2251
 
1977
2252
  // Lazily create the handler on first request so that ESM live bindings
1978
2253
  // have resolved by the time we read \`router\`. During HMR the module may
@@ -1983,6 +2258,11 @@ export default function handler(request, env) {
1983
2258
  _handler = createRSCHandler({
1984
2259
  router,
1985
2260
  version: VERSION,
2261
+ // Forward the router's CSP nonce provider. createRSCHandler reads the
2262
+ // provider only from options.nonce; without this, createRouter({ nonce })
2263
+ // is silently dropped on the Node preset (the Cloudflare path wires it via
2264
+ // router.fetch). router.nonce is undefined when unconfigured, a safe no-op.
2265
+ nonce: router.nonce,
1986
2266
  deps: {
1987
2267
  renderToReadableStream,
1988
2268
  decodeReply,
@@ -2017,7 +2297,7 @@ import { resolve } from "node:path";
2017
2297
  // package.json
2018
2298
  var package_default = {
2019
2299
  name: "@rangojs/router",
2020
- version: "0.0.0-experimental.9eb4192e",
2300
+ version: "0.0.0-experimental.a014d2b7",
2021
2301
  description: "Django-inspired RSC router with composable URL patterns",
2022
2302
  keywords: [
2023
2303
  "react",
@@ -2127,6 +2407,11 @@ var package_default = {
2127
2407
  "react-server": "./src/cache/cache-runtime.ts",
2128
2408
  default: "./src/cache/cache-runtime.ts"
2129
2409
  },
2410
+ "./cloudflare": {
2411
+ types: "./src/cloudflare/index.ts",
2412
+ "react-server": "./src/cloudflare/index.ts",
2413
+ default: "./src/cloudflare/index.ts"
2414
+ },
2130
2415
  "./theme": {
2131
2416
  types: "./src/theme/index.ts",
2132
2417
  default: "./src/theme/index.ts"
@@ -2143,6 +2428,31 @@ var package_default = {
2143
2428
  "./host/testing": {
2144
2429
  types: "./src/host/testing.ts",
2145
2430
  default: "./src/host/testing.ts"
2431
+ },
2432
+ "./testing": {
2433
+ types: "./src/testing/index.ts",
2434
+ default: "./src/testing/index.ts"
2435
+ },
2436
+ "./testing/vitest": {
2437
+ types: "./src/testing/vitest.ts",
2438
+ default: "./dist/testing/vitest.js"
2439
+ },
2440
+ "./testing/dom": {
2441
+ types: "./src/testing/dom.entry.ts",
2442
+ default: "./src/testing/dom.entry.ts"
2443
+ },
2444
+ "./testing/e2e": {
2445
+ types: "./src/testing/e2e/index.ts",
2446
+ default: "./src/testing/e2e/index.ts"
2447
+ },
2448
+ "./testing/flight": {
2449
+ types: "./src/testing/flight.entry.ts",
2450
+ "react-server": "./src/testing/flight.entry.ts",
2451
+ default: "./src/testing/flight.entry.ts"
2452
+ },
2453
+ "./testing/flight-matchers": {
2454
+ types: "./src/testing/flight-matchers.ts",
2455
+ default: "./src/testing/flight-matchers.ts"
2146
2456
  }
2147
2457
  },
2148
2458
  publishConfig: {
@@ -2150,48 +2460,70 @@ var package_default = {
2150
2460
  tag: "experimental"
2151
2461
  },
2152
2462
  scripts: {
2153
- build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
2463
+ build: "pnpm exec esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm exec esbuild src/testing/vitest.ts --bundle --format=esm --outfile=dist/testing/vitest.js --platform=node --packages=external && pnpm exec esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
2154
2464
  prepublishOnly: "pnpm build",
2155
- typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit",
2465
+ typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
2156
2466
  test: "playwright test",
2157
2467
  "test:ui": "playwright test --ui",
2468
+ "test:hmr-local": "playwright test --project=dev-warmup --project=hmr-routes --project=hmr-basename --project=hmr-prerender --no-deps --workers=1",
2158
2469
  "test:unit": "vitest run",
2159
- "test:unit:watch": "vitest"
2470
+ "test:unit:watch": "vitest",
2471
+ "test:unit:rsc": "vitest run --config vitest.rsc.config.ts"
2160
2472
  },
2161
2473
  dependencies: {
2162
- "@vitejs/plugin-rsc": "^0.5.23",
2474
+ "@types/debug": "^4.1.12",
2475
+ "@vitejs/plugin-rsc": "^0.5.27",
2163
2476
  debug: "^4.4.1",
2164
2477
  "magic-string": "^0.30.17",
2165
- picomatch: "^4.0.3",
2166
- "rsc-html-stream": "^0.0.7"
2478
+ picomatch: "^4.0.4",
2479
+ "rsc-html-stream": "^0.0.7",
2480
+ tinyexec: "^0.3.2"
2167
2481
  },
2168
2482
  devDependencies: {
2169
2483
  "@playwright/test": "^1.49.1",
2170
- "@types/debug": "^4.1.12",
2484
+ "@shared/e2e": "workspace:*",
2485
+ "@testing-library/dom": "^10.4.1",
2486
+ "@testing-library/react": "^16.3.2",
2171
2487
  "@types/node": "^24.10.1",
2172
2488
  "@types/react": "catalog:",
2173
2489
  "@types/react-dom": "catalog:",
2174
- esbuild: "^0.27.0",
2490
+ esbuild: "^0.28.1",
2491
+ "happy-dom": "^20.10.1",
2175
2492
  jiti: "^2.6.1",
2176
2493
  react: "catalog:",
2177
2494
  "react-dom": "catalog:",
2178
- tinyexec: "^0.3.2",
2179
2495
  typescript: "^5.3.0",
2180
- vitest: "^4.0.0"
2496
+ vitest: "^4.1.9"
2181
2497
  },
2182
2498
  peerDependencies: {
2183
- "@cloudflare/vite-plugin": "^1.25.0",
2184
- "@vitejs/plugin-rsc": "^0.5.23",
2185
- react: "^18.0.0 || ^19.0.0",
2186
- vite: "^7.3.0"
2499
+ "@cloudflare/vite-plugin": "^1.42.1",
2500
+ "@playwright/test": "^1.49.1",
2501
+ "@testing-library/react": ">=16",
2502
+ "@vitejs/plugin-rsc": "^0.5.27",
2503
+ react: ">=19.2.6 <20",
2504
+ "react-dom": ">=19.2.6 <20",
2505
+ vite: "^8.0.16",
2506
+ vitest: ">=3"
2187
2507
  },
2188
2508
  peerDependenciesMeta: {
2189
2509
  "@cloudflare/vite-plugin": {
2190
2510
  optional: true
2191
2511
  },
2512
+ "@playwright/test": {
2513
+ optional: true
2514
+ },
2515
+ "@testing-library/react": {
2516
+ optional: true
2517
+ },
2192
2518
  vite: {
2193
2519
  optional: true
2520
+ },
2521
+ vitest: {
2522
+ optional: true
2194
2523
  }
2524
+ },
2525
+ engines: {
2526
+ node: "^20.19.0 || >=22.12.0"
2195
2527
  }
2196
2528
  };
2197
2529
 
@@ -2265,10 +2597,10 @@ function extractParamsFromPattern(pattern) {
2265
2597
  function formatRouteEntry(key, pattern, _params, search) {
2266
2598
  const hasSearch = search && Object.keys(search).length > 0;
2267
2599
  if (!hasSearch) {
2268
- return ` ${key}: "${pattern}",`;
2600
+ return ` ${key}: ${JSON.stringify(pattern)},`;
2269
2601
  }
2270
- const searchBody = Object.entries(search).map(([k, v]) => `${k}: "${v}"`).join(", ");
2271
- return ` ${key}: { path: "${pattern}", search: { ${searchBody} } },`;
2602
+ const searchBody = Object.entries(search).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ");
2603
+ return ` ${key}: { path: ${JSON.stringify(pattern)}, search: { ${searchBody} } },`;
2272
2604
  }
2273
2605
 
2274
2606
  // src/build/route-types/ast-route-extraction.ts
@@ -2294,8 +2626,8 @@ function extractObjectStringProperties(node) {
2294
2626
  }
2295
2627
 
2296
2628
  // src/build/route-types/ast-route-extraction.ts
2297
- function extractRoutesFromSource(code) {
2298
- const sourceFile = ts2.createSourceFile(
2629
+ function extractRoutesFromSource(code, sourceFileArg) {
2630
+ const sourceFile = sourceFileArg ?? ts2.createSourceFile(
2299
2631
  "input.tsx",
2300
2632
  code,
2301
2633
  ts2.ScriptTarget.Latest,
@@ -2375,16 +2707,44 @@ export const NamedRoutes = {
2375
2707
  ${objectBody}
2376
2708
  } as const;
2377
2709
 
2710
+ // Aliased so the augmentation below does not pay a homomorphic mapped-type
2711
+ // instantiation per route; \`as const\` already makes the members readonly.
2712
+ type NamedRoutesShape = typeof NamedRoutes;
2713
+
2378
2714
  declare global {
2379
- namespace RSCRouter {
2380
- interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
2715
+ namespace Rango {
2716
+ interface GeneratedRouteMap extends NamedRoutesShape {}
2381
2717
  }
2382
2718
  }
2383
2719
  `;
2384
2720
  }
2385
2721
 
2386
2722
  // src/build/route-types/scan-filter.ts
2723
+ import { join, relative } from "node:path";
2387
2724
  import picomatch from "picomatch";
2725
+ var DEFAULT_EXCLUDE_PATTERNS = [
2726
+ "**/__tests__/**",
2727
+ "**/__mocks__/**",
2728
+ "**/dist/**",
2729
+ "**/coverage/**",
2730
+ "**/*.test.{ts,tsx,js,jsx}",
2731
+ "**/*.spec.{ts,tsx,js,jsx}"
2732
+ ];
2733
+ function createScanFilter(root, opts) {
2734
+ const { include, exclude } = opts;
2735
+ const hasInclude = include && include.length > 0;
2736
+ const hasCustomExclude = exclude !== void 0;
2737
+ if (!hasInclude && !hasCustomExclude) return void 0;
2738
+ const effectiveExclude = exclude ?? DEFAULT_EXCLUDE_PATTERNS;
2739
+ const includeMatcher = hasInclude ? picomatch(include) : null;
2740
+ const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
2741
+ return (absolutePath) => {
2742
+ const rel = relative(root, absolutePath);
2743
+ if (excludeMatcher && excludeMatcher(rel)) return false;
2744
+ if (includeMatcher) return includeMatcher(rel);
2745
+ return true;
2746
+ };
2747
+ }
2388
2748
 
2389
2749
  // src/build/route-types/per-module-writer.ts
2390
2750
  import ts4 from "typescript";
@@ -2393,6 +2753,33 @@ import ts4 from "typescript";
2393
2753
  import { readFileSync, existsSync as existsSync2 } from "node:fs";
2394
2754
  import { dirname, resolve as resolve2 } from "node:path";
2395
2755
  import ts3 from "typescript";
2756
+ function createScanMemo() {
2757
+ return { files: /* @__PURE__ */ new Map(), blockSourceFiles: /* @__PURE__ */ new Map() };
2758
+ }
2759
+ function parseBlock(memo, block) {
2760
+ if (memo) {
2761
+ const cached = memo.blockSourceFiles.get(block);
2762
+ if (cached) return cached;
2763
+ }
2764
+ const sf = ts3.createSourceFile(
2765
+ "input.tsx",
2766
+ block,
2767
+ ts3.ScriptTarget.Latest,
2768
+ true,
2769
+ ts3.ScriptKind.TSX
2770
+ );
2771
+ if (memo) memo.blockSourceFiles.set(block, sf);
2772
+ return sf;
2773
+ }
2774
+ function readSourceMemoized(memo, realPath) {
2775
+ if (memo) {
2776
+ const cached = memo.files.get(realPath);
2777
+ if (cached !== void 0) return cached;
2778
+ }
2779
+ const source = readFileSync(realPath, "utf-8");
2780
+ if (memo) memo.files.set(realPath, source);
2781
+ return source;
2782
+ }
2396
2783
  function extractNamePrefixFromInclude(node) {
2397
2784
  if (node.arguments.length >= 3) {
2398
2785
  const thirdArg = node.arguments[2];
@@ -2408,8 +2795,8 @@ function extractNamePrefixFromInclude(node) {
2408
2795
  }
2409
2796
  return null;
2410
2797
  }
2411
- function extractIncludesWithDiagnostics(code) {
2412
- const sourceFile = ts3.createSourceFile(
2798
+ function extractIncludesWithDiagnostics(code, sourceFileArg) {
2799
+ const sourceFile = sourceFileArg ?? ts3.createSourceFile(
2413
2800
  "input.tsx",
2414
2801
  code,
2415
2802
  ts3.ScriptTarget.Latest,
@@ -2463,7 +2850,7 @@ function extractIncludesWithDiagnostics(code) {
2463
2850
  return { resolved, unresolvable };
2464
2851
  }
2465
2852
  function resolveImportedVariable(code, localName) {
2466
- const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']([^"']+)["']/g;
2853
+ const importRegex = /import\s*(?:[\w$]+\s*,\s*)?\{([^}]+)\}\s*from\s*["']([^"']+)["']/g;
2467
2854
  let match;
2468
2855
  while ((match = importRegex.exec(code)) !== null) {
2469
2856
  const imports = match[1];
@@ -2500,8 +2887,8 @@ function resolveImportPath(importSpec, fromFile) {
2500
2887
  }
2501
2888
  return null;
2502
2889
  }
2503
- function extractUrlsBlockForVariable(code, varName) {
2504
- const sourceFile = ts3.createSourceFile(
2890
+ function extractUrlsBlockForVariable(code, varName, sourceFileArg) {
2891
+ const sourceFile = sourceFileArg ?? ts3.createSourceFile(
2505
2892
  "input.tsx",
2506
2893
  code,
2507
2894
  ts3.ScriptTarget.Latest,
@@ -2523,16 +2910,20 @@ function extractUrlsBlockForVariable(code, varName) {
2523
2910
  visit(sourceFile);
2524
2911
  return result;
2525
2912
  }
2526
- function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSchemasOut, diagnosticsOut) {
2913
+ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSchemasOut, diagnosticsOut, memo) {
2527
2914
  const routeMap = {};
2528
- const localRoutes = extractRoutesFromSource(block);
2915
+ const blockSourceFile = parseBlock(memo, block);
2916
+ const localRoutes = extractRoutesFromSource(block, blockSourceFile);
2529
2917
  for (const { name, pattern, search } of localRoutes) {
2530
2918
  routeMap[name] = pattern;
2531
2919
  if (search && searchSchemasOut) {
2532
2920
  searchSchemasOut[name] = search;
2533
2921
  }
2534
2922
  }
2535
- const { resolved: includes, unresolvable } = extractIncludesWithDiagnostics(block);
2923
+ const { resolved: includes, unresolvable } = extractIncludesWithDiagnostics(
2924
+ block,
2925
+ blockSourceFile
2926
+ );
2536
2927
  if (diagnosticsOut) {
2537
2928
  for (const entry of unresolvable) {
2538
2929
  diagnosticsOut.push({ ...entry, sourceFile: filePath });
@@ -2559,12 +2950,15 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
2559
2950
  targetFile,
2560
2951
  imported.exportedName,
2561
2952
  visited,
2562
- diagnosticsOut
2953
+ diagnosticsOut,
2954
+ void 0,
2955
+ memo
2563
2956
  );
2564
2957
  } else {
2565
2958
  const sameFileBlock = extractUrlsBlockForVariable(
2566
2959
  fullSource,
2567
- variableName
2960
+ variableName,
2961
+ parseBlock(memo, fullSource)
2568
2962
  );
2569
2963
  if (!sameFileBlock) {
2570
2964
  if (diagnosticsOut) {
@@ -2582,7 +2976,9 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
2582
2976
  filePath,
2583
2977
  variableName,
2584
2978
  visited,
2585
- diagnosticsOut
2979
+ diagnosticsOut,
2980
+ void 0,
2981
+ memo
2586
2982
  );
2587
2983
  }
2588
2984
  if (namePrefix === null) {
@@ -2606,18 +3002,19 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
2606
3002
  }
2607
3003
  return routeMap;
2608
3004
  }
2609
- function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock) {
3005
+ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock, memo) {
2610
3006
  visited = visited ?? /* @__PURE__ */ new Set();
3007
+ memo = memo ?? createScanMemo();
2611
3008
  const realPath = resolve2(filePath);
2612
3009
  const key = variableName ? `${realPath}:${variableName}` : realPath;
2613
3010
  if (visited.has(key)) {
2614
- console.warn(`[rsc-router] Circular include detected, skipping: ${key}`);
3011
+ console.warn(`[rango] Circular include detected, skipping: ${key}`);
2615
3012
  return { routes: {}, searchSchemas: {} };
2616
3013
  }
2617
3014
  visited.add(key);
2618
3015
  let source;
2619
3016
  try {
2620
- source = readFileSync(realPath, "utf-8");
3017
+ source = readSourceMemoized(memo, realPath);
2621
3018
  } catch {
2622
3019
  return { routes: {}, searchSchemas: {} };
2623
3020
  }
@@ -2625,7 +3022,11 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
2625
3022
  if (inlineBlock) {
2626
3023
  block = inlineBlock;
2627
3024
  } else if (variableName) {
2628
- const extracted = extractUrlsBlockForVariable(source, variableName);
3025
+ const extracted = extractUrlsBlockForVariable(
3026
+ source,
3027
+ variableName,
3028
+ parseBlock(memo, source)
3029
+ );
2629
3030
  if (!extracted) return { routes: {}, searchSchemas: {} };
2630
3031
  block = extracted;
2631
3032
  } else {
@@ -2638,7 +3039,8 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
2638
3039
  realPath,
2639
3040
  visited,
2640
3041
  searchSchemas,
2641
- diagnosticsOut
3042
+ diagnosticsOut,
3043
+ memo
2642
3044
  );
2643
3045
  visited.delete(key);
2644
3046
  return { routes, searchSchemas };
@@ -2653,7 +3055,7 @@ import {
2653
3055
  readdirSync
2654
3056
  } from "node:fs";
2655
3057
  import {
2656
- join,
3058
+ join as join2,
2657
3059
  dirname as dirname2,
2658
3060
  resolve as resolve3,
2659
3061
  sep,
@@ -2672,6 +3074,7 @@ function countPublicRouteEntries(source) {
2672
3074
  return count;
2673
3075
  }
2674
3076
  var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
3077
+ var ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
2675
3078
  function isRoutableSourceFile(name) {
2676
3079
  return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
2677
3080
  }
@@ -2681,14 +3084,14 @@ function findRouterFilesRecursive(dir, filter, results) {
2681
3084
  entries = readdirSync(dir, { withFileTypes: true });
2682
3085
  } catch (err) {
2683
3086
  console.warn(
2684
- `[rsc-router] Failed to scan directory ${dir}: ${err.message}`
3087
+ `[rango] Failed to scan directory ${dir}: ${err.message}`
2685
3088
  );
2686
3089
  return;
2687
3090
  }
2688
3091
  const childDirs = [];
2689
3092
  const routerFilesInDir = [];
2690
3093
  for (const entry of entries) {
2691
- const fullPath = join(dir, entry.name);
3094
+ const fullPath = join2(dir, entry.name);
2692
3095
  if (entry.isDirectory()) {
2693
3096
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
2694
3097
  continue;
@@ -2699,7 +3102,7 @@ function findRouterFilesRecursive(dir, filter, results) {
2699
3102
  if (filter && !filter(fullPath)) continue;
2700
3103
  try {
2701
3104
  const source = readFileSync2(fullPath, "utf-8");
2702
- if (ROUTER_CALL_PATTERN.test(source)) {
3105
+ if (ROUTER_CALL_PATTERN.test(source) && firstCodeMatchIndex(source, ROUTER_CALL_PATTERN_G) >= 0) {
2703
3106
  routerFilesInDir.push(fullPath);
2704
3107
  }
2705
3108
  } catch {
@@ -2737,7 +3140,7 @@ function findNestedRouterConflict(routerFiles) {
2737
3140
  }
2738
3141
  return null;
2739
3142
  }
2740
- function formatNestedRouterConflictError(conflict, prefix = "[rsc-router]") {
3143
+ function formatNestedRouterConflictError(conflict, prefix = "[rango]") {
2741
3144
  return `${prefix} Nested router roots are not supported.
2742
3145
  Router root: ${conflict.ancestor}
2743
3146
  Nested router: ${conflict.nested}
@@ -2833,19 +3236,38 @@ function extractBasenameFromRouter(code) {
2833
3236
  visit(sourceFile);
2834
3237
  return result;
2835
3238
  }
2836
- function applyBasenameToRoutes(result, basename3) {
3239
+ function applyBasenameToRoutes(result, basename2) {
2837
3240
  const prefixed = {};
2838
3241
  for (const [name, pattern] of Object.entries(result.routes)) {
2839
3242
  if (pattern === "/") {
2840
- prefixed[name] = basename3;
2841
- } else if (basename3.endsWith("/") && pattern.startsWith("/")) {
2842
- prefixed[name] = basename3 + pattern.slice(1);
3243
+ prefixed[name] = basename2;
3244
+ } else if (basename2.endsWith("/") && pattern.startsWith("/")) {
3245
+ prefixed[name] = basename2 + pattern.slice(1);
2843
3246
  } else {
2844
- prefixed[name] = basename3 + pattern;
3247
+ prefixed[name] = basename2 + pattern;
2845
3248
  }
2846
3249
  }
2847
3250
  return { routes: prefixed, searchSchemas: result.searchSchemas };
2848
3251
  }
3252
+ function genFileTsPath(sourceFile) {
3253
+ const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
3254
+ return join2(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
3255
+ }
3256
+ function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
3257
+ if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
3258
+ return runtimeSchemas;
3259
+ }
3260
+ const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
3261
+ if (Object.keys(staticParsed.searchSchemas).length === 0) {
3262
+ return runtimeSchemas;
3263
+ }
3264
+ const filtered = {};
3265
+ for (const name of publicRouteNames) {
3266
+ const schema = staticParsed.searchSchemas[name];
3267
+ if (schema) filtered[name] = schema;
3268
+ }
3269
+ return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
3270
+ }
2849
3271
  function buildCombinedRouteMapForRouterFile(routerFilePath) {
2850
3272
  let routerSource;
2851
3273
  try {
@@ -2858,7 +3280,7 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
2858
3280
  return { routes: {}, searchSchemas: {} };
2859
3281
  }
2860
3282
  const rawBasename = extractBasenameFromRouter(routerSource);
2861
- const basename3 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
3283
+ const basename2 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
2862
3284
  let result;
2863
3285
  if (extraction.kind === "inline") {
2864
3286
  result = buildCombinedRouteMapWithSearch(
@@ -2883,8 +3305,8 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
2883
3305
  result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
2884
3306
  }
2885
3307
  }
2886
- if (basename3) {
2887
- result = applyBasenameToRoutes(result, basename3);
3308
+ if (basename2) {
3309
+ result = applyBasenameToRoutes(result, basename2);
2888
3310
  }
2889
3311
  return result;
2890
3312
  }
@@ -2895,11 +3317,11 @@ function findRouterFiles(root, filter) {
2895
3317
  }
2896
3318
  function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2897
3319
  try {
2898
- const oldCombinedPath = join(root, "src", "named-routes.gen.ts");
3320
+ const oldCombinedPath = join2(root, "src", "named-routes.gen.ts");
2899
3321
  if (existsSync3(oldCombinedPath)) {
2900
3322
  unlinkSync(oldCombinedPath);
2901
3323
  console.log(
2902
- `[rsc-router] Removed stale combined route types: ${oldCombinedPath}`
3324
+ `[rango] Removed stale combined route types: ${oldCombinedPath}`
2903
3325
  );
2904
3326
  }
2905
3327
  } catch {
@@ -2921,18 +3343,12 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2921
3343
  }
2922
3344
  if (!extractUrlsFromRouter(routerSource)) continue;
2923
3345
  }
2924
- const routerBasename = pathBasename(routerFilePath).replace(
2925
- /\.(tsx?|jsx?)$/,
2926
- ""
2927
- );
2928
- const outPath = join(
2929
- dirname2(routerFilePath),
2930
- `${routerBasename}.named-routes.gen.ts`
2931
- );
3346
+ const outPath = genFileTsPath(routerFilePath);
2932
3347
  const existing = existsSync3(outPath) ? readFileSync2(outPath, "utf-8") : null;
2933
3348
  if (Object.keys(result.routes).length === 0) {
2934
3349
  if (!existing) {
2935
3350
  const emptySource = generateRouteTypesSource({});
3351
+ opts?.onWrite?.(outPath, emptySource);
2936
3352
  writeFileSync(outPath, emptySource);
2937
3353
  }
2938
3354
  continue;
@@ -2952,16 +3368,38 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2952
3368
  continue;
2953
3369
  }
2954
3370
  }
3371
+ opts?.onWrite?.(outPath, source);
2955
3372
  writeFileSync(outPath, source);
2956
3373
  console.log(
2957
- `[rsc-router] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
3374
+ `[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
2958
3375
  );
2959
3376
  }
2960
3377
  }
2961
3378
  }
2962
3379
 
2963
3380
  // src/vite/plugins/version-plugin.ts
3381
+ import { parseAst as parseAst4 } from "vite";
3382
+
3383
+ // src/vite/utils/directive-prologue.ts
2964
3384
  import { parseAst as parseAst3 } from "vite";
3385
+ function hasUseClientDirective(source) {
3386
+ let program;
3387
+ try {
3388
+ program = parseAst3(source, { lang: "tsx" });
3389
+ } catch {
3390
+ return false;
3391
+ }
3392
+ for (const node of program.body ?? []) {
3393
+ if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
3394
+ if (node.expression.value === "use client") return true;
3395
+ continue;
3396
+ }
3397
+ break;
3398
+ }
3399
+ return false;
3400
+ }
3401
+
3402
+ // src/vite/plugins/version-plugin.ts
2965
3403
  function isCodeModule(id) {
2966
3404
  return /\.(tsx?|jsx?)($|\?)/.test(id);
2967
3405
  }
@@ -2969,23 +3407,13 @@ function normalizeModuleId(id) {
2969
3407
  return id.split("?", 1)[0];
2970
3408
  }
2971
3409
  function getClientModuleSignature(source) {
3410
+ if (!hasUseClientDirective(source)) return void 0;
2972
3411
  let program;
2973
3412
  try {
2974
- program = parseAst3(source, { jsx: true });
3413
+ program = parseAst4(source, { lang: "tsx" });
2975
3414
  } catch {
2976
3415
  return void 0;
2977
3416
  }
2978
- let isUseClient = false;
2979
- for (const node of program.body ?? []) {
2980
- if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
2981
- if (node.expression.value === "use client") {
2982
- isUseClient = true;
2983
- }
2984
- continue;
2985
- }
2986
- break;
2987
- }
2988
- if (!isUseClient) return void 0;
2989
3417
  const exports = /* @__PURE__ */ new Set();
2990
3418
  let hasDefault = false;
2991
3419
  let hasExportAll = false;
@@ -3054,11 +3482,12 @@ function createVersionPlugin() {
3054
3482
  let currentVersion = buildVersion;
3055
3483
  let isDev = false;
3056
3484
  let server = null;
3485
+ let resolvedCacheDir;
3057
3486
  const clientModuleSignatures = /* @__PURE__ */ new Map();
3058
3487
  let versionCounter = 0;
3059
3488
  const bumpVersion = (reason) => {
3060
3489
  currentVersion = Date.now().toString(16) + String(++versionCounter);
3061
- console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
3490
+ console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
3062
3491
  const rscEnv = server?.environments?.rsc;
3063
3492
  const versionMod = rscEnv?.moduleGraph?.getModuleById(
3064
3493
  "\0" + VIRTUAL_IDS.version
@@ -3072,6 +3501,7 @@ function createVersionPlugin() {
3072
3501
  enforce: "pre",
3073
3502
  configResolved(config) {
3074
3503
  isDev = config.command === "serve";
3504
+ resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
3075
3505
  },
3076
3506
  configureServer(devServer) {
3077
3507
  server = devServer;
@@ -3108,11 +3538,11 @@ function createVersionPlugin() {
3108
3538
  }
3109
3539
  return null;
3110
3540
  },
3111
- // Track RSC module changes and update version
3112
3541
  async hotUpdate(ctx) {
3113
3542
  if (!isDev) return;
3114
3543
  const isRscModule = this.environment?.name === "rsc";
3115
3544
  if (!isRscModule) return;
3545
+ if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
3116
3546
  if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
3117
3547
  return;
3118
3548
  }
@@ -3142,13 +3572,24 @@ function createVersionPlugin() {
3142
3572
  }
3143
3573
  };
3144
3574
  }
3575
+ function isViteDepCachePath(filePath, cacheDir) {
3576
+ if (!filePath) return false;
3577
+ const normalized = filePath.replace(/\\/g, "/");
3578
+ if (cacheDir) {
3579
+ const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
3580
+ if (normalized === normalizedCacheDir || normalized.startsWith(normalizedCacheDir + "/")) {
3581
+ return true;
3582
+ }
3583
+ }
3584
+ return /\/node_modules\/\.vite[^/]*\//.test(normalized) || normalized.includes("/.vite-isolated/");
3585
+ }
3145
3586
 
3146
3587
  // src/vite/utils/shared-utils.ts
3147
3588
  import * as Vite from "vite";
3148
3589
 
3149
3590
  // src/vite/plugins/performance-tracks.ts
3150
3591
  import { readFile } from "node:fs/promises";
3151
- var debug6 = createRangoDebugger("rango:transform");
3592
+ var debug6 = createRangoDebugger(NS.transform);
3152
3593
  var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
3153
3594
  function buildPatchReplacement(match, debugInfoVar) {
3154
3595
  return `${match}
@@ -3170,22 +3611,15 @@ function patchRsdwClientDebugInfoRecovery(code) {
3170
3611
  };
3171
3612
  }
3172
3613
  function performanceTracksOptimizeDepsPlugin() {
3614
+ const RSDW_CLIENT_RE = /react-server-dom-webpack-client\.browser\.(development|production)\.js$/;
3173
3615
  return {
3174
3616
  name: "@rangojs/router:performance-tracks-optimize-deps",
3175
- setup(build) {
3176
- build.onLoad(
3177
- {
3178
- filter: /react-server-dom-webpack-client\.browser\.(development|production)\.js$/
3179
- },
3180
- async (args) => {
3181
- const code = await readFile(args.path, "utf8");
3182
- const patched = patchRsdwClientDebugInfoRecovery(code);
3183
- return {
3184
- contents: patched.code,
3185
- loader: "js"
3186
- };
3187
- }
3188
- );
3617
+ async load(id) {
3618
+ const cleanId = id.split("?")[0] ?? id;
3619
+ if (!RSDW_CLIENT_RE.test(cleanId)) return null;
3620
+ const code = await readFile(cleanId, "utf8");
3621
+ const patched = patchRsdwClientDebugInfoRecovery(code);
3622
+ return { code: patched.code };
3189
3623
  }
3190
3624
  };
3191
3625
  }
@@ -3212,24 +3646,27 @@ function performanceTracksPlugin() {
3212
3646
  }
3213
3647
 
3214
3648
  // src/vite/utils/shared-utils.ts
3215
- var versionEsbuildPlugin = {
3649
+ function resolveRscEntryFromConfig(config) {
3650
+ const entries = config.environments?.["rsc"]?.optimizeDeps?.entries;
3651
+ if (typeof entries === "string") return entries;
3652
+ if (Array.isArray(entries) && entries.length > 0) return entries[0];
3653
+ return void 0;
3654
+ }
3655
+ var versionRolldownPlugin = {
3216
3656
  name: "@rangojs/router-version",
3217
- setup(build) {
3218
- build.onResolve({ filter: /^rsc-router:version$/ }, (args) => ({
3219
- path: args.path,
3220
- namespace: "@rangojs/router-virtual"
3221
- }));
3222
- build.onLoad(
3223
- { filter: /.*/, namespace: "@rangojs/router-virtual" },
3224
- () => ({
3225
- contents: `export const VERSION = "dev";`,
3226
- loader: "js"
3227
- })
3228
- );
3657
+ resolveId(id) {
3658
+ if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
3659
+ return void 0;
3660
+ },
3661
+ load(id) {
3662
+ if (id === "\0" + VIRTUAL_IDS.version) {
3663
+ return getVirtualVersionContent("dev");
3664
+ }
3665
+ return void 0;
3229
3666
  }
3230
3667
  };
3231
- var sharedEsbuildOptions = {
3232
- plugins: [versionEsbuildPlugin, performanceTracksOptimizeDepsPlugin()]
3668
+ var sharedRolldownOptions = {
3669
+ plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()]
3233
3670
  };
3234
3671
  function createVirtualEntriesPlugin(entries, routerPathRef) {
3235
3672
  const virtualModules = {};
@@ -3271,8 +3708,29 @@ function createVirtualEntriesPlugin(entries, routerPathRef) {
3271
3708
  }
3272
3709
  };
3273
3710
  }
3711
+ function isContentHashedAssetConflict(message) {
3712
+ if (!message) return false;
3713
+ const match = /The emitted file "?([^"\s]+)"? overwrites a previously emitted file/.exec(
3714
+ message
3715
+ );
3716
+ if (!match) return false;
3717
+ const fileName = match[1];
3718
+ const base = fileName.slice(fileName.lastIndexOf("/") + 1);
3719
+ const dot = base.lastIndexOf(".");
3720
+ if (dot <= 0) return false;
3721
+ const stem = base.slice(0, dot);
3722
+ const HASH_LEN = 8;
3723
+ if (stem.length < HASH_LEN + 1 || stem[stem.length - HASH_LEN - 1] !== "-") {
3724
+ return false;
3725
+ }
3726
+ const hash = stem.slice(-HASH_LEN);
3727
+ return /^[A-Za-z0-9_-]+$/.test(hash) && /[A-Z0-9]/.test(hash);
3728
+ }
3274
3729
  function onwarn(warning, defaultHandler) {
3275
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE") {
3730
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE" || warning.code === "INEFFECTIVE_DYNAMIC_IMPORT") {
3731
+ return;
3732
+ }
3733
+ if (warning.code === "FILE_NAME_CONFLICT" && isContentHashedAssetConflict(warning.message)) {
3276
3734
  return;
3277
3735
  }
3278
3736
  if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
@@ -3291,28 +3749,153 @@ function getManualChunks(id) {
3291
3749
  return "react";
3292
3750
  }
3293
3751
  const packageName = getPublishedPackageName();
3294
- if (normalized.includes(`node_modules/${packageName}/`) || normalized.includes("packages/rsc-router/") || normalized.includes("packages/rangojs-router/")) {
3752
+ if (normalized.includes(`node_modules/${packageName}/`) || /\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)) {
3295
3753
  return "router";
3296
3754
  }
3297
3755
  return void 0;
3298
3756
  }
3299
3757
 
3300
- // src/vite/utils/banner.ts
3301
- var rangoVersion = package_default.version;
3302
- var _bannerPrinted = false;
3303
- function printBanner(mode, preset, version) {
3304
- if (_bannerPrinted) return;
3305
- _bannerPrinted = true;
3306
- const dim = "\x1B[2m";
3307
- const bold = "\x1B[1m";
3308
- const reset = "\x1B[0m";
3309
- const banner = `
3310
- ${dim} \u2726 \u2726 \u2727. . .${reset}
3311
- ${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2571 \u2726 *${reset}
3312
- ${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
3313
- ${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
3314
- ${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
3315
- ${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
3758
+ // src/vite/plugins/client-ref-hashing.ts
3759
+ import { relative as relative2 } from "node:path";
3760
+ import { createHash as createHash2 } from "node:crypto";
3761
+ var debug7 = createRangoDebugger(NS.transform);
3762
+ var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
3763
+ var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
3764
+ var FS_PREFIX = "/@fs/";
3765
+ function hashRefKey(relativeId) {
3766
+ return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
3767
+ }
3768
+ function computeProductionHash(projectRoot, refKey) {
3769
+ let toHash;
3770
+ if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
3771
+ toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
3772
+ } else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
3773
+ const absPath = decodeURIComponent(
3774
+ refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
3775
+ );
3776
+ toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
3777
+ } else if (refKey.startsWith(FS_PREFIX)) {
3778
+ const absPath = refKey.slice(FS_PREFIX.length - 1);
3779
+ toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
3780
+ } else if (refKey.startsWith("/")) {
3781
+ toHash = refKey.slice(1);
3782
+ } else {
3783
+ return refKey;
3784
+ }
3785
+ return hashRefKey(toHash);
3786
+ }
3787
+ var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
3788
+ function transformClientRefs(code, projectRoot) {
3789
+ if (!code.includes("registerClientReference")) return null;
3790
+ let hasReplacement = false;
3791
+ const result = code.replace(
3792
+ REGISTER_CLIENT_REF_RE,
3793
+ (match, refKey) => {
3794
+ const hash = computeProductionHash(projectRoot, refKey);
3795
+ if (hash === refKey) return match;
3796
+ hasReplacement = true;
3797
+ return match.replace(`"${refKey}"`, `"${hash}"`);
3798
+ }
3799
+ );
3800
+ return hasReplacement ? result : null;
3801
+ }
3802
+ function hashClientRefs(projectRoot) {
3803
+ const counter = createCounter(debug7, "hash-client-refs");
3804
+ return {
3805
+ name: "@rangojs/router:hash-client-refs",
3806
+ enforce: "post",
3807
+ applyToEnvironment(env) {
3808
+ return env.name === "rsc";
3809
+ },
3810
+ buildEnd() {
3811
+ counter?.flush();
3812
+ },
3813
+ transform(code, id) {
3814
+ const start = counter ? performance.now() : 0;
3815
+ try {
3816
+ const result = transformClientRefs(code, projectRoot);
3817
+ if (result === null) return;
3818
+ return { code: result, map: null };
3819
+ } finally {
3820
+ counter?.record(id, performance.now() - start);
3821
+ }
3822
+ }
3823
+ };
3824
+ }
3825
+
3826
+ // src/vite/utils/client-chunks.ts
3827
+ var debugChunks = createRangoDebugger(NS.chunks);
3828
+ function isSharedRuntime(meta) {
3829
+ return [meta.id, meta.normalizedId].some(
3830
+ (path6) => path6.includes("/node_modules/") || /\/@rangojs\/router\//.test(path6) || /\/packages\/(rangojs-router|rsc-router)\/(src|dist)\//.test(path6)
3831
+ );
3832
+ }
3833
+ function sanitizeGroup(name) {
3834
+ return name.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "app";
3835
+ }
3836
+ var ROUTE_ROOT_DIRS = /* @__PURE__ */ new Set([
3837
+ "routes",
3838
+ "route",
3839
+ "pages",
3840
+ "page",
3841
+ "app",
3842
+ "features",
3843
+ "feature",
3844
+ "views",
3845
+ "view",
3846
+ "handlers",
3847
+ "urls",
3848
+ "modules",
3849
+ "screens",
3850
+ "sections"
3851
+ ]);
3852
+ function directoryClientChunks(meta, ctx) {
3853
+ if (isSharedRuntime(meta)) {
3854
+ return void 0;
3855
+ }
3856
+ if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
3857
+ debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
3858
+ return "app-fallback";
3859
+ }
3860
+ const segments = meta.normalizedId.split("/").filter(Boolean);
3861
+ const dirCount = segments.length - 1;
3862
+ if (dirCount >= 1) {
3863
+ for (let i = 0; i < dirCount - 1; i++) {
3864
+ if (ROUTE_ROOT_DIRS.has(segments[i].toLowerCase())) {
3865
+ const group = `app-${sanitizeGroup(segments[i + 1])}`;
3866
+ debugChunks?.("split %s -> %s", meta.normalizedId, group);
3867
+ return group;
3868
+ }
3869
+ }
3870
+ }
3871
+ debugChunks?.(
3872
+ "shared %s (no route-root marker; inherits default grouping)",
3873
+ meta.normalizedId
3874
+ );
3875
+ return void 0;
3876
+ }
3877
+ function resolveClientChunks(option, ctx) {
3878
+ if (!option) return void 0;
3879
+ if (option === true) return (meta) => directoryClientChunks(meta, ctx);
3880
+ return option;
3881
+ }
3882
+
3883
+ // src/vite/utils/banner.ts
3884
+ var rangoVersion = package_default.version;
3885
+ var _bannerPrinted = false;
3886
+ function printBanner(mode, preset, version) {
3887
+ if (_bannerPrinted) return;
3888
+ _bannerPrinted = true;
3889
+ const dim = "\x1B[2m";
3890
+ const bold = "\x1B[1m";
3891
+ const reset = "\x1B[0m";
3892
+ const banner = `
3893
+ ${dim} \u2726 \u2726 \u2727. . .${reset}
3894
+ ${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2571 \u2726 *${reset}
3895
+ ${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
3896
+ ${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
3897
+ ${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
3898
+ ${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
3316
3899
  ${dim} ${reset}${bold}\u2551\u255A\u2550\u255D \u2554\u2550\u2550\u2550\u255D \u2569\u255A\u2550\u2569 \u2569\u255D\u255A\u255D\u255A\u2550\u255D\u255A\u2550\u255D${reset}${dim} \u2726 . *${reset}
3317
3900
  ${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
3318
3901
  ${dim} * ${reset}${bold}\u2551 \u2551${reset}${dim} * \u2727. \u2571${reset}
@@ -3333,15 +3916,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
3333
3916
  enforce: "pre",
3334
3917
  configResolved(config) {
3335
3918
  let entryPath = rscEntryPath;
3336
- if (!entryPath) {
3337
- const rscEnvConfig = config.environments?.["rsc"];
3338
- const entries = rscEnvConfig?.optimizeDeps?.entries;
3339
- if (typeof entries === "string") {
3340
- entryPath = entries;
3341
- } else if (Array.isArray(entries) && entries.length > 0) {
3342
- entryPath = entries[0];
3343
- }
3344
- }
3919
+ if (!entryPath) entryPath = resolveRscEntryFromConfig(config);
3345
3920
  if (entryPath) {
3346
3921
  resolvedEntryPath = resolve4(config.root, entryPath);
3347
3922
  }
@@ -3353,11 +3928,10 @@ function createVersionInjectorPlugin(rscEntryPath) {
3353
3928
  if (normalizedId !== normalizedEntry) {
3354
3929
  return null;
3355
3930
  }
3356
- const prepend = [];
3931
+ const prepend = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
3932
+ (id2) => `import "${id2}";`
3933
+ );
3357
3934
  let newCode = code;
3358
- if (!code.includes("virtual:rsc-router/routes-manifest")) {
3359
- prepend.push(`import "virtual:rsc-router/routes-manifest";`);
3360
- }
3361
3935
  const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
3362
3936
  if (needsVersion) {
3363
3937
  prepend.push(`import { VERSION } from "@rangojs/router:version";`);
@@ -3366,8 +3940,21 @@ function createVersionInjectorPlugin(rscEntryPath) {
3366
3940
  "createRSCHandler({\n version: VERSION,"
3367
3941
  );
3368
3942
  }
3369
- if (prepend.length === 0 && newCode === code) return null;
3370
- newCode = prepend.join("\n") + (prepend.length > 0 ? "\n" : "") + newCode;
3943
+ const lines = newCode.split("\n");
3944
+ let insertAt = 0;
3945
+ while (insertAt < lines.length) {
3946
+ const trimmed = lines[insertAt].trim();
3947
+ if (trimmed === "" || /^\/\/\/\s*<reference\b/.test(trimmed)) {
3948
+ insertAt++;
3949
+ } else {
3950
+ break;
3951
+ }
3952
+ }
3953
+ newCode = [
3954
+ ...lines.slice(0, insertAt),
3955
+ ...prepend,
3956
+ ...lines.slice(insertAt)
3957
+ ].join("\n");
3371
3958
  return {
3372
3959
  code: newCode,
3373
3960
  map: null
@@ -3377,28 +3964,27 @@ function createVersionInjectorPlugin(rscEntryPath) {
3377
3964
  }
3378
3965
 
3379
3966
  // src/vite/plugins/cjs-to-esm.ts
3380
- var debug7 = createRangoDebugger("rango:transform");
3967
+ var debug8 = createRangoDebugger(NS.transform);
3381
3968
  function createCjsToEsmPlugin() {
3382
- const counter = createCounter(debug7, "cjs-to-esm");
3969
+ let isProduction = false;
3383
3970
  return {
3384
3971
  name: "@rangojs/router:cjs-to-esm",
3385
3972
  enforce: "pre",
3386
- buildEnd() {
3387
- counter?.flush();
3973
+ configResolved(config) {
3974
+ isProduction = config.isProduction;
3388
3975
  },
3389
3976
  transform(code, id) {
3390
- const cleanId = id.split("?")[0];
3391
- const __t0 = counter ? performance.now() : 0;
3392
- if (cleanId.includes("vendor/react-server-dom/client.browser.js") || cleanId.includes("vendor\\react-server-dom\\client.browser.js")) {
3393
- const isProd = process.env.NODE_ENV === "production";
3977
+ const cleanId = id.split("?")[0].replaceAll("\\", "/");
3978
+ if (cleanId.includes("vendor/react-server-dom/client.browser.js")) {
3979
+ const isProd = isProduction;
3394
3980
  const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
3395
- counter?.record(id, performance.now() - __t0);
3981
+ debug8?.("cjs-to-esm entry redirect %s", id);
3396
3982
  return {
3397
3983
  code: `export * from "${cjsFile}";`,
3398
3984
  map: null
3399
3985
  };
3400
3986
  }
3401
- if ((cleanId.includes("vendor/react-server-dom/cjs/") || cleanId.includes("vendor\\react-server-dom\\cjs\\")) && cleanId.includes("client.browser")) {
3987
+ if (cleanId.includes("vendor/react-server-dom/cjs/") && cleanId.includes("client.browser")) {
3402
3988
  let transformed = code;
3403
3989
  const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
3404
3990
  const license = licenseMatch ? licenseMatch[0] : "";
@@ -3428,7 +4014,7 @@ function createCjsToEsmPlugin() {
3428
4014
  "export const $1 ="
3429
4015
  );
3430
4016
  transformed = license + "\n" + transformed;
3431
- counter?.record(id, performance.now() - __t0);
4017
+ debug8?.("cjs-to-esm body rewrite %s", id);
3432
4018
  return {
3433
4019
  code: transformed,
3434
4020
  map: null
@@ -3446,6 +4032,19 @@ import { readFileSync as readFileSync6 } from "node:fs";
3446
4032
  import { createRequire as createRequire2, register } from "node:module";
3447
4033
  import { pathToFileURL } from "node:url";
3448
4034
 
4035
+ // src/vite/inject-client-debug.ts
4036
+ function injectClientDebugFlag(id) {
4037
+ if (!id.includes("internal-debug")) return null;
4038
+ const norm = id.replace(/\\/g, "/");
4039
+ const isInternalDebug = /\/internal-debug\.[cm]?[jt]sx?(\?|$)/.test(norm) && (norm.includes("/@rangojs/router/") || norm.includes("/packages/rangojs-router/"));
4040
+ if (!isInternalDebug) return null;
4041
+ return {
4042
+ code: `export const INTERNAL_RANGO_DEBUG = ${!!process.env.INTERNAL_RANGO_DEBUG};
4043
+ `,
4044
+ map: null
4045
+ };
4046
+ }
4047
+
3449
4048
  // src/vite/plugins/virtual-stub-plugin.ts
3450
4049
  function createVirtualStubPlugin() {
3451
4050
  const STUB_PREFIXES = [
@@ -3517,7 +4116,7 @@ function createCloudflareProtocolStubPlugin() {
3517
4116
  if (!code.includes(CF_PREFIX)) return null;
3518
4117
  let ast;
3519
4118
  try {
3520
- ast = this.parse(code);
4119
+ ast = this.parse(code, { lang: "tsx" });
3521
4120
  } catch {
3522
4121
  return null;
3523
4122
  }
@@ -3577,72 +4176,6 @@ function walk(node, visit) {
3577
4176
  }
3578
4177
  }
3579
4178
 
3580
- // src/vite/plugins/client-ref-hashing.ts
3581
- import { relative } from "node:path";
3582
- import { createHash as createHash2 } from "node:crypto";
3583
- var debug8 = createRangoDebugger("rango:transform");
3584
- var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
3585
- var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
3586
- var FS_PREFIX = "/@fs/";
3587
- function computeProductionHash(projectRoot, refKey) {
3588
- let toHash;
3589
- if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
3590
- toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
3591
- } else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
3592
- const absPath = decodeURIComponent(
3593
- refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
3594
- );
3595
- toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
3596
- } else if (refKey.startsWith(FS_PREFIX)) {
3597
- const absPath = refKey.slice(FS_PREFIX.length - 1);
3598
- toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
3599
- } else if (refKey.startsWith("/")) {
3600
- toHash = refKey.slice(1);
3601
- } else {
3602
- return refKey;
3603
- }
3604
- return createHash2("sha256").update(toHash).digest("hex").slice(0, 12);
3605
- }
3606
- var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
3607
- function transformClientRefs(code, projectRoot) {
3608
- if (!code.includes("registerClientReference")) return null;
3609
- let hasReplacement = false;
3610
- const result = code.replace(
3611
- REGISTER_CLIENT_REF_RE,
3612
- (match, refKey) => {
3613
- const hash = computeProductionHash(projectRoot, refKey);
3614
- if (hash === refKey) return match;
3615
- hasReplacement = true;
3616
- return match.replace(`"${refKey}"`, `"${hash}"`);
3617
- }
3618
- );
3619
- return hasReplacement ? result : null;
3620
- }
3621
- function hashClientRefs(projectRoot) {
3622
- const counter = createCounter(debug8, "hash-client-refs");
3623
- return {
3624
- name: "@rangojs/router:hash-client-refs",
3625
- // Run after the RSC plugin's transform (default enforce is normal)
3626
- enforce: "post",
3627
- applyToEnvironment(env) {
3628
- return env.name === "rsc";
3629
- },
3630
- buildEnd() {
3631
- counter?.flush();
3632
- },
3633
- transform(code, id) {
3634
- const start = counter ? performance.now() : 0;
3635
- try {
3636
- const result = transformClientRefs(code, projectRoot);
3637
- if (result === null) return;
3638
- return { code: result, map: null };
3639
- } finally {
3640
- counter?.record(id, performance.now() - start);
3641
- }
3642
- }
3643
- };
3644
- }
3645
-
3646
4179
  // src/vite/utils/bundle-analysis.ts
3647
4180
  function findMatchingParenInBundle(code, openParenPos) {
3648
4181
  let depth = 1;
@@ -3673,7 +4206,7 @@ function extractHandlerExportsFromChunk(chunkCode, handlerModules, fnName, detec
3673
4206
  if (detectPassthrough) {
3674
4207
  const eFnName = escapeRegExp(fnName);
3675
4208
  const callStartRe = new RegExp(
3676
- `const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
4209
+ `(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
3677
4210
  );
3678
4211
  const callStart = callStartRe.exec(chunkCode);
3679
4212
  if (callStart) {
@@ -3698,7 +4231,7 @@ function evictHandlerCode(code, exports, fnName, brand) {
3698
4231
  if (passthrough) continue;
3699
4232
  const eName = escapeRegExp(name);
3700
4233
  const callStartRe = new RegExp(
3701
- `const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
4234
+ `(?:const|let|var)\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
3702
4235
  );
3703
4236
  const startMatch = callStartRe.exec(modified);
3704
4237
  if (!startMatch) continue;
@@ -3733,6 +4266,8 @@ function createDiscoveryState(entryPath, opts) {
3733
4266
  projectRoot: "",
3734
4267
  isBuildMode: false,
3735
4268
  userResolveAlias: void 0,
4269
+ userRunnerConfig: void 0,
4270
+ userResolvePlugins: [],
3736
4271
  scanFilter: void 0,
3737
4272
  cachedRouterFiles: void 0,
3738
4273
  opts,
@@ -3754,7 +4289,8 @@ function createDiscoveryState(entryPath, opts) {
3754
4289
  devServerOrigin: null,
3755
4290
  devServer: null,
3756
4291
  selfWrittenGenFiles: /* @__PURE__ */ new Map(),
3757
- SELF_WRITE_WINDOW_MS: 5e3
4292
+ SELF_WRITE_WINDOW_MS: 5e3,
4293
+ lastDiscoveryError: null
3758
4294
  };
3759
4295
  }
3760
4296
 
@@ -3766,6 +4302,12 @@ function markSelfGenWrite(state, filePath, content) {
3766
4302
  state.selfWrittenGenFiles.set(filePath, { at: Date.now(), hash });
3767
4303
  }
3768
4304
  function consumeSelfGenWrite(state, filePath) {
4305
+ return checkSelfGenWrite(state, filePath, true);
4306
+ }
4307
+ function peekSelfGenWrite(state, filePath) {
4308
+ return checkSelfGenWrite(state, filePath, false);
4309
+ }
4310
+ function checkSelfGenWrite(state, filePath, consume) {
3769
4311
  const info = state.selfWrittenGenFiles.get(filePath);
3770
4312
  if (!info) return false;
3771
4313
  if (Date.now() - info.at > state.SELF_WRITE_WINDOW_MS) {
@@ -3776,7 +4318,7 @@ function consumeSelfGenWrite(state, filePath) {
3776
4318
  const current = readFileSync3(filePath, "utf-8");
3777
4319
  const currentHash = createHash3("sha256").update(current).digest("hex");
3778
4320
  if (currentHash === info.hash) {
3779
- state.selfWrittenGenFiles.delete(filePath);
4321
+ if (consume) state.selfWrittenGenFiles.delete(filePath);
3780
4322
  return true;
3781
4323
  }
3782
4324
  return false;
@@ -3786,11 +4328,57 @@ function consumeSelfGenWrite(state, filePath) {
3786
4328
  }
3787
4329
  }
3788
4330
 
3789
- // src/vite/utils/manifest-utils.ts
4331
+ // src/router/logging.ts
4332
+ import { AsyncLocalStorage } from "node:async_hooks";
4333
+
4334
+ // src/internal-debug.ts
4335
+ var INTERNAL_RANGO_DEBUG = typeof process !== "undefined" && Boolean(process.env?.INTERNAL_RANGO_DEBUG);
4336
+
4337
+ // src/router/logging.ts
4338
+ var routerLogContext = new AsyncLocalStorage();
4339
+
4340
+ // src/router/pattern-matching.ts
4341
+ function parsePattern(pattern) {
4342
+ const segments = [];
4343
+ const segmentRegex = /\/(:([a-zA-Z_][a-zA-Z0-9_]*)(\(([^)]+)\))?(\?)?([^/]*)|(\*)|([^/]+))/g;
4344
+ let match;
4345
+ while ((match = segmentRegex.exec(pattern)) !== null) {
4346
+ const [
4347
+ ,
4348
+ ,
4349
+ paramName,
4350
+ ,
4351
+ constraint,
4352
+ optional,
4353
+ suffix,
4354
+ wildcard,
4355
+ staticText
4356
+ ] = match;
4357
+ if (wildcard) {
4358
+ segments.push({ type: "wildcard", value: "*", optional: false });
4359
+ } else if (paramName) {
4360
+ segments.push({
4361
+ type: "param",
4362
+ value: paramName,
4363
+ optional: optional === "?",
4364
+ constraint: constraint ? constraint.split("|") : void 0,
4365
+ suffix: suffix || void 0
4366
+ });
4367
+ } else if (staticText) {
4368
+ segments.push({ type: "static", value: staticText, optional: false });
4369
+ }
4370
+ }
4371
+ return segments;
4372
+ }
4373
+
4374
+ // src/build/prefix-tree-utils.ts
3790
4375
  function flattenLeafEntries(prefixTree, routeManifest, result) {
3791
- function visit(node) {
4376
+ function visit(node, ancestorStaticPrefixes) {
3792
4377
  const children = node.children || {};
3793
4378
  if (Object.keys(children).length === 0 && node.routes && node.routes.length > 0) {
4379
+ if (ancestorStaticPrefixes.has(node.staticPrefix)) {
4380
+ return;
4381
+ }
3794
4382
  const routes = {};
3795
4383
  for (const name of node.routes) {
3796
4384
  if (name in routeManifest) {
@@ -3799,13 +4387,15 @@ function flattenLeafEntries(prefixTree, routeManifest, result) {
3799
4387
  }
3800
4388
  result.push({ staticPrefix: node.staticPrefix, routes });
3801
4389
  } else {
4390
+ const nextAncestors = new Set(ancestorStaticPrefixes);
4391
+ nextAncestors.add(node.staticPrefix);
3802
4392
  for (const child of Object.values(children)) {
3803
- visit(child);
4393
+ visit(child, nextAncestors);
3804
4394
  }
3805
4395
  }
3806
4396
  }
3807
4397
  for (const node of Object.values(prefixTree)) {
3808
- visit(node);
4398
+ visit(node, /* @__PURE__ */ new Set());
3809
4399
  }
3810
4400
  }
3811
4401
  function buildRouteToStaticPrefix(prefixTree, result) {
@@ -3822,6 +4412,219 @@ function buildRouteToStaticPrefix(prefixTree, result) {
3822
4412
  visit(node);
3823
4413
  }
3824
4414
  }
4415
+
4416
+ // src/build/route-trie.ts
4417
+ function buildRouteTrie(routeManifest, routeAncestry, routeToStaticPrefix, routeTrailingSlash, prerenderRouteNames, passthroughRouteNames, responseTypeRoutes) {
4418
+ const root = {};
4419
+ for (const [routeName, pattern] of Object.entries(routeManifest)) {
4420
+ const ancestry = routeAncestry[routeName] || [];
4421
+ const staticPrefix = routeToStaticPrefix[routeName] || "";
4422
+ const trailingSlash = routeTrailingSlash?.[routeName];
4423
+ const responseType = responseTypeRoutes?.[routeName];
4424
+ const hasTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
4425
+ const normalizedPattern = hasTrailingSlash ? pattern.slice(0, -1) : pattern;
4426
+ const segments = parsePattern(normalizedPattern);
4427
+ insertRoute(root, segments, 0, {
4428
+ n: routeName,
4429
+ sp: staticPrefix,
4430
+ a: ancestry,
4431
+ ...trailingSlash ? { ts: trailingSlash } : {},
4432
+ ...prerenderRouteNames?.has(routeName) ? { pr: true } : {},
4433
+ ...passthroughRouteNames?.has(routeName) ? { pt: true } : {},
4434
+ ...responseType ? { rt: responseType } : {}
4435
+ });
4436
+ }
4437
+ sortSuffixParams(root);
4438
+ return root;
4439
+ }
4440
+ function sortSuffixParams(node) {
4441
+ if (node.xp) {
4442
+ const sorted = {};
4443
+ for (const suffix of Object.keys(node.xp).sort(
4444
+ (a, b) => b.length - a.length
4445
+ )) {
4446
+ sorted[suffix] = node.xp[suffix];
4447
+ }
4448
+ node.xp = sorted;
4449
+ for (const child of Object.values(node.xp)) {
4450
+ sortSuffixParams(child.c);
4451
+ }
4452
+ }
4453
+ if (node.s) {
4454
+ for (const child of Object.values(node.s)) {
4455
+ sortSuffixParams(child);
4456
+ }
4457
+ }
4458
+ if (node.p) {
4459
+ sortSuffixParams(node.p.c);
4460
+ }
4461
+ }
4462
+ function buildPerRouterTrie(manifest) {
4463
+ const ancestry = manifest._routeAncestry;
4464
+ if (!ancestry || Object.keys(ancestry).length === 0) {
4465
+ return null;
4466
+ }
4467
+ const routeToStaticPrefix = {};
4468
+ for (const name of Object.keys(manifest.routeManifest)) {
4469
+ routeToStaticPrefix[name] = "";
4470
+ }
4471
+ if (manifest.prefixTree) {
4472
+ buildRouteToStaticPrefix(manifest.prefixTree, routeToStaticPrefix);
4473
+ }
4474
+ return buildRouteTrie(
4475
+ manifest.routeManifest,
4476
+ ancestry,
4477
+ routeToStaticPrefix,
4478
+ manifest.routeTrailingSlash,
4479
+ manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0,
4480
+ manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0,
4481
+ manifest.responseTypeRoutes
4482
+ );
4483
+ }
4484
+ function insertRoute(node, segments, index, leaf) {
4485
+ const constraints = {};
4486
+ for (const seg of segments) {
4487
+ if (seg.type === "param") {
4488
+ if (seg.constraint) {
4489
+ constraints[seg.value] = seg.constraint;
4490
+ }
4491
+ }
4492
+ }
4493
+ const leafBase = {
4494
+ ...leaf,
4495
+ ...Object.keys(constraints).length > 0 ? { cv: constraints } : {}
4496
+ };
4497
+ insertSegments(node, segments, index, leafBase, []);
4498
+ }
4499
+ function toVariant(leaf, responseType) {
4500
+ return leaf.pa ? { routeKey: leaf.n, responseType, pa: leaf.pa } : { routeKey: leaf.n, responseType };
4501
+ }
4502
+ function mergeLeaves(existing, leaf) {
4503
+ if (!existing) return leaf;
4504
+ if (existing.rt && leaf.rt) {
4505
+ const merged = leaf;
4506
+ merged.nv = existing.nv || [];
4507
+ merged.nv.push(toVariant(existing, existing.rt));
4508
+ return merged;
4509
+ }
4510
+ if (leaf.rt && !existing.rt) {
4511
+ if (!existing.nv) {
4512
+ existing.nv = [];
4513
+ existing.rf = true;
4514
+ }
4515
+ existing.nv.push(toVariant(leaf, leaf.rt));
4516
+ return existing;
4517
+ }
4518
+ if (!leaf.rt && existing.rt) {
4519
+ if (!leaf.nv) leaf.nv = [];
4520
+ if (existing.nv) leaf.nv.push(...existing.nv);
4521
+ leaf.nv.push(toVariant(existing, existing.rt));
4522
+ return leaf;
4523
+ }
4524
+ return leaf;
4525
+ }
4526
+ function mergeLeaf(node, leaf) {
4527
+ node.r = mergeLeaves(node.r, leaf);
4528
+ }
4529
+ function buildLeaf(leafBase, paramNames) {
4530
+ return paramNames.length > 0 ? { ...leafBase, pa: [...paramNames] } : { ...leafBase };
4531
+ }
4532
+ function insertSegments(node, segments, index, leafBase, paramNames) {
4533
+ if (index >= segments.length) {
4534
+ mergeLeaf(node, buildLeaf(leafBase, paramNames));
4535
+ return;
4536
+ }
4537
+ const segment = segments[index];
4538
+ if (segment.type === "static") {
4539
+ if (!node.s) node.s = {};
4540
+ if (!node.s[segment.value]) node.s[segment.value] = {};
4541
+ insertSegments(
4542
+ node.s[segment.value],
4543
+ segments,
4544
+ index + 1,
4545
+ leafBase,
4546
+ paramNames
4547
+ );
4548
+ } else if (segment.type === "param") {
4549
+ if (segment.optional) {
4550
+ insertSegments(node, segments, index + 1, leafBase, paramNames);
4551
+ }
4552
+ if (segment.suffix) {
4553
+ if (!node.xp) node.xp = {};
4554
+ if (!node.xp[segment.suffix]) {
4555
+ node.xp[segment.suffix] = { n: segment.value, c: {} };
4556
+ }
4557
+ insertSegments(node.xp[segment.suffix].c, segments, index + 1, leafBase, [
4558
+ ...paramNames,
4559
+ segment.value
4560
+ ]);
4561
+ } else {
4562
+ if (!node.p) {
4563
+ node.p = { n: segment.value, c: {} };
4564
+ }
4565
+ insertSegments(node.p.c, segments, index + 1, leafBase, [
4566
+ ...paramNames,
4567
+ segment.value
4568
+ ]);
4569
+ }
4570
+ } else if (segment.type === "wildcard") {
4571
+ const wildLeaf = {
4572
+ ...buildLeaf(leafBase, paramNames),
4573
+ pn: "*"
4574
+ };
4575
+ const existing = node.w ? { ...node.w } : void 0;
4576
+ const merged = mergeLeaves(existing, wildLeaf);
4577
+ node.w = merged;
4578
+ }
4579
+ }
4580
+
4581
+ // src/build/collect-fallback-refs.ts
4582
+ var CLIENT_REF = /* @__PURE__ */ Symbol.for("react.client.reference");
4583
+ var MAX_DEPTH = 40;
4584
+ var SYNTHETIC_PROPS = {
4585
+ error: new Error("rango: build-time fallback-chunk discovery"),
4586
+ reset: () => {
4587
+ },
4588
+ pathname: "/",
4589
+ info: { componentStack: "" }
4590
+ };
4591
+ function isReactNodeLike(v) {
4592
+ return Array.isArray(v) || typeof v === "object" && v !== null && "$$typeof" in v;
4593
+ }
4594
+ function walkElementTree(node, report, depth) {
4595
+ if (node == null || depth > MAX_DEPTH) return;
4596
+ if (Array.isArray(node)) {
4597
+ for (const child of node) walkElementTree(child, report, depth + 1);
4598
+ return;
4599
+ }
4600
+ if (typeof node !== "object") return;
4601
+ const el = node;
4602
+ const type = el.type;
4603
+ if (type?.$$typeof === CLIENT_REF && typeof type.$$id === "string") {
4604
+ report(type.$$id.split("#")[0]);
4605
+ }
4606
+ const props = el.props;
4607
+ if (props && typeof props === "object") {
4608
+ walkElementTree(props.children, report, depth + 1);
4609
+ for (const key in props) {
4610
+ if (key === "children") continue;
4611
+ const value = props[key];
4612
+ if (isReactNodeLike(value)) walkElementTree(value, report, depth + 1);
4613
+ }
4614
+ }
4615
+ }
4616
+ function collectFallbackClientRefs(boundary, report) {
4617
+ try {
4618
+ let node = boundary;
4619
+ if (typeof node === "function") {
4620
+ node = node(SYNTHETIC_PROPS);
4621
+ }
4622
+ walkElementTree(node, report, 0);
4623
+ } catch {
4624
+ }
4625
+ }
4626
+
4627
+ // src/vite/utils/manifest-utils.ts
3825
4628
  function jsonParseExpression(value) {
3826
4629
  const json = JSON.stringify(value);
3827
4630
  const escaped = json.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
@@ -3829,6 +4632,9 @@ function jsonParseExpression(value) {
3829
4632
  }
3830
4633
 
3831
4634
  // src/context-var.ts
4635
+ function hasContextVars(variables) {
4636
+ return Object.keys(variables).length > 0 || Object.getOwnPropertySymbols(variables).length > 0;
4637
+ }
3832
4638
  var NON_CACHEABLE_KEYS = /* @__PURE__ */ Symbol.for(
3833
4639
  "rango:non-cacheable-keys"
3834
4640
  );
@@ -3869,9 +4675,6 @@ import {
3869
4675
  writeFileSync as writeFileSync2
3870
4676
  } from "node:fs";
3871
4677
  import { resolve as resolve5 } from "node:path";
3872
- function escapeRegExp2(str) {
3873
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3874
- }
3875
4678
  function encodePathParam(value) {
3876
4679
  return String(value).split("/").map((segment) => encodeURIComponent(segment)).join("/");
3877
4680
  }
@@ -3879,7 +4682,7 @@ function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
3879
4682
  let result = pattern;
3880
4683
  let hadOmittedOptional = false;
3881
4684
  for (const [key, value] of Object.entries(params)) {
3882
- const escaped = escapeRegExp2(key);
4685
+ const escaped = escapeRegExp(key);
3883
4686
  if (value === "") {
3884
4687
  result = result.replace(
3885
4688
  new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
@@ -3912,13 +4715,24 @@ async function runWithConcurrency(items, concurrency, fn) {
3912
4715
  return;
3913
4716
  }
3914
4717
  let nextIndex = 0;
4718
+ let firstError;
4719
+ let failed = false;
3915
4720
  async function worker() {
3916
- while (nextIndex < items.length) {
4721
+ while (nextIndex < items.length && !failed) {
3917
4722
  const idx = nextIndex++;
3918
- await fn(items[idx]);
4723
+ try {
4724
+ await fn(items[idx]);
4725
+ } catch (err) {
4726
+ if (!failed) {
4727
+ failed = true;
4728
+ firstError = err;
4729
+ }
4730
+ return;
4731
+ }
3919
4732
  }
3920
4733
  }
3921
4734
  await Promise.all(Array.from({ length: limit }, () => worker()));
4735
+ if (failed) throw firstError;
3922
4736
  }
3923
4737
  function groupByConcurrency(entries) {
3924
4738
  const map = /* @__PURE__ */ new Map();
@@ -3965,6 +4779,23 @@ function notifyOnError(registry, error, phase, routeKey, pathname, skipped) {
3965
4779
  break;
3966
4780
  }
3967
4781
  }
4782
+ function resolvePrerenderError(registry, error, onError, label, elapsed, phase, routeKey, pathname) {
4783
+ const isSkip = error?.name === "Skip";
4784
+ if (isSkip || onError === "warn") {
4785
+ if (isSkip) {
4786
+ console.log(`[rango] SKIP ${label} (${elapsed}ms) - ${error.message}`);
4787
+ } else {
4788
+ console.warn(
4789
+ `[rango] WARN ${label} (${elapsed}ms) - render error, not pre-rendered (prerender.onError: "warn"): ${error.message}`
4790
+ );
4791
+ }
4792
+ notifyOnError(registry, error, phase, routeKey, pathname, true);
4793
+ return;
4794
+ }
4795
+ console.error(`[rango] FAIL ${label} (${elapsed}ms) - ${error.message}`);
4796
+ notifyOnError(registry, error, phase, routeKey, pathname);
4797
+ throw error;
4798
+ }
3968
4799
  function getStagedAssetDir(projectRoot) {
3969
4800
  return resolve5(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
3970
4801
  }
@@ -3998,7 +4829,7 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
3998
4829
  }
3999
4830
 
4000
4831
  // src/vite/discovery/prerender-collection.ts
4001
- var debug9 = createRangoDebugger("rango:prerender");
4832
+ var debug9 = createRangoDebugger(NS.prerender);
4002
4833
  async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4003
4834
  if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
4004
4835
  const overallStart = debug9 ? performance.now() : 0;
@@ -4032,7 +4863,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4032
4863
  const progressInterval = totalDynamic > 0 ? setInterval(() => {
4033
4864
  const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
4034
4865
  console.log(
4035
- `[rsc-router] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
4866
+ `[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
4036
4867
  );
4037
4868
  }, 5e3) : void 0;
4038
4869
  try {
@@ -4069,7 +4900,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4069
4900
  get env() {
4070
4901
  if (buildEnv !== void 0) return buildEnv;
4071
4902
  throw new Error(
4072
- "[rsc-router] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
4903
+ "[rango] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
4073
4904
  );
4074
4905
  }
4075
4906
  };
@@ -4081,7 +4912,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4081
4912
  (performance.now() - getParamsStart).toFixed(1)
4082
4913
  );
4083
4914
  const concurrency = def.options?.concurrency ?? 1;
4084
- const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
4915
+ const hasBuildVars = hasContextVars(buildVars);
4085
4916
  for (const params of paramsList) {
4086
4917
  let url = substituteRouteParams(
4087
4918
  pattern,
@@ -4110,7 +4941,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4110
4941
  resolvedRoutes++;
4111
4942
  if (err.name === "Skip") {
4112
4943
  console.log(
4113
- `[rsc-router] SKIP route "${routeName}" - ${err.message}`
4944
+ `[rango] SKIP route "${routeName}" - ${err.message}`
4114
4945
  );
4115
4946
  notifyOnError(
4116
4947
  registry,
@@ -4123,14 +4954,14 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4123
4954
  continue;
4124
4955
  }
4125
4956
  console.error(
4126
- `[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`
4957
+ `[rango] Failed to get params for prerender route "${routeName}": ${err.message}`
4127
4958
  );
4128
4959
  notifyOnError(registry, err, "prerender", routeName);
4129
4960
  throw err;
4130
4961
  }
4131
4962
  } else {
4132
4963
  console.warn(
4133
- `[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
4964
+ `[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`
4134
4965
  );
4135
4966
  }
4136
4967
  }
@@ -4141,7 +4972,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4141
4972
  clearInterval(progressInterval);
4142
4973
  const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
4143
4974
  console.log(
4144
- `[rsc-router] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
4975
+ `[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
4145
4976
  );
4146
4977
  }
4147
4978
  }
@@ -4155,7 +4986,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4155
4986
  const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
4156
4987
  const concurrencyNote = maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
4157
4988
  console.log(
4158
- `[rsc-router] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
4989
+ `[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
4159
4990
  );
4160
4991
  debug9?.(
4161
4992
  "prerender loop: %d entries, max concurrency %d",
@@ -4166,6 +4997,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4166
4997
  const manifestEntries = {};
4167
4998
  let doneCount = 0;
4168
4999
  let skipCount = 0;
5000
+ const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
4169
5001
  const startTotal = performance.now();
4170
5002
  const groups = groupByConcurrency(entries);
4171
5003
  for (const group of groups) {
@@ -4188,7 +5020,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4188
5020
  if (result.passthrough) {
4189
5021
  const elapsed2 = (performance.now() - startUrl).toFixed(0);
4190
5022
  console.log(
4191
- `[rsc-router] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
5023
+ `[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
4192
5024
  );
4193
5025
  doneCount++;
4194
5026
  break;
@@ -4208,10 +5040,9 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4208
5040
  const interceptKey = `${result.routeName}/${paramHash}/i`;
4209
5041
  const interceptValue = JSON.stringify({
4210
5042
  segments: [...result.segments, ...result.interceptSegments],
4211
- handles: {
4212
- ...result.handles,
4213
- ...result.interceptHandles || {}
4214
- }
5043
+ // interceptHandles is the pre-encoded MERGED (main + intercept)
5044
+ // handle string (the producer merged before encoding).
5045
+ handles: result.interceptHandles ?? ""
4215
5046
  });
4216
5047
  manifestEntries[interceptKey] = stageBuildAssetModule(
4217
5048
  state.projectRoot,
@@ -4221,39 +5052,24 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4221
5052
  }
4222
5053
  const elapsed = (performance.now() - startUrl).toFixed(0);
4223
5054
  console.log(
4224
- `[rsc-router] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`
5055
+ `[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`
4225
5056
  );
4226
5057
  doneCount++;
4227
5058
  break;
4228
5059
  } catch (err) {
4229
- if (err.name === "Skip") {
4230
- const elapsed2 = (performance.now() - startUrl).toFixed(0);
4231
- console.log(
4232
- `[rsc-router] SKIP ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - ${err.message}`
4233
- );
4234
- skipCount++;
4235
- notifyOnError(
4236
- registry,
4237
- err,
4238
- "prerender",
4239
- entry.routeName,
4240
- entry.urlPath,
4241
- true
4242
- );
4243
- break;
4244
- }
4245
5060
  const elapsed = (performance.now() - startUrl).toFixed(0);
4246
- console.error(
4247
- `[rsc-router] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`
4248
- );
4249
- notifyOnError(
5061
+ resolvePrerenderError(
4250
5062
  registry,
4251
5063
  err,
5064
+ prerenderOnError,
5065
+ entry.urlPath.padEnd(40),
5066
+ elapsed,
4252
5067
  "prerender",
4253
5068
  entry.routeName,
4254
5069
  entry.urlPath
4255
5070
  );
4256
- throw err;
5071
+ skipCount++;
5072
+ break;
4257
5073
  }
4258
5074
  }
4259
5075
  }
@@ -4266,7 +5082,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
4266
5082
  const parts = [`${doneCount} done`];
4267
5083
  if (skipCount > 0) parts.push(`${skipCount} skipped`);
4268
5084
  console.log(
4269
- `[rsc-router] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`
5085
+ `[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`
4270
5086
  );
4271
5087
  debug9?.(
4272
5088
  "expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
@@ -4288,20 +5104,19 @@ async function renderStaticHandlers(state, rscEnv, registry) {
4288
5104
  let staticDone = 0;
4289
5105
  let staticSkip = 0;
4290
5106
  let totalStaticCount = 0;
5107
+ const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
4291
5108
  for (const [, exportNames] of state.resolvedStaticModules) {
4292
5109
  totalStaticCount += exportNames.length;
4293
5110
  }
4294
5111
  const startStatic = performance.now();
4295
- console.log(
4296
- `[rsc-router] Rendering ${totalStaticCount} static handler(s)...`
4297
- );
5112
+ console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
4298
5113
  for (const [moduleId, exportNames] of state.resolvedStaticModules) {
4299
5114
  let mod;
4300
5115
  try {
4301
5116
  mod = await rscEnv.runner.import(moduleId);
4302
5117
  } catch (err) {
4303
5118
  console.error(
4304
- `[rsc-router] Failed to import static module ${moduleId}: ${err.message}`
5119
+ `[rango] Failed to import static module ${moduleId}: ${err.message}`
4305
5120
  );
4306
5121
  notifyOnError(registry, err, "static");
4307
5122
  throw err;
@@ -4323,7 +5138,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
4323
5138
  !state.isBuildMode
4324
5139
  );
4325
5140
  if (result) {
4326
- const hasHandles = Object.keys(result.handles).length > 0;
5141
+ const hasHandles = result.handles !== "";
4327
5142
  const exportValue = hasHandles ? JSON.stringify(result) : JSON.stringify(result.encoded);
4328
5143
  manifestEntries[def.$$id] = stageBuildAssetModule(
4329
5144
  state.projectRoot,
@@ -4331,36 +5146,28 @@ async function renderStaticHandlers(state, rscEnv, registry) {
4331
5146
  exportValue
4332
5147
  );
4333
5148
  const elapsed = (performance.now() - startHandler).toFixed(0);
4334
- console.log(
4335
- `[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`
4336
- );
5149
+ console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
4337
5150
  staticDone++;
4338
5151
  handled = true;
4339
5152
  break;
4340
5153
  }
4341
5154
  } catch (err) {
4342
- if (err.name === "Skip") {
4343
- const elapsed2 = (performance.now() - startHandler).toFixed(0);
4344
- console.log(
4345
- `[rsc-router] SKIP ${name.padEnd(40)} (${elapsed2}ms) - ${err.message}`
4346
- );
4347
- staticSkip++;
4348
- notifyOnError(registry, err, "static", void 0, void 0, true);
4349
- handled = true;
4350
- break;
4351
- }
4352
5155
  const elapsed = (performance.now() - startHandler).toFixed(0);
4353
- console.error(
4354
- `[rsc-router] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`
5156
+ resolvePrerenderError(
5157
+ registry,
5158
+ err,
5159
+ prerenderOnError,
5160
+ name.padEnd(40),
5161
+ elapsed,
5162
+ "static"
4355
5163
  );
4356
- notifyOnError(registry, err, "static");
4357
- throw err;
5164
+ staticSkip++;
5165
+ handled = true;
5166
+ break;
4358
5167
  }
4359
5168
  }
4360
5169
  if (!handled) {
4361
- console.warn(
4362
- `[rsc-router] No router could render static handler "${name}"`
4363
- );
5170
+ console.warn(`[rango] No router could render static handler "${name}"`);
4364
5171
  }
4365
5172
  }
4366
5173
  }
@@ -4371,7 +5178,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
4371
5178
  const staticParts = [`${staticDone} done`];
4372
5179
  if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
4373
5180
  console.log(
4374
- `[rsc-router] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`
5181
+ `[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`
4375
5182
  );
4376
5183
  debug9?.(
4377
5184
  "renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
@@ -4382,8 +5189,82 @@ async function renderStaticHandlers(state, rscEnv, registry) {
4382
5189
  );
4383
5190
  }
4384
5191
 
5192
+ // src/vite/discovery/discovery-errors.ts
5193
+ function indent(text, pad) {
5194
+ return text.split("\n").map((line) => line.length > 0 ? pad + line : line).join("\n");
5195
+ }
5196
+ async function invokeLazyMount(loader, context, errors) {
5197
+ try {
5198
+ await loader();
5199
+ } catch (error) {
5200
+ errors.push({ context, error });
5201
+ }
5202
+ }
5203
+ function isLazyMount(route) {
5204
+ return !!route && route.kind === "lazy" && typeof route.handler === "function";
5205
+ }
5206
+ async function resolveHostRouterHandlers(hostRegistry) {
5207
+ const errors = [];
5208
+ for (const [hostId, entry] of hostRegistry) {
5209
+ for (const route of entry.routes) {
5210
+ if (isLazyMount(route)) {
5211
+ await invokeLazyMount(
5212
+ route.handler,
5213
+ `host "${hostId}" route handler`,
5214
+ errors
5215
+ );
5216
+ }
5217
+ }
5218
+ if (isLazyMount(entry.fallback)) {
5219
+ await invokeLazyMount(
5220
+ entry.fallback.handler,
5221
+ `host "${hostId}" fallback handler`,
5222
+ errors
5223
+ );
5224
+ }
5225
+ }
5226
+ return errors;
5227
+ }
5228
+ function formatNoRoutersError(entryPath, errors) {
5229
+ const base = `[rango] No routers found in registry after importing ${entryPath}`;
5230
+ if (errors.length === 0) {
5231
+ return base;
5232
+ }
5233
+ const formatted = errors.map(({ context, error }) => {
5234
+ const err = error instanceof Error ? error : new Error(String(error));
5235
+ const detail = err.stack ?? err.message;
5236
+ return ` - while resolving ${context}:
5237
+ ${indent(detail, " ")}`;
5238
+ }).join("\n");
5239
+ return `${base}
5240
+
5241
+ ${errors.length} error(s) were caught during host-router discovery and likely explain why no routers were registered:
5242
+ ${formatted}`;
5243
+ }
5244
+ function toCause(errors) {
5245
+ if (errors.length === 0) return void 0;
5246
+ if (errors.length === 1) return errors[0].error;
5247
+ return new AggregateError(
5248
+ errors.map((e) => e.error),
5249
+ "Multiple host-router handlers failed during discovery"
5250
+ );
5251
+ }
5252
+ var DiscoveryError = class _DiscoveryError extends Error {
5253
+ constructor(entryPath, caught) {
5254
+ super(formatNoRoutersError(entryPath, caught));
5255
+ const cause = toCause(caught);
5256
+ if (cause !== void 0) {
5257
+ this.cause = cause;
5258
+ }
5259
+ this.name = "DiscoveryError";
5260
+ this.entryPath = entryPath;
5261
+ this.caught = caught;
5262
+ Object.setPrototypeOf(this, _DiscoveryError.prototype);
5263
+ }
5264
+ };
5265
+
4385
5266
  // src/vite/discovery/discover-routers.ts
4386
- var debug10 = createRangoDebugger("rango:discovery");
5267
+ var debug10 = createRangoDebugger(NS.discovery);
4387
5268
  async function discoverRouters(state, rscEnv) {
4388
5269
  if (!state.resolvedEntryPath) return;
4389
5270
  await timed(
@@ -4398,27 +5279,17 @@ async function discoverRouters(state, rscEnv) {
4398
5279
  );
4399
5280
  let registry = serverMod.RouterRegistry;
4400
5281
  if (!registry || registry.size === 0) {
5282
+ const discoveryErrors = [];
4401
5283
  try {
4402
5284
  const hostRegistry = serverMod.HostRouterRegistry;
4403
5285
  if (hostRegistry && hostRegistry.size > 0) {
4404
5286
  console.log(
4405
- `[rsc-router] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
5287
+ `[rango] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
4406
5288
  );
4407
- for (const [, entry] of hostRegistry) {
4408
- for (const route of entry.routes) {
4409
- if (typeof route.handler === "function") {
4410
- try {
4411
- await route.handler();
4412
- } catch {
4413
- }
4414
- }
4415
- }
4416
- if (entry.fallback && typeof entry.fallback.handler === "function") {
4417
- try {
4418
- await entry.fallback.handler();
4419
- } catch {
4420
- }
4421
- }
5289
+ const handlerErrors = await resolveHostRouterHandlers(hostRegistry);
5290
+ discoveryErrors.push(...handlerErrors);
5291
+ for (const { context, error } of handlerErrors) {
5292
+ debug10?.("caught error while resolving %s: %O", context, error);
4422
5293
  }
4423
5294
  const freshServerMod = await rscEnv.runner.import(
4424
5295
  "@rangojs/router/server"
@@ -4429,12 +5300,11 @@ async function discoverRouters(state, rscEnv) {
4429
5300
  registry = freshRegistry;
4430
5301
  }
4431
5302
  }
4432
- } catch {
5303
+ } catch (error) {
5304
+ discoveryErrors.push({ context: "host-router discovery", error });
4433
5305
  }
4434
5306
  if (!registry || registry.size === 0) {
4435
- throw new Error(
4436
- `[rsc-router] No routers found in registry after importing ${state.resolvedEntryPath}`
4437
- );
5307
+ throw new DiscoveryError(state.resolvedEntryPath, discoveryErrors);
4438
5308
  }
4439
5309
  }
4440
5310
  const buildMod = await timed(
@@ -4462,6 +5332,15 @@ async function discoverRouters(state, rscEnv) {
4462
5332
  let mergedRouteTrailingSlash = {};
4463
5333
  let routerMountIndex = 0;
4464
5334
  const allManifests = [];
5335
+ const clientChunkCtx = state.opts?.clientChunkCtx;
5336
+ const collectClientFallbackRef = clientChunkCtx ? (refKey) => clientChunkCtx.fallbackRefs.add(
5337
+ computeProductionHash(state.projectRoot, refKey)
5338
+ ) : void 0;
5339
+ const collectFromBoundaryNode = (node) => {
5340
+ if (collectClientFallbackRef) {
5341
+ collectFallbackClientRefs(node, collectClientFallbackRef);
5342
+ }
5343
+ };
4465
5344
  const manifestGenStart = debug10 ? performance.now() : 0;
4466
5345
  for (const [id, router] of registry) {
4467
5346
  if (!router.urlpatterns || !generateManifestFull) {
@@ -4470,10 +5349,18 @@ async function discoverRouters(state, rscEnv) {
4470
5349
  const manifest = generateManifestFull(
4471
5350
  router.urlpatterns,
4472
5351
  routerMountIndex,
4473
- router.__basename ? { urlPrefix: router.__basename } : void 0
5352
+ {
5353
+ ...router.__basename ? { urlPrefix: router.__basename } : {},
5354
+ ...collectClientFallbackRef ? { collectClientFallbackRef } : {}
5355
+ }
4474
5356
  );
4475
5357
  routerMountIndex++;
4476
5358
  allManifests.push({ id, manifest });
5359
+ if (collectClientFallbackRef) {
5360
+ collectFromBoundaryNode(router.__defaultErrorBoundary);
5361
+ collectFromBoundaryNode(router.__defaultNotFoundBoundary);
5362
+ collectFromBoundaryNode(router.__notFound);
5363
+ }
4477
5364
  const routeCount = Object.keys(manifest.routeManifest).length;
4478
5365
  const staticRoutes = Object.values(manifest.routeManifest).filter(
4479
5366
  (p) => !p.includes(":") && !p.includes("*")
@@ -4510,21 +5397,17 @@ async function discoverRouters(state, rscEnv) {
4510
5397
  if (manifest.routeTrailingSlash) {
4511
5398
  Object.assign(mergedRouteTrailingSlash, manifest.routeTrailingSlash);
4512
5399
  }
4513
- flattenLeafEntries(
4514
- manifest.prefixTree,
4515
- manifest.routeManifest,
4516
- newMergedPrecomputedEntries
4517
- );
4518
- newPerRouterManifestDataMap.set(id, manifest.routeManifest);
4519
5400
  const routerPrecomputed = [];
4520
5401
  flattenLeafEntries(
4521
5402
  manifest.prefixTree,
4522
5403
  manifest.routeManifest,
4523
5404
  routerPrecomputed
4524
5405
  );
5406
+ newMergedPrecomputedEntries.push(...routerPrecomputed);
5407
+ newPerRouterManifestDataMap.set(id, manifest.routeManifest);
4525
5408
  newPerRouterPrecomputedMap.set(id, routerPrecomputed);
4526
5409
  console.log(
4527
- `[rsc-router] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
5410
+ `[rango] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
4528
5411
  );
4529
5412
  }
4530
5413
  if (registry.size > 1) {
@@ -4533,7 +5416,7 @@ async function discoverRouters(state, rscEnv) {
4533
5416
  );
4534
5417
  if (autoIds.length > 1) {
4535
5418
  console.warn(
4536
- `[rsc-router] WARNING: ${autoIds.length} routers use auto-generated IDs (${autoIds.join(", ")}). In multi-router setups, each createRouter() must have an explicit \`id\` option to ensure per-router manifest data is matched correctly at runtime. Example: createRouter({ id: "site", ... })`
5419
+ `[rango] WARNING: ${autoIds.length} routers use auto-generated IDs (${autoIds.join(", ")}). In multi-router setups, each createRouter() must have an explicit \`id\` option to ensure per-router manifest data is matched correctly at runtime. Example: createRouter({ id: "site", ... })`
4537
5420
  );
4538
5421
  }
4539
5422
  }
@@ -4545,8 +5428,7 @@ async function discoverRouters(state, rscEnv) {
4545
5428
  let newMergedRouteTrie = null;
4546
5429
  const trieStart = debug10 ? performance.now() : 0;
4547
5430
  if (Object.keys(newMergedRouteManifest).length > 0) {
4548
- const buildRouteTrie = buildMod.buildRouteTrie;
4549
- if (buildRouteTrie && mergedRouteAncestry) {
5431
+ if (mergedRouteAncestry) {
4550
5432
  const routeToStaticPrefix = {};
4551
5433
  for (const { manifest } of allManifests) {
4552
5434
  for (const name of Object.keys(manifest.routeManifest)) {
@@ -4578,31 +5460,16 @@ async function discoverRouters(state, rscEnv) {
4578
5460
  newMergedRouteManifest,
4579
5461
  mergedRouteAncestry,
4580
5462
  routeToStaticPrefix,
4581
- Object.keys(mergedRouteTrailingSlash).length > 0 ? mergedRouteTrailingSlash : void 0,
4582
- prerenderRouteNames.size > 0 ? prerenderRouteNames : void 0,
4583
- passthroughRouteNames.size > 0 ? passthroughRouteNames : void 0,
4584
- Object.keys(mergedResponseTypeRoutes).length > 0 ? mergedResponseTypeRoutes : void 0
5463
+ mergedRouteTrailingSlash,
5464
+ prerenderRouteNames,
5465
+ passthroughRouteNames,
5466
+ mergedResponseTypeRoutes
4585
5467
  );
4586
5468
  for (const { id, manifest } of allManifests) {
4587
- if (!manifest._routeAncestry || Object.keys(manifest._routeAncestry).length === 0)
4588
- continue;
4589
- const perRouterStaticPrefix = {};
4590
- for (const name of Object.keys(manifest.routeManifest)) {
4591
- perRouterStaticPrefix[name] = "";
5469
+ const perRouterTrie = buildPerRouterTrie(manifest);
5470
+ if (perRouterTrie) {
5471
+ newPerRouterTrieMap.set(id, perRouterTrie);
4592
5472
  }
4593
- buildRouteToStaticPrefix(manifest.prefixTree, perRouterStaticPrefix);
4594
- const perRouterPrerenderNames = manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : void 0;
4595
- const perRouterPassthroughNames = manifest.passthroughRoutes ? new Set(manifest.passthroughRoutes) : void 0;
4596
- const perRouterTrie = buildRouteTrie(
4597
- manifest.routeManifest,
4598
- manifest._routeAncestry,
4599
- perRouterStaticPrefix,
4600
- manifest.routeTrailingSlash && Object.keys(manifest.routeTrailingSlash).length > 0 ? manifest.routeTrailingSlash : void 0,
4601
- perRouterPrerenderNames && perRouterPrerenderNames.size > 0 ? perRouterPrerenderNames : void 0,
4602
- perRouterPassthroughNames && perRouterPassthroughNames.size > 0 ? perRouterPassthroughNames : void 0,
4603
- manifest.responseTypeRoutes && Object.keys(manifest.responseTypeRoutes).length > 0 ? manifest.responseTypeRoutes : void 0
4604
- );
4605
- newPerRouterTrieMap.set(id, perRouterTrie);
4606
5473
  }
4607
5474
  }
4608
5475
  }
@@ -4623,7 +5490,7 @@ async function discoverRouters(state, rscEnv) {
4623
5490
  }
4624
5491
 
4625
5492
  // src/vite/discovery/route-types-writer.ts
4626
- import { dirname as dirname3, basename, join as join2, resolve as resolve6 } from "node:path";
5493
+ import { dirname as dirname3, join as join3, resolve as resolve6 } from "node:path";
4627
5494
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
4628
5495
  function filterUserNamedRoutes(manifest) {
4629
5496
  const filtered = {};
@@ -4634,39 +5501,20 @@ function filterUserNamedRoutes(manifest) {
4634
5501
  }
4635
5502
  return filtered;
4636
5503
  }
5504
+ function writeGenFileIfChanged(state, outPath, source, opts) {
5505
+ const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
5506
+ if (existing === source) return;
5507
+ markSelfGenWrite(state, outPath, source);
5508
+ writeFileSync3(outPath, source);
5509
+ if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
5510
+ }
4637
5511
  function writeCombinedRouteTypesWithTracking(state, opts) {
4638
5512
  const routerFiles = state.cachedRouterFiles ?? findRouterFiles(state.projectRoot, state.scanFilter);
4639
5513
  state.cachedRouterFiles = routerFiles;
4640
- const preContent = /* @__PURE__ */ new Map();
4641
- for (const routerFilePath of routerFiles) {
4642
- const routerDir = dirname3(routerFilePath);
4643
- const routerBasename = basename(routerFilePath).replace(
4644
- /\.(tsx?|jsx?)$/,
4645
- ""
4646
- );
4647
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4648
- try {
4649
- preContent.set(outPath, readFileSync4(outPath, "utf-8"));
4650
- } catch {
4651
- }
4652
- }
4653
- writeCombinedRouteTypes(state.projectRoot, routerFiles, opts);
4654
- for (const routerFilePath of routerFiles) {
4655
- const routerDir = dirname3(routerFilePath);
4656
- const routerBasename = basename(routerFilePath).replace(
4657
- /\.(tsx?|jsx?)$/,
4658
- ""
4659
- );
4660
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4661
- if (!existsSync5(outPath)) continue;
4662
- try {
4663
- const content = readFileSync4(outPath, "utf-8");
4664
- if (content !== preContent.get(outPath)) {
4665
- markSelfGenWrite(state, outPath, content);
4666
- }
4667
- } catch {
4668
- }
4669
- }
5514
+ writeCombinedRouteTypes(state.projectRoot, routerFiles, {
5515
+ ...opts,
5516
+ onWrite: (outPath, content) => markSelfGenWrite(state, outPath, content)
5517
+ });
4670
5518
  }
4671
5519
  function writeRouteTypesFiles(state) {
4672
5520
  if (state.perRouterManifests.length === 0) return;
@@ -4674,11 +5522,11 @@ function writeRouteTypesFiles(state) {
4674
5522
  const entryDir = dirname3(
4675
5523
  resolve6(state.projectRoot, state.resolvedEntryPath)
4676
5524
  );
4677
- const oldCombinedPath = join2(entryDir, "named-routes.gen.ts");
5525
+ const oldCombinedPath = join3(entryDir, "named-routes.gen.ts");
4678
5526
  if (existsSync5(oldCombinedPath)) {
4679
5527
  unlinkSync2(oldCombinedPath);
4680
5528
  console.log(
4681
- `[rsc-router] Removed stale combined route types: ${oldCombinedPath}`
5529
+ `[rango] Removed stale combined route types: ${oldCombinedPath}`
4682
5530
  );
4683
5531
  }
4684
5532
  } catch {
@@ -4692,39 +5540,23 @@ function writeRouteTypesFiles(state) {
4692
5540
  if (!sourceFile) continue;
4693
5541
  if (sourceFile.includes("node_modules")) {
4694
5542
  throw new Error(
4695
- `[rsc-router] Router "${id}" has sourceFile inside node_modules: ${sourceFile}
5543
+ `[rango] Router "${id}" has sourceFile inside node_modules: ${sourceFile}
4696
5544
  This means createRouter() stack trace parsing matched a Vite internal frame.
4697
5545
  Set an explicit \`id\` on createRouter() or check the call site.`
4698
5546
  );
4699
5547
  }
4700
- const routerDir = dirname3(sourceFile);
4701
- const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
4702
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
5548
+ const outPath = genFileTsPath(sourceFile);
4703
5549
  const userRoutes = filterUserNamedRoutes(routeManifest);
4704
- let effectiveSearchSchemas = routeSearchSchemas;
4705
- if ((!effectiveSearchSchemas || Object.keys(effectiveSearchSchemas).length === 0) && sourceFile) {
4706
- const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
4707
- if (Object.keys(staticParsed.searchSchemas).length > 0) {
4708
- const filtered = {};
4709
- for (const name of Object.keys(userRoutes)) {
4710
- const schema = staticParsed.searchSchemas[name];
4711
- if (schema) filtered[name] = schema;
4712
- }
4713
- if (Object.keys(filtered).length > 0) {
4714
- effectiveSearchSchemas = filtered;
4715
- }
4716
- }
4717
- }
5550
+ const effectiveSearchSchemas = resolveSearchSchemas(
5551
+ Object.keys(userRoutes),
5552
+ routeSearchSchemas,
5553
+ sourceFile
5554
+ );
4718
5555
  const source = generateRouteTypesSource(
4719
5556
  userRoutes,
4720
5557
  effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
4721
5558
  );
4722
- const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
4723
- if (existing !== source) {
4724
- markSelfGenWrite(state, outPath, source);
4725
- writeFileSync3(outPath, source);
4726
- console.log(`[rsc-router] Generated route types -> ${outPath}`);
4727
- }
5559
+ writeGenFileIfChanged(state, outPath, source, { log: true });
4728
5560
  }
4729
5561
  }
4730
5562
  function supplementGenFilesWithRuntimeRoutes(state) {
@@ -4762,23 +5594,17 @@ function supplementGenFilesWithRuntimeRoutes(state) {
4762
5594
  }
4763
5595
  }
4764
5596
  }
4765
- const routerDir = dirname3(sourceFile);
4766
- const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
4767
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
5597
+ const outPath = genFileTsPath(sourceFile);
4768
5598
  const source = generateRouteTypesSource(
4769
5599
  mergedRoutes,
4770
5600
  Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
4771
5601
  );
4772
- const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
4773
- if (existing !== source) {
4774
- markSelfGenWrite(state, outPath, source);
4775
- writeFileSync3(outPath, source);
4776
- }
5602
+ writeGenFileIfChanged(state, outPath, source);
4777
5603
  }
4778
5604
  }
4779
5605
 
4780
5606
  // src/vite/discovery/virtual-module-codegen.ts
4781
- import { dirname as dirname4, basename as basename2, join as join3 } from "node:path";
5607
+ import { dirname as dirname4, basename, join as join4 } from "node:path";
4782
5608
  function generateRoutesManifestModule(state) {
4783
5609
  const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
4784
5610
  if (hasManifest) {
@@ -4789,11 +5615,11 @@ function generateRoutesManifestModule(state) {
4789
5615
  for (const entry of state.perRouterManifests) {
4790
5616
  if (entry.sourceFile) {
4791
5617
  const routerDir = dirname4(entry.sourceFile);
4792
- const routerBasename = basename2(entry.sourceFile).replace(
5618
+ const routerBasename = basename(entry.sourceFile).replace(
4793
5619
  /\.(tsx?|jsx?)$/,
4794
5620
  ""
4795
5621
  );
4796
- const genPath = join3(
5622
+ const genPath = join4(
4797
5623
  routerDir,
4798
5624
  `${routerBasename}.named-routes.gen.js`
4799
5625
  ).replaceAll("\\", "/");
@@ -4810,7 +5636,7 @@ function generateRoutesManifestModule(state) {
4810
5636
  }
4811
5637
  }
4812
5638
  const lines = [
4813
- `import { setCachedManifest, setPrecomputedEntries, setRouteTrie, setRouterManifest, registerRouterManifestLoader, clearAllRouterData } from "@rangojs/router/server";`,
5639
+ `import { setCachedManifest, setRouterManifest, registerRouterManifestLoader, clearAllRouterData } from "@rangojs/router/server";`,
4814
5640
  ...genFileImports,
4815
5641
  // Clear stale per-router cached data (manifest, trie, precomputed entries)
4816
5642
  // before re-populating. In Cloudflare dev mode, program reloads re-evaluate
@@ -4846,18 +5672,6 @@ function generateRoutesManifestModule(state) {
4846
5672
  );
4847
5673
  }
4848
5674
  }
4849
- if (state.isBuildMode) {
4850
- if (state.mergedPrecomputedEntries && state.mergedPrecomputedEntries.length > 0) {
4851
- lines.push(
4852
- `setPrecomputedEntries(${jsonParseExpression(state.mergedPrecomputedEntries)});`
4853
- );
4854
- }
4855
- if (state.mergedRouteTrie) {
4856
- lines.push(
4857
- `setRouteTrie(${jsonParseExpression(state.mergedRouteTrie)});`
4858
- );
4859
- }
4860
- }
4861
5675
  for (const routerId of state.perRouterManifestDataMap.keys()) {
4862
5676
  lines.push(
4863
5677
  `registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`
@@ -4886,11 +5700,11 @@ function generatePerRouterModule(state, routerId) {
4886
5700
  const lines = [];
4887
5701
  if (routerEntry?.sourceFile) {
4888
5702
  const routerDir = dirname4(routerEntry.sourceFile);
4889
- const routerBasename = basename2(routerEntry.sourceFile).replace(
5703
+ const routerBasename = basename(routerEntry.sourceFile).replace(
4890
5704
  /\.(tsx?|jsx?)$/,
4891
5705
  ""
4892
5706
  );
4893
- const genPath = join3(
5707
+ const genPath = join4(
4894
5708
  routerDir,
4895
5709
  `${routerBasename}.named-routes.gen.js`
4896
5710
  ).replaceAll("\\", "/");
@@ -4913,7 +5727,7 @@ function generatePerRouterModule(state, routerId) {
4913
5727
  `export const precomputedEntries = ${jsonParseExpression(entries)};`
4914
5728
  );
4915
5729
  }
4916
- return lines.join("\n") || "// empty router manifest";
5730
+ return lines.join("\n") || "";
4917
5731
  }
4918
5732
 
4919
5733
  // src/vite/discovery/bundle-postprocess.ts
@@ -4957,12 +5771,12 @@ function postprocessBundle(state) {
4957
5771
  writeFileSync4(chunkPath, result.code);
4958
5772
  const savedKB = (result.savedBytes / 1024).toFixed(1);
4959
5773
  console.log(
4960
- `[rsc-router] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
5774
+ `[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
4961
5775
  );
4962
5776
  }
4963
5777
  } catch (replaceErr) {
4964
5778
  console.warn(
4965
- `[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
5779
+ `[rango] Failed to evict ${target.label}: ${replaceErr.message}`
4966
5780
  );
4967
5781
  }
4968
5782
  }
@@ -4984,7 +5798,7 @@ function postprocessBundle(state) {
4984
5798
  manifestMap[key] = `./assets/${assetFileName}`;
4985
5799
  }
4986
5800
  const manifestCode = [
4987
- `const m=JSON.parse('${JSON.stringify(manifestMap).replace(/'/g, "\\'")}');`,
5801
+ `const m=${jsonParseExpression(manifestMap)};`,
4988
5802
  `export function loadPrerenderAsset(s){return import(s)}`,
4989
5803
  `export default m;`,
4990
5804
  ""
@@ -5000,11 +5814,11 @@ function postprocessBundle(state) {
5000
5814
  writeFileSync4(rscEntryPath, injection + rscCode);
5001
5815
  const totalKB = (totalBytes / 1024).toFixed(1);
5002
5816
  console.log(
5003
- `[rsc-router] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
5817
+ `[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
5004
5818
  );
5005
5819
  } catch (err) {
5006
5820
  throw new Error(
5007
- `[rsc-router] Failed to write prerender assets: ${err.message}`
5821
+ `[rango] Failed to write prerender assets: ${err.message}`
5008
5822
  );
5009
5823
  }
5010
5824
  }
@@ -5038,22 +5852,147 @@ function postprocessBundle(state) {
5038
5852
  writeFileSync4(rscEntryPath, injection + rscCode);
5039
5853
  const totalKB = (totalBytes / 1024).toFixed(1);
5040
5854
  console.log(
5041
- `[rsc-router] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
5855
+ `[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
5042
5856
  );
5043
5857
  } catch (err) {
5044
5858
  throw new Error(
5045
- `[rsc-router] Failed to write static assets: ${err.message}`
5859
+ `[rango] Failed to write static assets: ${err.message}`
5046
5860
  );
5047
5861
  }
5048
5862
  }
5049
5863
  }
5050
5864
  }
5051
5865
 
5866
+ // src/vite/discovery/gate-state.ts
5867
+ function createDiscoveryGate(s, debug11) {
5868
+ let gatePending = false;
5869
+ let gateResolver = () => {
5870
+ };
5871
+ let inProgress = false;
5872
+ let queued = false;
5873
+ let pendingEvents = false;
5874
+ const beginGate = () => {
5875
+ if (gatePending) return;
5876
+ s.discoveryDone = new Promise((resolve10) => {
5877
+ gateResolver = resolve10;
5878
+ });
5879
+ gatePending = true;
5880
+ };
5881
+ const resolveGate = () => {
5882
+ if (!gatePending) return;
5883
+ if (inProgress || queued || pendingEvents) {
5884
+ debug11?.(
5885
+ "hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
5886
+ inProgress,
5887
+ queued,
5888
+ pendingEvents
5889
+ );
5890
+ return;
5891
+ }
5892
+ gatePending = false;
5893
+ debug11?.("hmr: discoveryDone resolved");
5894
+ gateResolver();
5895
+ };
5896
+ const noteRouteEvent = () => {
5897
+ pendingEvents = true;
5898
+ beginGate();
5899
+ };
5900
+ const runRefreshCycle = async (work) => {
5901
+ if (inProgress) {
5902
+ queued = true;
5903
+ debug11?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
5904
+ return;
5905
+ }
5906
+ pendingEvents = false;
5907
+ inProgress = true;
5908
+ try {
5909
+ await work();
5910
+ } finally {
5911
+ inProgress = false;
5912
+ if (queued) {
5913
+ queued = false;
5914
+ debug11?.("hmr: consuming queued rediscovery");
5915
+ runRefreshCycle(work).catch((err) => {
5916
+ debug11?.(
5917
+ "hmr: queued cycle rejected \u2014 releasing gate (%s)",
5918
+ err instanceof Error ? err.message : String(err)
5919
+ );
5920
+ resolveGate();
5921
+ });
5922
+ } else if (pendingEvents) {
5923
+ debug11?.(
5924
+ "hmr: holding gate for pending events (debounce not yet fired)"
5925
+ );
5926
+ } else {
5927
+ resolveGate();
5928
+ }
5929
+ }
5930
+ };
5931
+ return {
5932
+ beginGate,
5933
+ resolveGate,
5934
+ noteRouteEvent,
5935
+ runRefreshCycle,
5936
+ state: () => ({ gatePending, inProgress, queued, pendingEvents })
5937
+ };
5938
+ }
5939
+
5940
+ // src/vite/utils/forward-user-plugins.ts
5941
+ function isDenied(name) {
5942
+ return name.startsWith("vite:") || name === "rsc" || name.startsWith("rsc:") || name.startsWith("@rangojs/router") || name.startsWith("@cloudflare/vite-plugin") || name.startsWith("vite-plugin-cloudflare");
5943
+ }
5944
+ function hasResolutionHooks(p) {
5945
+ return Boolean(p.resolveId || p.load);
5946
+ }
5947
+ function stripToResolutionHooks(p) {
5948
+ const stripped = { name: p.name };
5949
+ if (p.enforce) stripped.enforce = p.enforce;
5950
+ if (p.applyToEnvironment)
5951
+ stripped.applyToEnvironment = p.applyToEnvironment;
5952
+ if (p.resolveId) stripped.resolveId = p.resolveId;
5953
+ if (p.load) stripped.load = p.load;
5954
+ return stripped;
5955
+ }
5956
+ function selectForwardableResolvePlugins(plugins) {
5957
+ if (!plugins) return [];
5958
+ const forwarded = [];
5959
+ for (const p of plugins) {
5960
+ const name = p?.name;
5961
+ if (!name || isDenied(name)) continue;
5962
+ if (!hasResolutionHooks(p)) continue;
5963
+ forwarded.push(stripToResolutionHooks(p));
5964
+ }
5965
+ return forwarded;
5966
+ }
5967
+ function pickForwardedRunnerConfig(config) {
5968
+ const r = config.resolve ?? {};
5969
+ const resolve10 = {};
5970
+ if (r.alias !== void 0) resolve10.alias = r.alias;
5971
+ if (r.dedupe !== void 0) resolve10.dedupe = r.dedupe;
5972
+ if (r.conditions !== void 0) resolve10.conditions = r.conditions;
5973
+ if (r.mainFields !== void 0) resolve10.mainFields = r.mainFields;
5974
+ if (r.extensions !== void 0) resolve10.extensions = r.extensions;
5975
+ if (r.preserveSymlinks !== void 0)
5976
+ resolve10.preserveSymlinks = r.preserveSymlinks;
5977
+ if (r.tsconfigPaths !== void 0) resolve10.tsconfigPaths = r.tsconfigPaths;
5978
+ const userOxc = config.oxc;
5979
+ const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
5980
+ const oxc = userOxc && typeof userOxc === "object" ? {
5981
+ ...userOxc,
5982
+ jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
5983
+ } : { jsx: { runtime: "automatic", importSource: "react" } };
5984
+ return {
5985
+ resolve: resolve10,
5986
+ define: config.define,
5987
+ oxc
5988
+ };
5989
+ }
5990
+
5052
5991
  // src/vite/router-discovery.ts
5053
- var debugDiscovery = createRangoDebugger("rango:discovery");
5054
- var debugRoutes = createRangoDebugger("rango:routes");
5055
- var debugBuild = createRangoDebugger("rango:build");
5056
- var debugDev = createRangoDebugger("rango:dev");
5992
+ var debugDiscovery = createRangoDebugger(NS.discovery);
5993
+ var debugRoutes = createRangoDebugger(NS.routes);
5994
+ var debugBuild = createRangoDebugger(NS.build);
5995
+ var debugDev = createRangoDebugger(NS.dev);
5057
5996
  var loaderHookRegistered = false;
5058
5997
  function ensureCloudflareProtocolLoaderRegistered() {
5059
5998
  if (loaderHookRegistered) return;
@@ -5064,21 +6003,29 @@ function ensureCloudflareProtocolLoaderRegistered() {
5064
6003
  );
5065
6004
  } catch (err) {
5066
6005
  console.warn(
5067
- `[rsc-router] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
6006
+ `[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
5068
6007
  );
5069
6008
  }
5070
6009
  }
5071
6010
  async function createTempRscServer(state, options = {}) {
5072
6011
  ensureCloudflareProtocolLoaderRegistered();
5073
6012
  const { default: rsc } = await import("@vitejs/plugin-rsc");
6013
+ const runnerConfig = state.userRunnerConfig;
6014
+ const resolveConfig = runnerConfig?.resolve ?? {
6015
+ alias: state.userResolveAlias
6016
+ };
6017
+ const oxcConfig = runnerConfig?.oxc ?? {
6018
+ jsx: { runtime: "automatic", importSource: "react" }
6019
+ };
5074
6020
  return createViteServer({
5075
6021
  root: state.projectRoot,
5076
6022
  configFile: false,
5077
6023
  server: { middlewareMode: true },
5078
6024
  appType: "custom",
5079
6025
  logLevel: "silent",
5080
- resolve: { alias: state.userResolveAlias },
5081
- esbuild: { jsx: "automatic", jsxImportSource: "react" },
6026
+ resolve: resolveConfig,
6027
+ ...runnerConfig?.define ? { define: runnerConfig.define } : {},
6028
+ oxc: oxcConfig,
5082
6029
  ...options.cacheDir && { cacheDir: options.cacheDir },
5083
6030
  plugins: [
5084
6031
  rsc({
@@ -5096,7 +6043,11 @@ async function createTempRscServer(state, options = {}) {
5096
6043
  // Dev prerender must use dev-mode IDs (path-based) to match the workerd
5097
6044
  // runtime. forceBuild produces hashed IDs for production bundle consistency.
5098
6045
  exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
5099
- exposeRouterId()
6046
+ exposeRouterId(),
6047
+ // Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
6048
+ // to resolveId/load and placed last so framework resolution runs first;
6049
+ // Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
6050
+ ...state.userResolvePlugins
5100
6051
  ]
5101
6052
  });
5102
6053
  }
@@ -5105,7 +6056,7 @@ async function resolveBuildEnv(option, factoryCtx) {
5105
6056
  if (option === "auto") {
5106
6057
  if (factoryCtx.preset !== "cloudflare") {
5107
6058
  throw new Error(
5108
- '[rsc-router] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
6059
+ '[rango] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
5109
6060
  );
5110
6061
  }
5111
6062
  try {
@@ -5121,7 +6072,7 @@ async function resolveBuildEnv(option, factoryCtx) {
5121
6072
  };
5122
6073
  } catch (err) {
5123
6074
  throw new Error(
5124
- `[rsc-router] buildEnv: "auto" requires wrangler to be installed.
6075
+ `[rango] buildEnv: "auto" requires wrangler to be installed.
5125
6076
  Install it with: pnpm add -D wrangler
5126
6077
  ${err.message}`
5127
6078
  );
@@ -5152,7 +6103,7 @@ async function releaseBuildEnv(s) {
5152
6103
  try {
5153
6104
  await s.buildEnvDispose();
5154
6105
  } catch (err) {
5155
- console.warn(`[rsc-router] buildEnv dispose failed: ${err.message}`);
6106
+ console.warn(`[rango] buildEnv dispose failed: ${err.message}`);
5156
6107
  }
5157
6108
  s.buildEnvDispose = null;
5158
6109
  }
@@ -5165,31 +6116,31 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
5165
6116
  let viteMode = "production";
5166
6117
  return {
5167
6118
  name: "@rangojs/router:discovery",
5168
- config() {
5169
- const config = {
5170
- define: {
5171
- __RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG)
5172
- }
5173
- };
5174
- return config;
6119
+ // Make INTERNAL_RANGO_DEBUG reach the CLIENT debug logs by just setting the
6120
+ // env var. See injectClientDebugFlag: bakes the resolved flag into the
6121
+ // internal-debug module so FE debug no longer depends on Vite delivering the
6122
+ // `__RANGO_DEBUG__` define to the client (which it does only as an injected
6123
+ // global whose presence varies across consumer setups). Runs in dev and build.
6124
+ transform(_code, id) {
6125
+ return injectClientDebugFlag(id);
5175
6126
  },
5176
6127
  configResolved(config) {
5177
6128
  s.projectRoot = config.root;
6129
+ s.scanFilter = opts?.discovery ? createScanFilter(s.projectRoot, opts.discovery) : void 0;
5178
6130
  s.isBuildMode = config.command === "build";
5179
6131
  viteCommand = config.command;
5180
6132
  viteMode = config.mode;
5181
6133
  s.userResolveAlias = config.resolve.alias;
6134
+ s.userRunnerConfig = pickForwardedRunnerConfig(config);
6135
+ s.userResolvePlugins = selectForwardableResolvePlugins(
6136
+ config.plugins
6137
+ );
5182
6138
  if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
5183
6139
  s.resolvedEntryPath = opts.routerPathRef.path;
5184
6140
  }
5185
6141
  if (!s.resolvedEntryPath) {
5186
- const rscEnvConfig = config.environments?.["rsc"];
5187
- const entries = rscEnvConfig?.optimizeDeps?.entries;
5188
- if (typeof entries === "string") {
5189
- s.resolvedEntryPath = entries;
5190
- } else if (Array.isArray(entries) && entries.length > 0) {
5191
- s.resolvedEntryPath = entries[0];
5192
- }
6142
+ const entry = resolveRscEntryFromConfig(config);
6143
+ if (entry) s.resolvedEntryPath = entry;
5193
6144
  }
5194
6145
  if (opts?.staticRouteTypesGeneration !== false) {
5195
6146
  s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
@@ -5213,6 +6164,9 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
5213
6164
  const discoveryPromise = new Promise((resolve10) => {
5214
6165
  resolveDiscovery = resolve10;
5215
6166
  });
6167
+ const gate = createDiscoveryGate(s, debugDiscovery);
6168
+ const beginDiscoveryGate = gate.beginGate;
6169
+ const resolveDiscoveryGate = gate.resolveGate;
5216
6170
  const getDevServerOrigin = () => server.resolvedUrls?.local?.[0]?.replace(/\/$/, "") || `http://localhost:${server.config.server.port || 5173}`;
5217
6171
  let prerenderTempServer = null;
5218
6172
  let prerenderNodeRegistry = null;
@@ -5225,35 +6179,155 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
5225
6179
  releaseBuildEnv(s).catch(() => {
5226
6180
  });
5227
6181
  });
6182
+ async function importEntryAndRegistry(tempRscEnv) {
6183
+ const flagAlreadySet = !!globalThis.__rscRouterDiscoveryActive;
6184
+ if (!flagAlreadySet) {
6185
+ globalThis.__rscRouterDiscoveryActive = true;
6186
+ }
6187
+ try {
6188
+ debugDiscovery?.(
6189
+ "importEntryAndRegistry: importing entry (flag=%s)",
6190
+ globalThis.__rscRouterDiscoveryActive ?? false
6191
+ );
6192
+ await tempRscEnv.runner.import(s.resolvedEntryPath);
6193
+ debugDiscovery?.(
6194
+ "importEntryAndRegistry: entry import OK, fetching RouterRegistry"
6195
+ );
6196
+ const serverMod = await tempRscEnv.runner.import(
6197
+ "@rangojs/router/server"
6198
+ );
6199
+ prerenderNodeRegistry = serverMod.RouterRegistry;
6200
+ debugDiscovery?.(
6201
+ "importEntryAndRegistry: registry size=%d",
6202
+ prerenderNodeRegistry?.size ?? 0
6203
+ );
6204
+ } finally {
6205
+ if (!flagAlreadySet) {
6206
+ delete globalThis.__rscRouterDiscoveryActive;
6207
+ debugDiscovery?.(
6208
+ "importEntryAndRegistry: cleared __rscRouterDiscoveryActive"
6209
+ );
6210
+ }
6211
+ }
6212
+ }
5228
6213
  async function getOrCreateTempServer() {
5229
- if (prerenderNodeRegistry) {
5230
- return prerenderTempServer.environments?.rsc ?? null;
6214
+ if (prerenderTempServer) {
6215
+ const existingEnv = prerenderTempServer.environments?.rsc;
6216
+ if (existingEnv?.runner) {
6217
+ if (prerenderNodeRegistry) {
6218
+ debugDiscovery?.(
6219
+ "getOrCreateTempServer: cached temp runner reused"
6220
+ );
6221
+ return existingEnv;
6222
+ }
6223
+ debugDiscovery?.(
6224
+ "getOrCreateTempServer: server alive but registry missing \u2014 re-importing"
6225
+ );
6226
+ try {
6227
+ await importEntryAndRegistry(existingEnv);
6228
+ return existingEnv;
6229
+ } catch (err) {
6230
+ debugDiscovery?.(
6231
+ "getOrCreateTempServer: reuse import failed (%s) \u2014 closing orphan and creating fresh",
6232
+ err?.message ?? String(err)
6233
+ );
6234
+ await prerenderTempServer.close().catch(() => {
6235
+ });
6236
+ prerenderTempServer = null;
6237
+ prerenderNodeRegistry = null;
6238
+ }
6239
+ } else {
6240
+ debugDiscovery?.(
6241
+ "getOrCreateTempServer: existing server has no rsc.runner \u2014 closing and recreating"
6242
+ );
6243
+ await prerenderTempServer.close().catch(() => {
6244
+ });
6245
+ prerenderTempServer = null;
6246
+ prerenderNodeRegistry = null;
6247
+ }
5231
6248
  }
6249
+ debugDiscovery?.(
6250
+ "getOrCreateTempServer: creating new temp server, entry=%s",
6251
+ s.resolvedEntryPath ?? "(unset)"
6252
+ );
5232
6253
  try {
5233
6254
  prerenderTempServer = await createTempRscServer(s, {
5234
6255
  cacheDir: "node_modules/.vite_prerender"
5235
6256
  });
5236
6257
  const tempRscEnv = prerenderTempServer.environments?.rsc;
5237
6258
  if (tempRscEnv?.runner) {
5238
- await tempRscEnv.runner.import(s.resolvedEntryPath);
5239
- const serverMod = await tempRscEnv.runner.import(
5240
- "@rangojs/router/server"
5241
- );
5242
- prerenderNodeRegistry = serverMod.RouterRegistry;
6259
+ await importEntryAndRegistry(tempRscEnv);
5243
6260
  return tempRscEnv;
5244
6261
  }
6262
+ debugDiscovery?.(
6263
+ "getOrCreateTempServer: tempRscEnv.runner unavailable"
6264
+ );
5245
6265
  } catch (err) {
5246
- console.warn(
5247
- `[rsc-router] Failed to create temp runner: ${err.message}`
6266
+ debugDiscovery?.(
6267
+ "getOrCreateTempServer: FAILED message=%s",
6268
+ err.message
5248
6269
  );
6270
+ console.warn(`[rango] Failed to create temp runner: ${err.message}`);
5249
6271
  }
5250
6272
  return null;
5251
6273
  }
6274
+ async function clearTempRegistries(tempRscEnv) {
6275
+ try {
6276
+ const serverMod = await tempRscEnv.runner.import(
6277
+ "@rangojs/router/server"
6278
+ );
6279
+ if (typeof serverMod?.RouterRegistry?.clear === "function") {
6280
+ serverMod.RouterRegistry.clear();
6281
+ }
6282
+ if (typeof serverMod?.HostRouterRegistry?.clear === "function") {
6283
+ serverMod.HostRouterRegistry.clear();
6284
+ }
6285
+ debugDiscovery?.(
6286
+ "clearTempRegistries: cleared RouterRegistry + HostRouterRegistry"
6287
+ );
6288
+ } catch (err) {
6289
+ debugDiscovery?.(
6290
+ "clearTempRegistries: import @rangojs/router/server failed (%s)",
6291
+ err?.message ?? String(err)
6292
+ );
6293
+ }
6294
+ }
6295
+ async function refreshTempRscEnv() {
6296
+ let tempRscEnv = await getOrCreateTempServer();
6297
+ if (!tempRscEnv) return null;
6298
+ const envGraph = tempRscEnv.moduleGraph;
6299
+ const serverGraph = prerenderTempServer?.moduleGraph;
6300
+ const target = envGraph?.invalidateAll ? envGraph : serverGraph?.invalidateAll ? serverGraph : null;
6301
+ if (!target) {
6302
+ debugDiscovery?.(
6303
+ "refreshTempRscEnv: invalidateAll unavailable on env+server graphs, falling back to close+recreate"
6304
+ );
6305
+ if (prerenderTempServer) {
6306
+ await prerenderTempServer.close().catch(() => {
6307
+ });
6308
+ prerenderTempServer = null;
6309
+ prerenderNodeRegistry = null;
6310
+ }
6311
+ return await getOrCreateTempServer();
6312
+ }
6313
+ debugDiscovery?.(
6314
+ "refreshTempRscEnv: invalidating module graph (%s)",
6315
+ envGraph?.invalidateAll ? "env" : "server"
6316
+ );
6317
+ target.invalidateAll();
6318
+ prerenderNodeRegistry = null;
6319
+ await clearTempRegistries(tempRscEnv);
6320
+ await importEntryAndRegistry(tempRscEnv);
6321
+ return tempRscEnv;
6322
+ }
5252
6323
  const discover = async () => {
5253
6324
  const discoverStart = performance.now();
5254
6325
  const rscEnv = server.environments?.rsc;
5255
6326
  if (!rscEnv?.runner) {
5256
- debugDiscovery?.("dev: no rsc runner (cloudflare path)");
6327
+ debugDiscovery?.(
6328
+ "dev: cloudflare path start, __rscRouterDiscoveryActive=%s",
6329
+ globalThis.__rscRouterDiscoveryActive ?? false
6330
+ );
5257
6331
  s.devServerOrigin = getDevServerOrigin();
5258
6332
  try {
5259
6333
  await timed(
@@ -5280,7 +6354,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
5280
6354
  }
5281
6355
  } catch (err) {
5282
6356
  console.warn(
5283
- `[rsc-router] Cloudflare dev discovery failed: ${err.message}
6357
+ `[rango] Cloudflare dev discovery failed: ${err.message}
5284
6358
  ${err.stack}`
5285
6359
  );
5286
6360
  }
@@ -5324,7 +6398,7 @@ ${err.stack}`
5324
6398
  );
5325
6399
  } catch (err) {
5326
6400
  console.warn(
5327
- `[rsc-router] Router discovery failed: ${err.message}
6401
+ `[rango] Router discovery failed: ${err.message}
5328
6402
  ${err.stack}`
5329
6403
  );
5330
6404
  } finally {
@@ -5335,9 +6409,11 @@ ${err.stack}`
5335
6409
  resolveDiscovery();
5336
6410
  }
5337
6411
  };
5338
- s.discoveryDone = new Promise((resolve10) => {
5339
- setTimeout(() => discover().then(resolve10, resolve10), 0);
5340
- });
6412
+ beginDiscoveryGate();
6413
+ setTimeout(
6414
+ () => discover().then(resolveDiscoveryGate, resolveDiscoveryGate),
6415
+ 0
6416
+ );
5341
6417
  let mainRegistry = null;
5342
6418
  const propagateDiscoveryState = async (rscEnv) => {
5343
6419
  const serverMod = await rscEnv.runner.import("@rangojs/router/server");
@@ -5355,20 +6431,15 @@ ${err.stack}`
5355
6431
  if (s.mergedRouteTrie && serverMod.setRouteTrie) {
5356
6432
  serverMod.setRouteTrie(s.mergedRouteTrie);
5357
6433
  }
5358
- if (serverMod.setRouterManifest) {
5359
- for (const [routerId, manifest] of s.perRouterManifestDataMap) {
5360
- serverMod.setRouterManifest(routerId, manifest);
5361
- }
5362
- }
5363
- if (serverMod.setRouterTrie) {
5364
- for (const [routerId, trie] of s.perRouterTrieMap) {
5365
- serverMod.setRouterTrie(routerId, trie);
5366
- }
5367
- }
5368
- if (serverMod.setRouterPrecomputedEntries) {
5369
- for (const [routerId, entries] of s.perRouterPrecomputedMap) {
5370
- serverMod.setRouterPrecomputedEntries(routerId, entries);
5371
- }
6434
+ const perRouterSetters = [
6435
+ [s.perRouterManifestDataMap, "setRouterManifest"],
6436
+ [s.perRouterTrieMap, "setRouterTrie"],
6437
+ [s.perRouterPrecomputedMap, "setRouterPrecomputedEntries"]
6438
+ ];
6439
+ for (const [map, fn] of perRouterSetters) {
6440
+ const setter = serverMod[fn];
6441
+ if (typeof setter !== "function") continue;
6442
+ for (const [routerId, value] of map) setter(routerId, value);
5372
6443
  }
5373
6444
  };
5374
6445
  server.middlewares.use("/__rsc_prerender", async (req, res) => {
@@ -5402,7 +6473,7 @@ ${err.stack}`
5402
6473
  registry = serverMod.RouterRegistry ?? null;
5403
6474
  } catch (err) {
5404
6475
  console.warn(
5405
- `[rsc-router] Dev prerender module refresh failed: ${err.message}`
6476
+ `[rango] Dev prerender module refresh failed: ${err.message}`
5406
6477
  );
5407
6478
  res.statusCode = 500;
5408
6479
  res.end(`Prerender handler error: ${err.message}`);
@@ -5447,10 +6518,9 @@ ${err.stack}`
5447
6518
  if (wantIntercept && result.interceptSegments?.length) {
5448
6519
  payload = {
5449
6520
  segments: [...result.segments, ...result.interceptSegments],
5450
- handles: {
5451
- ...result.handles,
5452
- ...result.interceptHandles || {}
5453
- }
6521
+ // Pre-encoded MERGED handle string from the producer (handles are
6522
+ // Flight-encoded so Promise/ReactNode values survive the wire).
6523
+ handles: result.interceptHandles ?? ""
5454
6524
  };
5455
6525
  } else {
5456
6526
  payload = { segments: result.segments, handles: result.handles };
@@ -5459,9 +6529,11 @@ ${err.stack}`
5459
6529
  logResult(200, `match ${result.routeName}`);
5460
6530
  return;
5461
6531
  } catch (err) {
5462
- console.warn(
5463
- `[rsc-router] Dev prerender failed for ${pathname}: ${err.message}`
5464
- );
6532
+ if (err?.name !== "Skip") {
6533
+ console.warn(
6534
+ `[rango] Dev prerender error for ${pathname} (serving live instead): ${err.message}`
6535
+ );
6536
+ }
5465
6537
  }
5466
6538
  }
5467
6539
  res.statusCode = 404;
@@ -5486,38 +6558,96 @@ ${err.stack}`
5486
6558
  return true;
5487
6559
  };
5488
6560
  let routeChangeTimer;
5489
- let runtimeRediscoveryInProgress = false;
5490
6561
  const refreshRuntimeDiscovery = async () => {
5491
6562
  const rscEnv = server.environments?.rsc;
5492
- if (!rscEnv?.runner || runtimeRediscoveryInProgress) return;
5493
- runtimeRediscoveryInProgress = true;
5494
- const hmrStart = performance.now();
6563
+ const hasMainRunner = !!rscEnv?.runner;
6564
+ if (!hasMainRunner && s.perRouterManifests.length === 0) return;
6565
+ await gate.runRefreshCycle(async () => {
6566
+ const hmrStart = performance.now();
6567
+ try {
6568
+ if (hasMainRunner) {
6569
+ await timed(
6570
+ debugDiscovery,
6571
+ "hmr discoverRouters",
6572
+ () => discoverRouters(s, rscEnv)
6573
+ );
6574
+ timedSync(
6575
+ debugDiscovery,
6576
+ "hmr writeRouteTypesFiles",
6577
+ () => writeRouteTypesFiles(s)
6578
+ );
6579
+ await timed(
6580
+ debugDiscovery,
6581
+ "hmr propagateDiscoveryState",
6582
+ () => propagateDiscoveryState(rscEnv)
6583
+ );
6584
+ } else {
6585
+ const tempRscEnv = await timed(
6586
+ debugDiscovery,
6587
+ "hmr refreshTempRscEnv (cloudflare)",
6588
+ () => refreshTempRscEnv()
6589
+ );
6590
+ if (!tempRscEnv) {
6591
+ throw new Error(
6592
+ "temp runner unavailable for cloudflare HMR rediscovery"
6593
+ );
6594
+ }
6595
+ await timed(
6596
+ debugDiscovery,
6597
+ "hmr discoverRouters (cloudflare)",
6598
+ () => discoverRouters(s, tempRscEnv)
6599
+ );
6600
+ timedSync(
6601
+ debugDiscovery,
6602
+ "hmr writeRouteTypesFiles",
6603
+ () => writeRouteTypesFiles(s)
6604
+ );
6605
+ }
6606
+ if (s.lastDiscoveryError) {
6607
+ debugDiscovery?.(
6608
+ "hmr: cleared lastDiscoveryError (%s) after successful rediscovery",
6609
+ s.lastDiscoveryError.message
6610
+ );
6611
+ s.lastDiscoveryError = null;
6612
+ }
6613
+ if (rscEnv && !rscEnv.runner) forceCloudflareWorkerReload(rscEnv);
6614
+ } catch (err) {
6615
+ s.lastDiscoveryError = {
6616
+ message: err?.message ?? String(err),
6617
+ at: Date.now()
6618
+ };
6619
+ console.warn(
6620
+ `[rango] Runtime re-discovery failed: ${err.message}`
6621
+ );
6622
+ debugDiscovery?.(
6623
+ "hmr: lastDiscoveryError set (%s) \u2014 manifest preserved at last-good; recovery mode active (any in-scan source change will trigger rediscovery)",
6624
+ err?.message
6625
+ );
6626
+ } finally {
6627
+ debugDiscovery?.(
6628
+ "hmr re-discovery done (%sms)",
6629
+ (performance.now() - hmrStart).toFixed(1)
6630
+ );
6631
+ }
6632
+ });
6633
+ };
6634
+ const forceCloudflareWorkerReload = (rscEnv) => {
6635
+ if (!rscEnv?.hot) return;
5495
6636
  try {
5496
- await timed(
5497
- debugDiscovery,
5498
- "hmr discoverRouters",
5499
- () => discoverRouters(s, rscEnv)
5500
- );
5501
- timedSync(
5502
- debugDiscovery,
5503
- "hmr writeRouteTypesFiles",
5504
- () => writeRouteTypesFiles(s)
5505
- );
5506
- await timed(
5507
- debugDiscovery,
5508
- "hmr propagateDiscoveryState",
5509
- () => propagateDiscoveryState(rscEnv)
6637
+ const graph = rscEnv.moduleGraph;
6638
+ if (graph?.invalidateAll) {
6639
+ graph.invalidateAll();
6640
+ debugDiscovery?.("hmr: invalidated workerd rsc module graph");
6641
+ }
6642
+ rscEnv.hot.send({ type: "full-reload" });
6643
+ debugDiscovery?.(
6644
+ "hmr: forced workerd rsc env reload (full-reload)"
5510
6645
  );
5511
6646
  } catch (err) {
5512
- console.warn(
5513
- `[rsc-router] Runtime re-discovery failed: ${err.message}`
5514
- );
5515
- } finally {
5516
6647
  debugDiscovery?.(
5517
- "hmr re-discovery done (%sms)",
5518
- (performance.now() - hmrStart).toFixed(1)
6648
+ "hmr: workerd reload failed: %s",
6649
+ err?.message ?? err
5519
6650
  );
5520
- runtimeRediscoveryInProgress = false;
5521
6651
  }
5522
6652
  };
5523
6653
  const scheduleRouteRegeneration = () => {
@@ -5525,15 +6655,21 @@ ${err.stack}`
5525
6655
  routeChangeTimer = setTimeout(() => {
5526
6656
  routeChangeTimer = void 0;
5527
6657
  const regenStart = debugDiscovery ? performance.now() : 0;
6658
+ const rscEnv = server.environments?.rsc;
6659
+ const skipStaticWrite = !rscEnv?.runner && s.perRouterManifests.length > 0;
5528
6660
  try {
5529
- writeCombinedRouteTypesWithTracking(s);
5530
- if (s.perRouterManifests.length > 0) {
5531
- supplementGenFilesWithRuntimeRoutes(s);
6661
+ if (skipStaticWrite) {
6662
+ debugDiscovery?.(
6663
+ "watcher: skipping static write (cloudflare HMR \u2014 runtime rediscovery owns gen file)"
6664
+ );
6665
+ } else {
6666
+ writeCombinedRouteTypesWithTracking(s);
6667
+ if (s.perRouterManifests.length > 0) {
6668
+ supplementGenFilesWithRuntimeRoutes(s);
6669
+ }
5532
6670
  }
5533
6671
  } catch (err) {
5534
- console.error(
5535
- `[rsc-router] Route regeneration error: ${err.message}`
5536
- );
6672
+ console.error(`[rango] Route regeneration error: ${err.message}`);
5537
6673
  }
5538
6674
  debugDiscovery?.(
5539
6675
  "watcher: regenerated gen files (%sms)",
@@ -5542,31 +6678,65 @@ ${err.stack}`
5542
6678
  if (s.perRouterManifests.length > 0) {
5543
6679
  refreshRuntimeDiscovery().catch((err) => {
5544
6680
  console.warn(
5545
- `[rsc-router] Runtime re-discovery error: ${err.message}`
6681
+ `[rango] Runtime re-discovery error: ${err.message}`
5546
6682
  );
6683
+ resolveDiscoveryGate();
5547
6684
  });
5548
6685
  }
5549
6686
  }, 100);
5550
6687
  };
5551
6688
  const handleRouteFileChange = (filePath) => {
5552
6689
  if (maybeHandleGeneratedRouteFileMutation(filePath)) return;
5553
- if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx"))
6690
+ if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx")) {
6691
+ if (s.lastDiscoveryError) {
6692
+ debugDiscovery?.(
6693
+ "watcher: skip non-source %s [LASTERR %s]",
6694
+ filePath,
6695
+ s.lastDiscoveryError.message
6696
+ );
6697
+ }
6698
+ return;
6699
+ }
6700
+ if (s.scanFilter && !s.scanFilter(filePath)) {
6701
+ if (s.lastDiscoveryError) {
6702
+ debugDiscovery?.(
6703
+ "watcher: skip scan-filter %s [LASTERR %s]",
6704
+ filePath,
6705
+ s.lastDiscoveryError.message
6706
+ );
6707
+ }
5554
6708
  return;
5555
- if (s.scanFilter && !s.scanFilter(filePath)) return;
6709
+ }
6710
+ const inRecoveryMode = !!s.lastDiscoveryError;
5556
6711
  try {
5557
6712
  const source = readFileSync6(filePath, "utf-8");
5558
6713
  const trimmed = source.trimStart();
5559
- if (trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'"))
5560
- return;
5561
- const hasUrls = source.includes("urls(");
5562
- const hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
5563
- if (!hasUrls && !hasCreateRouter) return;
5564
- debugDiscovery?.(
5565
- "watcher: %s matches (urls=%s, router=%s)",
5566
- filePath,
5567
- hasUrls,
5568
- hasCreateRouter
5569
- );
6714
+ const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
6715
+ if (!inRecoveryMode && isUseClient) return;
6716
+ let hasUrls = source.includes("urls(");
6717
+ let hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
6718
+ if (hasUrls) hasUrls = firstCodeMatchIndex(source, /urls\(/g) >= 0;
6719
+ if (hasCreateRouter) {
6720
+ hasCreateRouter = firstCodeMatchIndex(source, /\bcreateRouter\s*[<(]/g) >= 0;
6721
+ }
6722
+ if (!inRecoveryMode && !hasUrls && !hasCreateRouter) return;
6723
+ if (inRecoveryMode) {
6724
+ debugDiscovery?.(
6725
+ "watcher: recovery rediscovery for %s (urls=%s, router=%s, useClient=%s) [LASTERR %s]",
6726
+ filePath,
6727
+ hasUrls,
6728
+ hasCreateRouter,
6729
+ isUseClient,
6730
+ s.lastDiscoveryError.message
6731
+ );
6732
+ } else {
6733
+ debugDiscovery?.(
6734
+ "watcher: %s matches (urls=%s, router=%s)",
6735
+ filePath,
6736
+ hasUrls,
6737
+ hasCreateRouter
6738
+ );
6739
+ }
5570
6740
  if (hasCreateRouter) {
5571
6741
  const nestedRouterConflict = findNestedRouterConflict([
5572
6742
  ...s.cachedRouterFiles ?? [],
@@ -5580,8 +6750,19 @@ ${err.stack}`
5580
6750
  }
5581
6751
  s.cachedRouterFiles = void 0;
5582
6752
  }
6753
+ if (s.perRouterManifests.length > 0) {
6754
+ gate.noteRouteEvent();
6755
+ }
5583
6756
  scheduleRouteRegeneration();
5584
- } catch {
6757
+ } catch (readErr) {
6758
+ if (s.lastDiscoveryError) {
6759
+ debugDiscovery?.(
6760
+ "watcher: read error %s: %s [LASTERR %s]",
6761
+ filePath,
6762
+ readErr?.message,
6763
+ s.lastDiscoveryError.message
6764
+ );
6765
+ }
5585
6766
  }
5586
6767
  };
5587
6768
  server.watcher.on("add", handleRouteFileChange);
@@ -5627,7 +6808,7 @@ ${err.stack}`
5627
6808
  const rscEnv = tempServer.environments?.rsc;
5628
6809
  if (!rscEnv?.runner) {
5629
6810
  console.warn(
5630
- "[rsc-router] RSC environment runner not available during build, skipping manifest generation"
6811
+ "[rango] RSC environment runner not available during build, skipping manifest generation"
5631
6812
  );
5632
6813
  return;
5633
6814
  }
@@ -5659,8 +6840,9 @@ ${err.stack}`
5659
6840
  ${err.stack}` : null
5660
6841
  ].filter(Boolean).join("\n");
5661
6842
  throw new Error(
5662
- `[rsc-router] Build-time router discovery failed:
5663
- ${details}`
6843
+ `[rango] Build-time router discovery failed:
6844
+ ${details}`,
6845
+ { cause: err }
5664
6846
  );
5665
6847
  } finally {
5666
6848
  delete globalThis.__rscRouterDiscoveryActive;
@@ -5678,6 +6860,34 @@ ${details}`
5678
6860
  );
5679
6861
  }
5680
6862
  },
6863
+ // Suppress vite's HMR cascade for our own gen-file writes.
6864
+ //
6865
+ // After every cf HMR cycle, refreshTempRscEnv → writeRouteTypesFiles
6866
+ // writes the configured gen files (default `router.named-routes.gen.ts`,
6867
+ // but the source filenames and gen suffix are user-configurable). The
6868
+ // chokidar watcher then fires twice independently: our
6869
+ // `handleRouteFileChange` (already short-circuited by
6870
+ // `consumeSelfGenWrite` inside `maybeHandleGeneratedRouteFileMutation`),
6871
+ // AND vite's own HMR pipeline (which invalidates the gen file's
6872
+ // importers and triggers a second workerd full reload — visible to the
6873
+ // user as a duplicate "[Rango] HMR: version changed" on the client).
6874
+ //
6875
+ // `peekSelfGenWrite` is the authoritative filter: its map only contains
6876
+ // paths that `markSelfGenWrite` has registered, so it natively works
6877
+ // for any configured gen-file name. It is non-consuming so the chokidar
6878
+ // handler that fires later can still consume the same entry. Returning
6879
+ // [] tells vite "no modules invalidated by this change" — safe because
6880
+ // `s.perRouterManifests` is already up-to-date (the write that just
6881
+ // happened is the consequence of our just-completed rediscovery).
6882
+ handleHotUpdate(ctx) {
6883
+ if (peekSelfGenWrite(s, ctx.file)) {
6884
+ debugDiscovery?.(
6885
+ "handleHotUpdate: suppressing self-write HMR cascade for %s",
6886
+ ctx.file
6887
+ );
6888
+ return [];
6889
+ }
6890
+ },
5681
6891
  // Virtual module: provides the pre-generated route manifest as a JS module
5682
6892
  // that calls setCachedManifest() at import time.
5683
6893
  resolveId(id) {
@@ -5695,7 +6905,7 @@ ${details}`
5695
6905
  await timed(
5696
6906
  debugRoutes,
5697
6907
  "await discoveryDone (manifest)",
5698
- () => Promise.resolve(s.discoveryDone)
6908
+ () => s.discoveryDone
5699
6909
  );
5700
6910
  }
5701
6911
  const code = await timed(
@@ -5712,7 +6922,7 @@ ${details}`
5712
6922
  await timed(
5713
6923
  debugRoutes,
5714
6924
  "await discoveryDone (per-router)",
5715
- () => Promise.resolve(s.discoveryDone)
6925
+ () => s.discoveryDone
5716
6926
  );
5717
6927
  }
5718
6928
  const routerId = id.slice(perRouterPrefix.length);
@@ -5814,12 +7024,16 @@ ${details}`
5814
7024
  }
5815
7025
 
5816
7026
  // src/vite/rango.ts
5817
- var debugConfig = createRangoDebugger("rango:config");
7027
+ var debugConfig = createRangoDebugger(NS.config);
5818
7028
  async function rango(options) {
5819
7029
  const rangoStart = performance.now();
5820
7030
  const resolvedOptions = options ?? { preset: "node" };
5821
7031
  const preset = resolvedOptions.preset ?? "node";
5822
7032
  const showBanner = resolvedOptions.banner ?? true;
7033
+ const clientChunksOption = resolvedOptions.clientChunks ?? true;
7034
+ const useBuiltInClientChunks = clientChunksOption === true;
7035
+ const clientChunkCtx = useBuiltInClientChunks ? { fallbackRefs: /* @__PURE__ */ new Set() } : void 0;
7036
+ const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
5823
7037
  debugConfig?.("rango(%s) setup start", preset);
5824
7038
  const plugins = [];
5825
7039
  const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
@@ -5851,14 +7065,20 @@ async function rango(options) {
5851
7065
  enforce: "pre",
5852
7066
  config() {
5853
7067
  return {
5854
- // Exclude rsc-router modules from optimization to prevent module duplication
5855
- // This ensures the same Context instance is used by both browser entry and RSC proxy modules
5856
7068
  optimizeDeps: {
5857
7069
  exclude: excludeDeps,
5858
- esbuildOptions: sharedEsbuildOptions
7070
+ rolldownOptions: sharedRolldownOptions
5859
7071
  },
5860
7072
  resolve: {
5861
- alias: rangoAliases
7073
+ alias: rangoAliases,
7074
+ // Force a single React/React-DOM copy across all three RSC
7075
+ // environments. RSC requires exactly one react/react-dom instance
7076
+ // per environment runtime; consumer install topologies (pnpm
7077
+ // strict layout, experimental React pins, third-party "use client"
7078
+ // packages) can otherwise resolve duplicate copies, causing
7079
+ // "Invalid hook call" / lost context. Child environments inherit
7080
+ // this root dedupe, and Vite merges it with any consumer dedupe.
7081
+ dedupe: ["react", "react-dom"]
5862
7082
  },
5863
7083
  build: {
5864
7084
  rollupOptions: { onwarn }
@@ -5867,30 +7087,22 @@ async function rango(options) {
5867
7087
  client: {
5868
7088
  build: {
5869
7089
  rollupOptions: {
7090
+ onwarn,
5870
7091
  output: {
5871
7092
  manualChunks: getManualChunks
5872
7093
  }
5873
7094
  }
5874
7095
  },
5875
- // Pre-bundle rsc-html-stream to prevent discovery during first request
5876
- // Exclude rsc-router modules to ensure same Context instance
5877
7096
  optimizeDeps: {
5878
7097
  include: [nested("rsc-html-stream/client")],
5879
7098
  exclude: excludeDeps,
5880
- esbuildOptions: sharedEsbuildOptions
7099
+ rolldownOptions: sharedRolldownOptions
5881
7100
  }
5882
7101
  },
5883
7102
  ssr: {
5884
- // Build SSR inside RSC directory so wrangler can deploy self-contained dist/rsc
5885
7103
  build: {
5886
7104
  outDir: "./dist/rsc/ssr"
5887
7105
  },
5888
- resolve: {
5889
- // Ensure single React instance in SSR child environment
5890
- dedupe: ["react", "react-dom"]
5891
- },
5892
- // Pre-bundle SSR entry and React for proper module linking with childEnvironments
5893
- // All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
5894
7106
  optimizeDeps: {
5895
7107
  entries: [finalEntries.ssr],
5896
7108
  include: [
@@ -5906,14 +7118,11 @@ async function rango(options) {
5906
7118
  )
5907
7119
  ],
5908
7120
  exclude: excludeDeps,
5909
- esbuildOptions: sharedEsbuildOptions
7121
+ rolldownOptions: sharedRolldownOptions
5910
7122
  }
5911
7123
  },
5912
7124
  rsc: {
5913
- // RSC environment needs exclude list and esbuild options
5914
- // Exclude rsc-router modules to prevent createContext in RSC environment
5915
7125
  optimizeDeps: {
5916
- // Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
5917
7126
  include: [
5918
7127
  "react",
5919
7128
  "react/jsx-runtime",
@@ -5923,7 +7132,7 @@ async function rango(options) {
5923
7132
  )
5924
7133
  ],
5925
7134
  exclude: excludeDeps,
5926
- esbuildOptions: sharedEsbuildOptions
7135
+ rolldownOptions: sharedRolldownOptions
5927
7136
  }
5928
7137
  }
5929
7138
  }
@@ -5941,7 +7150,8 @@ async function rango(options) {
5941
7150
  plugins.push(
5942
7151
  rsc({
5943
7152
  entries: finalEntries,
5944
- serverHandler: false
7153
+ serverHandler: false,
7154
+ clientChunks
5945
7155
  })
5946
7156
  );
5947
7157
  plugins.push(clientRefDedup());
@@ -5959,7 +7169,7 @@ async function rango(options) {
5959
7169
  const list = candidates.map(
5960
7170
  (f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
5961
7171
  ).join("\n");
5962
- throw new Error(`[rsc-router] Multiple routers found:
7172
+ throw new Error(`[rango] Multiple routers found:
5963
7173
  ${list}`);
5964
7174
  }
5965
7175
  }
@@ -5978,18 +7188,27 @@ ${list}`);
5978
7188
  return {
5979
7189
  optimizeDeps: {
5980
7190
  exclude: excludeDeps,
5981
- esbuildOptions: sharedEsbuildOptions
7191
+ rolldownOptions: sharedRolldownOptions
5982
7192
  },
5983
7193
  build: {
5984
7194
  rollupOptions: { onwarn }
5985
7195
  },
5986
7196
  resolve: {
5987
- alias: rangoAliases
7197
+ alias: rangoAliases,
7198
+ // Force a single React/React-DOM copy across all three RSC
7199
+ // environments. RSC requires exactly one react/react-dom instance
7200
+ // per environment runtime; consumer install topologies (pnpm
7201
+ // strict layout, experimental React pins, third-party "use client"
7202
+ // packages) can otherwise resolve duplicate copies, causing
7203
+ // "Invalid hook call" / lost context. Child environments inherit
7204
+ // this root dedupe, and Vite merges it with any consumer dedupe.
7205
+ dedupe: ["react", "react-dom"]
5988
7206
  },
5989
7207
  environments: {
5990
7208
  client: {
5991
7209
  build: {
5992
7210
  rollupOptions: {
7211
+ onwarn,
5993
7212
  output: {
5994
7213
  manualChunks: getManualChunks
5995
7214
  }
@@ -6004,7 +7223,7 @@ ${list}`);
6004
7223
  nested("rsc-html-stream/client")
6005
7224
  ],
6006
7225
  exclude: excludeDeps,
6007
- esbuildOptions: sharedEsbuildOptions,
7226
+ rolldownOptions: sharedRolldownOptions,
6008
7227
  entries: [VIRTUAL_IDS.browser]
6009
7228
  }
6010
7229
  },
@@ -6023,7 +7242,7 @@ ${list}`);
6023
7242
  )
6024
7243
  ],
6025
7244
  exclude: excludeDeps,
6026
- esbuildOptions: sharedEsbuildOptions
7245
+ rolldownOptions: sharedRolldownOptions
6027
7246
  }
6028
7247
  },
6029
7248
  rsc: {
@@ -6037,7 +7256,13 @@ ${list}`);
6037
7256
  "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
6038
7257
  )
6039
7258
  ],
6040
- esbuildOptions: sharedEsbuildOptions
7259
+ // Vite 8 does not propagate the top-level optimizeDeps.exclude
7260
+ // (set in config()) to non-client envs, so the rsc env must set
7261
+ // it explicitly — mirroring the node ssr env and the cloudflare
7262
+ // rsc env. Without it a strict-pnpm npm-installed app can try to
7263
+ // pre-bundle the router's own subpath entries and fail.
7264
+ exclude: excludeDeps,
7265
+ rolldownOptions: sharedRolldownOptions
6041
7266
  }
6042
7267
  }
6043
7268
  }
@@ -6054,7 +7279,7 @@ ${list}`);
6054
7279
  if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
6055
7280
  hasWarnedDuplicate = true;
6056
7281
  console.warn(
6057
- "[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
7282
+ "[rango] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
6058
7283
  );
6059
7284
  }
6060
7285
  }
@@ -6063,7 +7288,8 @@ ${list}`);
6063
7288
  plugins.push(performanceTracksPlugin());
6064
7289
  plugins.push(
6065
7290
  rsc({
6066
- entries: finalEntries
7291
+ entries: finalEntries,
7292
+ clientChunks
6067
7293
  })
6068
7294
  );
6069
7295
  plugins.push(clientRefDedup());
@@ -6078,8 +7304,7 @@ ${list}`);
6078
7304
  return;
6079
7305
  try {
6080
7306
  const source = readFileSync7(file, "utf-8");
6081
- const trimmed = source.trimStart();
6082
- if (trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'")) {
7307
+ if (hasUseClientDirective(source)) {
6083
7308
  return [];
6084
7309
  }
6085
7310
  } catch {
@@ -6102,7 +7327,10 @@ ${list}`);
6102
7327
  routerPathRef: discoveryRouterRef,
6103
7328
  enableBuildPrerender: prerenderEnabled,
6104
7329
  buildEnv: options?.buildEnv,
6105
- preset
7330
+ preset,
7331
+ prerenderOnError: options?.prerender?.onError,
7332
+ discovery: options?.discovery,
7333
+ clientChunkCtx
6106
7334
  })
6107
7335
  );
6108
7336
  debugConfig?.(
@@ -6117,7 +7345,7 @@ ${list}`);
6117
7345
  // src/vite/plugins/refresh-cmd.ts
6118
7346
  function poke() {
6119
7347
  return {
6120
- name: "vite-plugin-poke",
7348
+ name: "@rangojs/router:poke",
6121
7349
  apply: "serve",
6122
7350
  configureServer(server) {
6123
7351
  const stdin = process.stdin;