@rangojs/router 0.0.0-experimental.9c9afef3 → 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 (402) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +245 -49
  3. package/dist/bin/rango.js +440 -133
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3373 -1176
  6. package/dist/vite/index.js.bak +5448 -0
  7. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  8. package/package.json +68 -14
  9. package/skills/api-client/SKILL.md +211 -0
  10. package/skills/breadcrumbs/SKILL.md +64 -2
  11. package/skills/bundle-analysis/SKILL.md +159 -0
  12. package/skills/cache-guide/SKILL.md +224 -32
  13. package/skills/caching/SKILL.md +279 -17
  14. package/skills/composability/SKILL.md +27 -3
  15. package/skills/css/SKILL.md +76 -0
  16. package/skills/debug-manifest/SKILL.md +4 -2
  17. package/skills/document-cache/SKILL.md +78 -55
  18. package/skills/handler-use/SKILL.md +364 -0
  19. package/skills/hooks/SKILL.md +250 -30
  20. package/skills/host-router/SKILL.md +83 -23
  21. package/skills/i18n/SKILL.md +276 -0
  22. package/skills/intercept/SKILL.md +87 -18
  23. package/skills/layout/SKILL.md +35 -9
  24. package/skills/links/SKILL.md +249 -17
  25. package/skills/loader/SKILL.md +235 -9
  26. package/skills/middleware/SKILL.md +52 -13
  27. package/skills/migrate-nextjs/SKILL.md +584 -0
  28. package/skills/migrate-react-router/SKILL.md +771 -0
  29. package/skills/mime-routes/SKILL.md +28 -1
  30. package/skills/observability/SKILL.md +172 -0
  31. package/skills/parallel/SKILL.md +77 -7
  32. package/skills/prerender/SKILL.md +172 -125
  33. package/skills/rango/SKILL.md +251 -22
  34. package/skills/react-compiler/SKILL.md +168 -0
  35. package/skills/response-routes/SKILL.md +123 -48
  36. package/skills/route/SKILL.md +70 -5
  37. package/skills/router-setup/SKILL.md +65 -8
  38. package/skills/scripts/SKILL.md +179 -0
  39. package/skills/server-actions/SKILL.md +775 -0
  40. package/skills/streams-and-websockets/SKILL.md +283 -0
  41. package/skills/tailwind/SKILL.md +27 -3
  42. package/skills/testing/SKILL.md +130 -0
  43. package/skills/testing/bindings.md +103 -0
  44. package/skills/testing/cache-prerender.md +127 -0
  45. package/skills/testing/client-components.md +124 -0
  46. package/skills/testing/e2e-parity.md +125 -0
  47. package/skills/testing/flight.md +91 -0
  48. package/skills/testing/handles.md +129 -0
  49. package/skills/testing/loader.md +128 -0
  50. package/skills/testing/middleware.md +99 -0
  51. package/skills/testing/render-handler.md +122 -0
  52. package/skills/testing/response-routes.md +95 -0
  53. package/skills/testing/reverse-and-types.md +84 -0
  54. package/skills/testing/server-actions.md +107 -0
  55. package/skills/testing/server-tree.md +128 -0
  56. package/skills/testing/setup.md +123 -0
  57. package/skills/typesafety/SKILL.md +322 -29
  58. package/skills/use-cache/SKILL.md +57 -14
  59. package/skills/view-transitions/SKILL.md +337 -0
  60. package/src/__augment-tests__/augment.ts +81 -0
  61. package/src/__augment-tests__/augmented.check.ts +116 -0
  62. package/src/__internal.ts +1 -66
  63. package/src/browser/action-coordinator.ts +53 -36
  64. package/src/browser/action-fence.ts +47 -0
  65. package/src/browser/app-shell.ts +39 -0
  66. package/src/browser/app-version.ts +14 -0
  67. package/src/browser/connection-warmup.ts +134 -0
  68. package/src/browser/cookie-name.ts +140 -0
  69. package/src/browser/event-controller.ts +192 -150
  70. package/src/browser/history-state.ts +21 -0
  71. package/src/browser/index.ts +3 -3
  72. package/src/browser/invalidate-client-cache.ts +52 -0
  73. package/src/browser/navigation-bridge.ts +131 -30
  74. package/src/browser/navigation-client.ts +186 -100
  75. package/src/browser/navigation-store-handle.ts +38 -0
  76. package/src/browser/navigation-store.ts +157 -74
  77. package/src/browser/navigation-transaction.ts +9 -59
  78. package/src/browser/network-error-handler.ts +34 -7
  79. package/src/browser/partial-update.ts +165 -112
  80. package/src/browser/prefetch/cache.ts +205 -62
  81. package/src/browser/prefetch/fetch.ts +347 -39
  82. package/src/browser/prefetch/queue.ts +42 -8
  83. package/src/browser/rango-state.ts +158 -76
  84. package/src/browser/react/Link.tsx +102 -15
  85. package/src/browser/react/NavigationProvider.tsx +295 -119
  86. package/src/browser/react/ScrollRestoration.tsx +10 -6
  87. package/src/browser/react/context.ts +7 -2
  88. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  89. package/src/browser/react/filter-segment-order.ts +66 -7
  90. package/src/browser/react/index.ts +0 -48
  91. package/src/browser/react/location-state-shared.ts +178 -8
  92. package/src/browser/react/location-state.ts +39 -14
  93. package/src/browser/react/use-action.ts +6 -15
  94. package/src/browser/react/use-handle.ts +23 -69
  95. package/src/browser/react/use-href.tsx +8 -1
  96. package/src/browser/react/use-link-status.ts +33 -8
  97. package/src/browser/react/use-navigation.ts +32 -7
  98. package/src/browser/react/use-params.ts +20 -10
  99. package/src/browser/react/use-reverse.ts +106 -0
  100. package/src/browser/react/use-router.ts +46 -11
  101. package/src/browser/react/use-search-params.ts +0 -5
  102. package/src/browser/react/use-segments.ts +11 -21
  103. package/src/browser/response-adapter.ts +99 -8
  104. package/src/browser/rsc-router.tsx +114 -24
  105. package/src/browser/scroll-restoration.ts +37 -22
  106. package/src/browser/segment-reconciler.ts +36 -14
  107. package/src/browser/segment-structure-assert.ts +2 -2
  108. package/src/browser/server-action-bridge.ts +222 -72
  109. package/src/browser/types.ts +102 -12
  110. package/src/browser/validate-redirect-origin.ts +43 -16
  111. package/src/build/collect-fallback-refs.ts +107 -0
  112. package/src/build/generate-manifest.ts +65 -40
  113. package/src/build/generate-route-types.ts +5 -1
  114. package/src/build/index.ts +8 -2
  115. package/src/build/prefix-tree-utils.ts +123 -0
  116. package/src/build/route-trie.ts +165 -36
  117. package/src/build/route-types/ast-route-extraction.ts +15 -8
  118. package/src/build/route-types/codegen.ts +16 -5
  119. package/src/build/route-types/include-resolution.ts +125 -24
  120. package/src/build/route-types/param-extraction.ts +6 -3
  121. package/src/build/route-types/per-module-writer.ts +22 -6
  122. package/src/build/route-types/router-processing.ts +260 -94
  123. package/src/build/route-types/scan-filter.ts +9 -2
  124. package/src/build/route-types/source-scan.ts +216 -0
  125. package/src/build/runtime-discovery.ts +9 -20
  126. package/src/cache/cache-error.ts +104 -0
  127. package/src/cache/cache-key-utils.ts +29 -13
  128. package/src/cache/cache-policy.ts +108 -34
  129. package/src/cache/cache-runtime.ts +224 -41
  130. package/src/cache/cache-scope.ts +188 -82
  131. package/src/cache/cache-tag.ts +103 -0
  132. package/src/cache/cf/cf-base64.ts +33 -0
  133. package/src/cache/cf/cf-cache-constants.ts +127 -0
  134. package/src/cache/cf/cf-cache-store.ts +1989 -378
  135. package/src/cache/cf/cf-cache-types.ts +349 -0
  136. package/src/cache/cf/cf-kv-utils.ts +46 -0
  137. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  138. package/src/cache/cf/index.ts +6 -16
  139. package/src/cache/document-cache.ts +89 -21
  140. package/src/cache/handle-snapshot.ts +70 -0
  141. package/src/cache/index.ts +10 -20
  142. package/src/cache/memory-segment-store.ts +136 -37
  143. package/src/cache/profile-registry.ts +46 -31
  144. package/src/cache/read-through-swr.ts +56 -12
  145. package/src/cache/segment-codec.ts +9 -17
  146. package/src/cache/tag-invalidation.ts +230 -0
  147. package/src/cache/types.ts +37 -100
  148. package/src/client.rsc.tsx +44 -21
  149. package/src/client.tsx +119 -290
  150. package/src/cloudflare/index.ts +11 -0
  151. package/src/cloudflare/tracing.ts +109 -0
  152. package/src/component-utils.ts +19 -0
  153. package/src/components/DefaultDocument.tsx +8 -2
  154. package/src/context-var.ts +18 -6
  155. package/src/decode-loader-results.ts +52 -0
  156. package/src/defer.ts +196 -0
  157. package/src/deps/ssr.ts +0 -1
  158. package/src/encode-kv.ts +49 -0
  159. package/src/errors.ts +30 -4
  160. package/src/escape-script.ts +52 -0
  161. package/src/handle.ts +70 -22
  162. package/src/handles/MetaTags.tsx +62 -19
  163. package/src/handles/Scripts.tsx +183 -0
  164. package/src/handles/breadcrumbs.ts +37 -8
  165. package/src/handles/is-thenable.ts +19 -0
  166. package/src/handles/meta.ts +51 -40
  167. package/src/handles/script.ts +244 -0
  168. package/src/host/cookie-handler.ts +9 -60
  169. package/src/host/errors.ts +0 -24
  170. package/src/host/index.ts +8 -2
  171. package/src/host/pattern-matcher.ts +23 -52
  172. package/src/host/router.ts +107 -99
  173. package/src/host/testing.ts +40 -27
  174. package/src/host/types.ts +37 -4
  175. package/src/host/utils.ts +1 -1
  176. package/src/href-client.ts +137 -22
  177. package/src/index.rsc.ts +99 -13
  178. package/src/index.ts +139 -19
  179. package/src/internal-debug.ts +11 -10
  180. package/src/loader-store.ts +500 -0
  181. package/src/loader.rsc.ts +20 -13
  182. package/src/loader.ts +12 -11
  183. package/src/missing-id-error.ts +68 -0
  184. package/src/outlet-context.ts +1 -1
  185. package/src/outlet-provider.tsx +1 -5
  186. package/src/prerender/param-hash.ts +16 -16
  187. package/src/prerender/store.ts +37 -41
  188. package/src/prerender.ts +198 -82
  189. package/src/redirect-origin.ts +100 -0
  190. package/src/regex-escape.ts +8 -0
  191. package/src/render-error-thrower.tsx +20 -0
  192. package/src/response-utils.ts +62 -0
  193. package/src/reverse.ts +65 -15
  194. package/src/root-error-boundary.tsx +1 -19
  195. package/src/route-content-wrapper.tsx +19 -77
  196. package/src/route-definition/dsl-helpers.ts +461 -304
  197. package/src/route-definition/helper-factories.ts +28 -140
  198. package/src/route-definition/helpers-types.ts +143 -69
  199. package/src/route-definition/index.ts +4 -2
  200. package/src/route-definition/redirect.ts +51 -10
  201. package/src/route-definition/resolve-handler-use.ts +160 -0
  202. package/src/route-definition/use-item-types.ts +29 -0
  203. package/src/route-map-builder.ts +0 -16
  204. package/src/route-types.ts +37 -46
  205. package/src/router/basename.ts +14 -0
  206. package/src/router/content-negotiation.ts +164 -17
  207. package/src/router/error-handling.ts +45 -18
  208. package/src/router/find-match.ts +44 -23
  209. package/src/router/handler-context.ts +52 -31
  210. package/src/router/instrument.ts +350 -0
  211. package/src/router/intercept-resolution.ts +48 -24
  212. package/src/router/lazy-includes.ts +15 -52
  213. package/src/router/loader-resolution.ts +268 -56
  214. package/src/router/logging.ts +0 -6
  215. package/src/router/manifest.ts +40 -42
  216. package/src/router/match-api.ts +124 -204
  217. package/src/router/match-context.ts +0 -22
  218. package/src/router/match-handlers.ts +58 -58
  219. package/src/router/match-middleware/background-revalidation.ts +40 -24
  220. package/src/router/match-middleware/cache-lookup.ts +170 -276
  221. package/src/router/match-middleware/cache-store.ts +64 -52
  222. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  223. package/src/router/match-middleware/segment-resolution.ts +45 -14
  224. package/src/router/match-pipelines.ts +1 -42
  225. package/src/router/match-result.ts +87 -39
  226. package/src/router/metrics.ts +0 -34
  227. package/src/router/middleware-types.ts +7 -140
  228. package/src/router/middleware.ts +266 -169
  229. package/src/router/navigation-snapshot.ts +131 -0
  230. package/src/router/params-util.ts +23 -0
  231. package/src/router/pattern-matching.ts +132 -90
  232. package/src/router/prefetch-cache-ttl.ts +51 -0
  233. package/src/router/prerender-match.ts +195 -56
  234. package/src/router/preview-match.ts +32 -102
  235. package/src/router/request-classification.ts +276 -0
  236. package/src/router/revalidation.ts +123 -73
  237. package/src/router/route-snapshot.ts +244 -0
  238. package/src/router/router-context.ts +3 -28
  239. package/src/router/router-interfaces.ts +115 -35
  240. package/src/router/router-options.ts +172 -15
  241. package/src/router/router-registry.ts +2 -5
  242. package/src/router/segment-resolution/fresh.ts +162 -84
  243. package/src/router/segment-resolution/helpers.ts +86 -6
  244. package/src/router/segment-resolution/loader-cache.ts +76 -39
  245. package/src/router/segment-resolution/revalidation.ts +351 -321
  246. package/src/router/segment-resolution/static-store.ts +19 -5
  247. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  248. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  249. package/src/router/segment-resolution.ts +5 -1
  250. package/src/router/segment-wrappers.ts +6 -5
  251. package/src/router/state-cookie-name.ts +33 -0
  252. package/src/router/substitute-pattern-params.ts +56 -0
  253. package/src/router/telemetry-otel.ts +161 -199
  254. package/src/router/telemetry.ts +96 -19
  255. package/src/router/timeout.ts +0 -20
  256. package/src/router/tracing.ts +206 -0
  257. package/src/router/trie-matching.ts +163 -59
  258. package/src/router/types.ts +9 -63
  259. package/src/router/url-params.ts +44 -0
  260. package/src/router.ts +157 -54
  261. package/src/rsc/handler-context.ts +3 -2
  262. package/src/rsc/handler.ts +655 -529
  263. package/src/rsc/helpers.ts +168 -46
  264. package/src/rsc/index.ts +2 -5
  265. package/src/rsc/json-route-result.ts +38 -0
  266. package/src/rsc/loader-fetch.ts +122 -31
  267. package/src/rsc/manifest-init.ts +33 -42
  268. package/src/rsc/origin-guard.ts +39 -25
  269. package/src/rsc/progressive-enhancement.ts +131 -14
  270. package/src/rsc/redirect-guard.ts +99 -0
  271. package/src/rsc/response-cache-serve.ts +238 -0
  272. package/src/rsc/response-error.ts +79 -12
  273. package/src/rsc/response-route-handler.ts +99 -189
  274. package/src/rsc/rsc-rendering.ts +109 -74
  275. package/src/rsc/runtime-warnings.ts +23 -10
  276. package/src/rsc/server-action.ts +287 -115
  277. package/src/rsc/ssr-setup.ts +18 -2
  278. package/src/rsc/transition-gate.ts +89 -0
  279. package/src/rsc/types.ts +29 -9
  280. package/src/runtime-env.ts +18 -0
  281. package/src/search-params.ts +35 -30
  282. package/src/segment-content-promise.ts +67 -0
  283. package/src/segment-loader-promise.ts +149 -0
  284. package/src/segment-system.tsx +236 -202
  285. package/src/serialize.ts +243 -0
  286. package/src/server/context.ts +224 -52
  287. package/src/server/cookie-parse.ts +32 -0
  288. package/src/server/cookie-store.ts +80 -5
  289. package/src/server/handle-store.ts +40 -38
  290. package/src/server/loader-registry.ts +38 -46
  291. package/src/server/request-context.ts +401 -173
  292. package/src/ssr/index.tsx +24 -16
  293. package/src/static-handler.ts +27 -18
  294. package/src/testing/cache-status.ts +162 -0
  295. package/src/testing/collect-handle.ts +40 -0
  296. package/src/testing/dispatch.ts +701 -0
  297. package/src/testing/dom.entry.ts +22 -0
  298. package/src/testing/e2e/fixture.ts +188 -0
  299. package/src/testing/e2e/index.ts +128 -0
  300. package/src/testing/e2e/matchers.ts +35 -0
  301. package/src/testing/e2e/page-helpers.ts +272 -0
  302. package/src/testing/e2e/parity.ts +387 -0
  303. package/src/testing/e2e/server.ts +195 -0
  304. package/src/testing/flight-matchers.ts +97 -0
  305. package/src/testing/flight-normalize.ts +11 -0
  306. package/src/testing/flight-runtime.d.ts +57 -0
  307. package/src/testing/flight-tree.ts +682 -0
  308. package/src/testing/flight.entry.ts +52 -0
  309. package/src/testing/flight.ts +257 -0
  310. package/src/testing/generated-routes.ts +183 -0
  311. package/src/testing/index.ts +105 -0
  312. package/src/testing/internal/context.ts +371 -0
  313. package/src/testing/internal/flight-client-globals.ts +30 -0
  314. package/src/testing/internal/seed-vars.ts +54 -0
  315. package/src/testing/render-handler.ts +357 -0
  316. package/src/testing/render-route.tsx +581 -0
  317. package/src/testing/run-loader.ts +385 -0
  318. package/src/testing/run-middleware.ts +205 -0
  319. package/src/testing/run-transition-when.ts +164 -0
  320. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  321. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  322. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  323. package/src/testing/vitest-stubs/version.ts +5 -0
  324. package/src/testing/vitest.ts +305 -0
  325. package/src/theme/ThemeProvider.tsx +20 -58
  326. package/src/theme/ThemeScript.tsx +7 -9
  327. package/src/theme/constants.ts +52 -13
  328. package/src/theme/index.ts +0 -7
  329. package/src/theme/theme-context.ts +1 -5
  330. package/src/theme/theme-script.ts +22 -21
  331. package/src/theme/use-theme.ts +0 -3
  332. package/src/types/boundaries.ts +0 -35
  333. package/src/types/cache-types.ts +17 -8
  334. package/src/types/error-types.ts +30 -90
  335. package/src/types/global-namespace.ts +54 -41
  336. package/src/types/handler-context.ts +125 -71
  337. package/src/types/index.ts +3 -10
  338. package/src/types/loader-types.ts +40 -11
  339. package/src/types/request-scope.ts +112 -0
  340. package/src/types/route-config.ts +6 -50
  341. package/src/types/route-entry.ts +12 -7
  342. package/src/types/segments.ts +136 -15
  343. package/src/urls/include-helper.ts +33 -70
  344. package/src/urls/index.ts +1 -11
  345. package/src/urls/path-helper-types.ts +68 -18
  346. package/src/urls/path-helper.ts +57 -111
  347. package/src/urls/pattern-types.ts +48 -19
  348. package/src/urls/response-types.ts +25 -22
  349. package/src/urls/type-extraction.ts +58 -139
  350. package/src/urls/urls-function.ts +1 -19
  351. package/src/use-loader.tsx +346 -89
  352. package/src/vite/debug.ts +185 -0
  353. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  354. package/src/vite/discovery/discover-routers.ts +130 -85
  355. package/src/vite/discovery/discovery-errors.ts +194 -0
  356. package/src/vite/discovery/gate-state.ts +171 -0
  357. package/src/vite/discovery/prerender-collection.ts +214 -132
  358. package/src/vite/discovery/route-types-writer.ts +40 -84
  359. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  360. package/src/vite/discovery/state.ts +57 -4
  361. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  362. package/src/vite/index.ts +6 -0
  363. package/src/vite/inject-client-debug.ts +36 -0
  364. package/src/vite/plugin-types.ts +178 -5
  365. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  366. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  367. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  368. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  369. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  370. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  371. package/src/vite/plugins/expose-action-id.ts +48 -95
  372. package/src/vite/plugins/expose-id-utils.ts +96 -51
  373. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  374. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  375. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  376. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  377. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  378. package/src/vite/plugins/performance-tracks.ts +64 -170
  379. package/src/vite/plugins/refresh-cmd.ts +89 -27
  380. package/src/vite/plugins/use-cache-transform.ts +73 -83
  381. package/src/vite/plugins/version-injector.ts +40 -29
  382. package/src/vite/plugins/version-plugin.ts +37 -40
  383. package/src/vite/plugins/virtual-entries.ts +39 -25
  384. package/src/vite/rango.ts +118 -114
  385. package/src/vite/router-discovery.ts +941 -142
  386. package/src/vite/utils/ast-handler-extract.ts +26 -35
  387. package/src/vite/utils/banner.ts +1 -1
  388. package/src/vite/utils/bundle-analysis.ts +10 -15
  389. package/src/vite/utils/client-chunks.ts +184 -0
  390. package/src/vite/utils/directive-prologue.ts +40 -0
  391. package/src/vite/utils/forward-user-plugins.ts +171 -0
  392. package/src/vite/utils/manifest-utils.ts +4 -59
  393. package/src/vite/utils/package-resolution.ts +20 -52
  394. package/src/vite/utils/prerender-utils.ts +81 -34
  395. package/src/vite/utils/shared-utils.ts +92 -42
  396. package/src/browser/action-response-classifier.ts +0 -99
  397. package/src/browser/debug-channel.ts +0 -93
  398. package/src/browser/react/use-client-cache.ts +0 -58
  399. package/src/browser/shallow.ts +0 -40
  400. package/src/handles/index.ts +0 -7
  401. package/src/network-error-thrower.tsx +0 -23
  402. package/src/router/middleware-cookies.ts +0 -55
@@ -6,16 +6,20 @@
6
6
  * generation.
7
7
  */
8
8
 
9
- import { contextSet } from "../../context-var.js";
9
+ import { contextSet, hasContextVars } from "../../context-var.js";
10
10
  import {
11
11
  encodePathParam,
12
12
  substituteRouteParams,
13
13
  runWithConcurrency,
14
14
  groupByConcurrency,
15
15
  notifyOnError,
16
+ resolvePrerenderError,
16
17
  stageBuildAssetModule,
17
18
  } from "../utils/prerender-utils.js";
18
19
  import type { DiscoveryState } from "./state.js";
20
+ import { createRangoDebugger, NS } from "../debug.js";
21
+
22
+ const debug = createRangoDebugger(NS.prerender);
19
23
 
20
24
  /**
21
25
  * Expand prerender routes into concrete URLs and render them via the
@@ -30,6 +34,12 @@ export async function expandPrerenderRoutes(
30
34
  ): Promise<void> {
31
35
  if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
32
36
 
37
+ const overallStart = debug ? performance.now() : 0;
38
+ debug?.(
39
+ "expandPrerenderRoutes: start (%d router manifest(s))",
40
+ allManifests.length,
41
+ );
42
+
33
43
  type PrerenderEntry = {
34
44
  urlPath: string;
35
45
  routeName: string;
@@ -51,103 +61,170 @@ export async function expandPrerenderRoutes(
51
61
  return substituteRouteParams(pattern, params);
52
62
  };
53
63
 
64
+ let resolvedRoutes = 0;
65
+ let totalDynamic = 0;
66
+
67
+ // Count dynamic routes upfront for progress reporting
54
68
  for (const { manifest } of allManifests) {
55
69
  if (!manifest.prerenderRoutes) continue;
56
- const defs = manifest._prerenderDefs || {};
57
70
  for (const routeName of manifest.prerenderRoutes) {
58
71
  const pattern = manifest.routeManifest[routeName];
59
- if (!pattern) continue;
60
- const def = defs[routeName];
61
- const isPassthroughRoute = !!def?.options?.passthrough;
62
- const hasDynamic = pattern.includes(":") || pattern.includes("*");
63
- if (!hasDynamic) {
64
- // Static route: use pattern directly (strip trailing slash for URL)
65
- entries.push({
66
- urlPath: pattern.replace(/\/$/, "") || "/",
67
- routeName,
68
- concurrency: 1,
69
- isPassthroughRoute,
70
- });
71
- } else {
72
- // Dynamic route: call getParams() to enumerate param combinations
73
- if (def?.getParams) {
74
- try {
75
- const buildVars: Record<string, any> = {};
76
- const getParamsCtx = {
77
- build: true as const,
78
- set: ((keyOrVar: any, value: any) => {
79
- contextSet(buildVars, keyOrVar, value);
80
- }) as any,
81
- reverse: getParamsReverse,
82
- };
83
- const paramsList = await def.getParams(getParamsCtx);
84
- const concurrency = def.options?.concurrency ?? 1;
85
- const hasBuildVars =
86
- Object.keys(buildVars).length > 0 ||
87
- Object.getOwnPropertySymbols(buildVars).length > 0;
88
- for (const params of paramsList) {
89
- let url = substituteRouteParams(
90
- pattern,
91
- params as Record<string, string>,
92
- encodePathParam,
72
+ if (pattern && (pattern.includes(":") || pattern.includes("*"))) {
73
+ totalDynamic++;
74
+ }
75
+ }
76
+ }
77
+
78
+ // Periodic progress log so long getParams() calls don't look stalled
79
+ const paramsStart = performance.now();
80
+ const progressInterval =
81
+ totalDynamic > 0
82
+ ? setInterval(() => {
83
+ const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
84
+ console.log(
85
+ `[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
86
+ );
87
+ }, 5000)
88
+ : undefined;
89
+
90
+ try {
91
+ for (const { manifest } of allManifests) {
92
+ if (!manifest.prerenderRoutes) continue;
93
+ const defs = manifest._prerenderDefs || {};
94
+ const passthroughSet = new Set(manifest.passthroughRoutes || []);
95
+ for (const routeName of manifest.prerenderRoutes) {
96
+ const pattern = manifest.routeManifest[routeName];
97
+ if (!pattern) continue;
98
+ const def = defs[routeName];
99
+ const isPassthroughRoute = passthroughSet.has(routeName);
100
+ const hasDynamic = pattern.includes(":") || pattern.includes("*");
101
+ if (!hasDynamic) {
102
+ // Static route: use pattern directly (strip trailing slash for URL)
103
+ entries.push({
104
+ urlPath: pattern.replace(/\/$/, "") || "/",
105
+ routeName,
106
+ concurrency: 1,
107
+ isPassthroughRoute,
108
+ });
109
+ } else {
110
+ // Dynamic route: call getParams() to enumerate param combinations
111
+ if (def?.getParams) {
112
+ const getParamsStart = debug ? performance.now() : 0;
113
+ try {
114
+ const buildVars: Record<string, any> = {};
115
+ const buildEnv = state.resolvedBuildEnv;
116
+ const getParamsCtx = {
117
+ build: true as const,
118
+ dev: !state.isBuildMode,
119
+ set: ((keyOrVar: any, value: any) => {
120
+ contextSet(buildVars, keyOrVar, value);
121
+ }) as any,
122
+ reverse: getParamsReverse,
123
+ get env() {
124
+ if (buildEnv !== undefined) return buildEnv;
125
+ throw new Error(
126
+ "[rango] ctx.env is not available during build-time getParams(). " +
127
+ "Configure buildEnv in your rango() plugin options to enable build-time env access.",
128
+ );
129
+ },
130
+ };
131
+ const paramsList = await def.getParams(getParamsCtx);
132
+ debug?.(
133
+ "getParams %s -> %d params (%sms)",
134
+ routeName,
135
+ paramsList.length,
136
+ (performance.now() - getParamsStart).toFixed(1),
93
137
  );
94
- // Anonymous wildcard fallback: use conventional keys if provided
95
- if (url.includes("*")) {
96
- const wildcardValue =
97
- (params as Record<string, string>)["*"] ??
98
- (params as Record<string, string>).splat;
99
- if (wildcardValue !== undefined) {
100
- url = url.replace(/\*[^/]*$/, encodePathParam(wildcardValue));
138
+ const concurrency = def.options?.concurrency ?? 1;
139
+ const hasBuildVars = hasContextVars(buildVars);
140
+ for (const params of paramsList) {
141
+ let url = substituteRouteParams(
142
+ pattern,
143
+ params as Record<string, string>,
144
+ encodePathParam,
145
+ );
146
+ // Anonymous wildcard fallback: use conventional keys if provided
147
+ if (url.includes("*")) {
148
+ const wildcardValue =
149
+ (params as Record<string, string>)["*"] ??
150
+ (params as Record<string, string>).splat;
151
+ if (wildcardValue !== undefined) {
152
+ url = url.replace(
153
+ /\*[^/]*$/,
154
+ encodePathParam(wildcardValue),
155
+ );
156
+ }
101
157
  }
158
+ entries.push({
159
+ urlPath: url.replace(/\/$/, "") || "/",
160
+ routeName,
161
+ concurrency,
162
+ ...(hasBuildVars ? { buildVars } : {}),
163
+ isPassthroughRoute,
164
+ });
102
165
  }
103
- entries.push({
104
- urlPath: url.replace(/\/$/, "") || "/",
105
- routeName,
106
- concurrency,
107
- ...(hasBuildVars ? { buildVars } : {}),
108
- isPassthroughRoute,
109
- });
110
- }
111
- } catch (err: any) {
112
- // Skip in getParams() skips the entire route
113
- if (err.name === "Skip") {
114
- console.log(
115
- `[rsc-router] SKIP route "${routeName}" - ${err.message}`,
116
- );
117
- notifyOnError(
118
- registry,
119
- err,
120
- "prerender",
121
- routeName,
122
- undefined,
123
- true,
166
+ resolvedRoutes++;
167
+ } catch (err: any) {
168
+ resolvedRoutes++;
169
+ // Skip in getParams() skips the entire route
170
+ if (err.name === "Skip") {
171
+ console.log(
172
+ `[rango] SKIP route "${routeName}" - ${err.message}`,
173
+ );
174
+ notifyOnError(
175
+ registry,
176
+ err,
177
+ "prerender",
178
+ routeName,
179
+ undefined,
180
+ true,
181
+ );
182
+ continue;
183
+ }
184
+ // Regular error: fail the build
185
+ console.error(
186
+ `[rango] Failed to get params for prerender route "${routeName}": ${err.message}`,
124
187
  );
125
- continue;
188
+ notifyOnError(registry, err, "prerender", routeName);
189
+ throw err;
126
190
  }
127
- // Regular error: fail the build
128
- console.error(
129
- `[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`,
191
+ } else {
192
+ console.warn(
193
+ `[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
130
194
  );
131
- notifyOnError(registry, err, "prerender", routeName);
132
- throw err;
133
195
  }
134
- } else {
135
- console.warn(
136
- `[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
137
- );
138
196
  }
139
197
  }
140
198
  }
199
+ } finally {
200
+ if (progressInterval) {
201
+ clearInterval(progressInterval);
202
+ const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
203
+ console.log(
204
+ `[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
205
+ );
206
+ }
141
207
  }
142
208
 
143
- if (entries.length === 0) return;
209
+ if (entries.length === 0) {
210
+ debug?.(
211
+ "no prerender entries (done in %sms)",
212
+ (performance.now() - overallStart).toFixed(1),
213
+ );
214
+ return;
215
+ }
144
216
 
145
217
  // Determine the max concurrency for the log header
146
218
  const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
147
219
  const concurrencyNote =
148
220
  maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
149
221
  console.log(
150
- `[rsc-router] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`,
222
+ `[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`,
223
+ );
224
+ debug?.(
225
+ "prerender loop: %d entries, max concurrency %d",
226
+ entries.length,
227
+ maxConcurrency,
151
228
  );
152
229
 
153
230
  const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
@@ -155,6 +232,10 @@ export async function expandPrerenderRoutes(
155
232
  const manifestEntries: Record<string, string> = {};
156
233
  let doneCount = 0;
157
234
  let skipCount = 0;
235
+ // #587: a render error reaches here (matchForPrerender now re-throws it rather
236
+ // than baking the error boundary). Default "fail" fails the build; "warn" logs
237
+ // and skips baking the URL.
238
+ const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
158
239
  const startTotal = performance.now();
159
240
 
160
241
  // Group entries by concurrency for batched rendering.
@@ -175,6 +256,7 @@ export async function expandPrerenderRoutes(
175
256
  {},
176
257
  entry.buildVars,
177
258
  entry.isPassthroughRoute,
259
+ state.resolvedBuildEnv,
178
260
  );
179
261
  if (!result) continue;
180
262
 
@@ -182,7 +264,7 @@ export async function expandPrerenderRoutes(
182
264
  if (result.passthrough) {
183
265
  const elapsed = (performance.now() - startUrl).toFixed(0);
184
266
  console.log(
185
- `[rsc-router] PASS ${entry.urlPath.padEnd(40)} (${elapsed}ms) - live fallback`,
267
+ `[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed}ms) - live fallback`,
186
268
  );
187
269
  doneCount++;
188
270
  break;
@@ -203,10 +285,9 @@ export async function expandPrerenderRoutes(
203
285
  const interceptKey = `${result.routeName}/${paramHash}/i`;
204
286
  const interceptValue = JSON.stringify({
205
287
  segments: [...result.segments, ...result.interceptSegments],
206
- handles: {
207
- ...result.handles,
208
- ...(result.interceptHandles || {}),
209
- },
288
+ // interceptHandles is the pre-encoded MERGED (main + intercept)
289
+ // handle string (the producer merged before encoding).
290
+ handles: result.interceptHandles ?? "",
210
291
  });
211
292
  manifestEntries[interceptKey] = stageBuildAssetModule(
212
293
  state.projectRoot,
@@ -216,40 +297,27 @@ export async function expandPrerenderRoutes(
216
297
  }
217
298
  const elapsed = (performance.now() - startUrl).toFixed(0);
218
299
  console.log(
219
- `[rsc-router] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`,
300
+ `[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`,
220
301
  );
221
302
  doneCount++;
222
303
  break;
223
304
  } catch (err: any) {
224
- if (err.name === "Skip") {
225
- const elapsed = (performance.now() - startUrl).toFixed(0);
226
- console.log(
227
- `[rsc-router] SKIP ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
228
- );
229
- skipCount++;
230
- notifyOnError(
231
- registry,
232
- err,
233
- "prerender",
234
- entry.routeName,
235
- entry.urlPath,
236
- true,
237
- );
238
- break;
239
- }
240
- // Regular error: log, notify, and fail the build
305
+ // Skip, or a render error under prerender.onError "warn": skip the
306
+ // URL (never bake the error page, #587). A render error under the
307
+ // default "fail" re-throws below to fail the build.
241
308
  const elapsed = (performance.now() - startUrl).toFixed(0);
242
- console.error(
243
- `[rsc-router] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
244
- );
245
- notifyOnError(
309
+ resolvePrerenderError(
246
310
  registry,
247
311
  err,
312
+ prerenderOnError,
313
+ entry.urlPath.padEnd(40),
314
+ elapsed,
248
315
  "prerender",
249
316
  entry.routeName,
250
317
  entry.urlPath,
251
318
  );
252
- throw err;
319
+ skipCount++;
320
+ break;
253
321
  }
254
322
  }
255
323
  },
@@ -263,7 +331,14 @@ export async function expandPrerenderRoutes(
263
331
  const parts = [`${doneCount} done`];
264
332
  if (skipCount > 0) parts.push(`${skipCount} skipped`);
265
333
  console.log(
266
- `[rsc-router] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`,
334
+ `[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`,
335
+ );
336
+ debug?.(
337
+ "expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
338
+ doneCount,
339
+ skipCount,
340
+ totalElapsed,
341
+ (performance.now() - overallStart).toFixed(1),
267
342
  );
268
343
  }
269
344
 
@@ -285,19 +360,24 @@ export async function renderStaticHandlers(
285
360
  )
286
361
  return;
287
362
 
363
+ const overallStart = debug ? performance.now() : 0;
364
+ debug?.(
365
+ "renderStaticHandlers: start (%d static module(s))",
366
+ state.resolvedStaticModules.size,
367
+ );
368
+
288
369
  const manifestEntries: Record<string, string> = {};
289
370
  let staticDone = 0;
290
371
  let staticSkip = 0;
291
372
  let totalStaticCount = 0;
373
+ const prerenderOnError = state.opts?.prerenderOnError ?? "fail";
292
374
 
293
375
  // Count handlers for the log header
294
376
  for (const [, exportNames] of state.resolvedStaticModules) {
295
377
  totalStaticCount += exportNames.length;
296
378
  }
297
379
  const startStatic = performance.now();
298
- console.log(
299
- `[rsc-router] Rendering ${totalStaticCount} static handler(s)...`,
300
- );
380
+ console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
301
381
 
302
382
  for (const [moduleId, exportNames] of state.resolvedStaticModules) {
303
383
  let mod: any;
@@ -305,7 +385,7 @@ export async function renderStaticHandlers(
305
385
  mod = await rscEnv!.runner.import(moduleId);
306
386
  } catch (err: any) {
307
387
  console.error(
308
- `[rsc-router] Failed to import static module ${moduleId}: ${err.message}`,
388
+ `[rango] Failed to import static module ${moduleId}: ${err.message}`,
309
389
  );
310
390
  notifyOnError(registry, err, "static");
311
391
  throw err;
@@ -326,9 +406,12 @@ export async function renderStaticHandlers(
326
406
  def.handler,
327
407
  def.$$id,
328
408
  (def as any).$$routePrefix,
409
+ state.resolvedBuildEnv,
410
+ !state.isBuildMode,
329
411
  );
330
412
  if (result) {
331
- const hasHandles = Object.keys(result.handles).length > 0;
413
+ // result.handles is the pre-encoded handle string ("" when none).
414
+ const hasHandles = result.handles !== "";
332
415
  const exportValue = hasHandles
333
416
  ? JSON.stringify(result)
334
417
  : JSON.stringify(result.encoded);
@@ -338,37 +421,29 @@ export async function renderStaticHandlers(
338
421
  exportValue,
339
422
  );
340
423
  const elapsed = (performance.now() - startHandler).toFixed(0);
341
- console.log(
342
- `[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`,
343
- );
424
+ console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
344
425
  staticDone++;
345
426
  handled = true;
346
427
  break;
347
428
  }
348
429
  } catch (err: any) {
349
- if (err.name === "Skip") {
350
- const elapsed = (performance.now() - startHandler).toFixed(0);
351
- console.log(
352
- `[rsc-router] SKIP ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
353
- );
354
- staticSkip++;
355
- notifyOnError(registry, err, "static", undefined, undefined, true);
356
- handled = true;
357
- break;
358
- }
359
- // Regular error: log, notify, and fail the build
430
+ // Same Skip/warn/fail policy as the prerender loop (shared helper).
360
431
  const elapsed = (performance.now() - startHandler).toFixed(0);
361
- console.error(
362
- `[rsc-router] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
432
+ resolvePrerenderError(
433
+ registry,
434
+ err,
435
+ prerenderOnError,
436
+ name.padEnd(40),
437
+ elapsed,
438
+ "static",
363
439
  );
364
- notifyOnError(registry, err, "static");
365
- throw err;
440
+ staticSkip++;
441
+ handled = true;
442
+ break;
366
443
  }
367
444
  }
368
445
  if (!handled) {
369
- console.warn(
370
- `[rsc-router] No router could render static handler "${name}"`,
371
- );
446
+ console.warn(`[rango] No router could render static handler "${name}"`);
372
447
  }
373
448
  }
374
449
  }
@@ -380,6 +455,13 @@ export async function renderStaticHandlers(
380
455
  const staticParts = [`${staticDone} done`];
381
456
  if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
382
457
  console.log(
383
- `[rsc-router] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`,
458
+ `[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`,
459
+ );
460
+ debug?.(
461
+ "renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
462
+ staticDone,
463
+ staticSkip,
464
+ totalStaticElapsed,
465
+ (performance.now() - overallStart).toFixed(1),
384
466
  );
385
467
  }