@rangojs/router 0.0.0-experimental.1b930379 → 0.0.0-experimental.1c0bdfad

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 (400) hide show
  1. package/AGENTS.md +12 -0
  2. package/README.md +245 -49
  3. package/dist/bin/rango.js +441 -134
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3453 -1240
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +76 -21
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +64 -2
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +247 -23
  12. package/skills/caching/SKILL.md +318 -15
  13. package/skills/composability/SKILL.md +27 -2
  14. package/skills/css/SKILL.md +76 -0
  15. package/skills/debug-manifest/SKILL.md +4 -2
  16. package/skills/document-cache/SKILL.md +78 -55
  17. package/skills/handler-use/SKILL.md +364 -0
  18. package/skills/hooks/SKILL.md +250 -30
  19. package/skills/host-router/SKILL.md +83 -23
  20. package/skills/i18n/SKILL.md +276 -0
  21. package/skills/intercept/SKILL.md +50 -6
  22. package/skills/layout/SKILL.md +35 -9
  23. package/skills/links/SKILL.md +249 -17
  24. package/skills/loader/SKILL.md +279 -53
  25. package/skills/middleware/SKILL.md +52 -13
  26. package/skills/migrate-nextjs/SKILL.md +584 -0
  27. package/skills/migrate-react-router/SKILL.md +771 -0
  28. package/skills/mime-routes/SKILL.md +28 -1
  29. package/skills/observability/SKILL.md +172 -0
  30. package/skills/parallel/SKILL.md +203 -7
  31. package/skills/prerender/SKILL.md +153 -109
  32. package/skills/rango/SKILL.md +251 -22
  33. package/skills/react-compiler/SKILL.md +168 -0
  34. package/skills/response-routes/SKILL.md +123 -48
  35. package/skills/route/SKILL.md +101 -5
  36. package/skills/router-setup/SKILL.md +116 -8
  37. package/skills/scripts/SKILL.md +179 -0
  38. package/skills/server-actions/SKILL.md +775 -0
  39. package/skills/streams-and-websockets/SKILL.md +283 -0
  40. package/skills/tailwind/SKILL.md +27 -3
  41. package/skills/testing/SKILL.md +129 -0
  42. package/skills/testing/bindings.md +103 -0
  43. package/skills/testing/cache-prerender.md +127 -0
  44. package/skills/testing/client-components.md +124 -0
  45. package/skills/testing/e2e-parity.md +125 -0
  46. package/skills/testing/flight.md +91 -0
  47. package/skills/testing/handles.md +129 -0
  48. package/skills/testing/loader.md +128 -0
  49. package/skills/testing/middleware.md +99 -0
  50. package/skills/testing/render-handler.md +121 -0
  51. package/skills/testing/response-routes.md +95 -0
  52. package/skills/testing/reverse-and-types.md +84 -0
  53. package/skills/testing/server-actions.md +107 -0
  54. package/skills/testing/server-tree.md +128 -0
  55. package/skills/testing/setup.md +123 -0
  56. package/skills/typesafety/SKILL.md +332 -29
  57. package/skills/use-cache/SKILL.md +46 -14
  58. package/skills/view-transitions/SKILL.md +294 -0
  59. package/src/__augment-tests__/augment.ts +81 -0
  60. package/src/__augment-tests__/augmented.check.ts +116 -0
  61. package/src/__internal.ts +1 -66
  62. package/src/browser/action-coordinator.ts +53 -36
  63. package/src/browser/action-fence.ts +47 -0
  64. package/src/browser/app-shell.ts +39 -0
  65. package/src/browser/app-version.ts +14 -0
  66. package/src/browser/connection-warmup.ts +134 -0
  67. package/src/browser/cookie-name.ts +140 -0
  68. package/src/browser/event-controller.ts +197 -150
  69. package/src/browser/history-state.ts +21 -0
  70. package/src/browser/index.ts +3 -3
  71. package/src/browser/invalidate-client-cache.ts +52 -0
  72. package/src/browser/navigation-bridge.ts +111 -31
  73. package/src/browser/navigation-client.ts +201 -67
  74. package/src/browser/navigation-store-handle.ts +38 -0
  75. package/src/browser/navigation-store.ts +76 -67
  76. package/src/browser/navigation-transaction.ts +18 -66
  77. package/src/browser/network-error-handler.ts +34 -7
  78. package/src/browser/partial-update.ts +187 -112
  79. package/src/browser/prefetch/cache.ts +230 -35
  80. package/src/browser/prefetch/fetch.ts +338 -39
  81. package/src/browser/prefetch/queue.ts +126 -20
  82. package/src/browser/prefetch/resource-ready.ts +77 -0
  83. package/src/browser/rango-state.ts +158 -76
  84. package/src/browser/react/Link.tsx +111 -16
  85. package/src/browser/react/NavigationProvider.tsx +135 -120
  86. package/src/browser/react/ScrollRestoration.tsx +10 -6
  87. package/src/browser/react/context.ts +7 -2
  88. package/src/browser/react/filter-segment-order.ts +66 -7
  89. package/src/browser/react/index.ts +0 -48
  90. package/src/browser/react/location-state-shared.ts +178 -8
  91. package/src/browser/react/location-state.ts +39 -14
  92. package/src/browser/react/use-action.ts +6 -15
  93. package/src/browser/react/use-handle.ts +23 -69
  94. package/src/browser/react/use-href.tsx +8 -1
  95. package/src/browser/react/use-link-status.ts +33 -8
  96. package/src/browser/react/use-navigation.ts +32 -7
  97. package/src/browser/react/use-params.ts +20 -10
  98. package/src/browser/react/use-reverse.ts +106 -0
  99. package/src/browser/react/use-router.ts +46 -11
  100. package/src/browser/react/use-search-params.ts +0 -5
  101. package/src/browser/react/use-segments.ts +11 -21
  102. package/src/browser/response-adapter.ts +80 -5
  103. package/src/browser/rsc-router.tsx +218 -76
  104. package/src/browser/scroll-restoration.ts +54 -42
  105. package/src/browser/segment-reconciler.ts +36 -9
  106. package/src/browser/segment-structure-assert.ts +2 -2
  107. package/src/browser/server-action-bridge.ts +222 -61
  108. package/src/browser/types.ts +91 -11
  109. package/src/browser/validate-redirect-origin.ts +43 -16
  110. package/src/build/collect-fallback-refs.ts +107 -0
  111. package/src/build/generate-manifest.ts +65 -40
  112. package/src/build/generate-route-types.ts +5 -1
  113. package/src/build/index.ts +8 -2
  114. package/src/build/prefix-tree-utils.ts +123 -0
  115. package/src/build/route-trie.ts +165 -36
  116. package/src/build/route-types/ast-route-extraction.ts +15 -8
  117. package/src/build/route-types/codegen.ts +16 -5
  118. package/src/build/route-types/include-resolution.ts +125 -24
  119. package/src/build/route-types/param-extraction.ts +6 -3
  120. package/src/build/route-types/per-module-writer.ts +22 -6
  121. package/src/build/route-types/router-processing.ts +272 -96
  122. package/src/build/route-types/scan-filter.ts +9 -2
  123. package/src/build/route-types/source-scan.ts +216 -0
  124. package/src/build/runtime-discovery.ts +9 -20
  125. package/src/cache/cache-error.ts +104 -0
  126. package/src/cache/cache-key-utils.ts +29 -13
  127. package/src/cache/cache-policy.ts +108 -34
  128. package/src/cache/cache-runtime.ts +214 -48
  129. package/src/cache/cache-scope.ts +236 -89
  130. package/src/cache/cache-tag.ts +103 -0
  131. package/src/cache/cf/cf-base64.ts +33 -0
  132. package/src/cache/cf/cf-cache-constants.ts +127 -0
  133. package/src/cache/cf/cf-cache-store.ts +2224 -171
  134. package/src/cache/cf/cf-cache-types.ts +349 -0
  135. package/src/cache/cf/cf-kv-utils.ts +46 -0
  136. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  137. package/src/cache/cf/index.ts +11 -17
  138. package/src/cache/document-cache.ts +89 -27
  139. package/src/cache/handle-snapshot.ts +70 -0
  140. package/src/cache/index.ts +11 -20
  141. package/src/cache/memory-segment-store.ts +136 -37
  142. package/src/cache/profile-registry.ts +31 -31
  143. package/src/cache/read-through-swr.ts +41 -11
  144. package/src/cache/segment-codec.ts +9 -17
  145. package/src/cache/tag-invalidation.ts +230 -0
  146. package/src/cache/taint.ts +55 -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 +84 -2
  155. package/src/debug.ts +2 -2
  156. package/src/decode-loader-results.ts +52 -0
  157. package/src/defer.ts +196 -0
  158. package/src/deps/ssr.ts +0 -1
  159. package/src/encode-kv.ts +49 -0
  160. package/src/errors.ts +30 -4
  161. package/src/escape-script.ts +52 -0
  162. package/src/handle.ts +70 -22
  163. package/src/handles/MetaTags.tsx +56 -19
  164. package/src/handles/Scripts.tsx +183 -0
  165. package/src/handles/breadcrumbs.ts +37 -8
  166. package/src/handles/is-thenable.ts +19 -0
  167. package/src/handles/meta.ts +51 -40
  168. package/src/handles/script.ts +244 -0
  169. package/src/host/cookie-handler.ts +9 -60
  170. package/src/host/errors.ts +0 -24
  171. package/src/host/index.ts +8 -2
  172. package/src/host/pattern-matcher.ts +23 -52
  173. package/src/host/router.ts +107 -99
  174. package/src/host/testing.ts +40 -27
  175. package/src/host/types.ts +37 -4
  176. package/src/host/utils.ts +1 -1
  177. package/src/href-client.ts +137 -22
  178. package/src/index.rsc.ts +93 -12
  179. package/src/index.ts +133 -15
  180. package/src/internal-debug.ts +11 -10
  181. package/src/loader-store.ts +500 -0
  182. package/src/loader.rsc.ts +20 -13
  183. package/src/loader.ts +12 -11
  184. package/src/missing-id-error.ts +68 -0
  185. package/src/outlet-context.ts +1 -1
  186. package/src/outlet-provider.tsx +1 -5
  187. package/src/prerender/param-hash.ts +16 -16
  188. package/src/prerender/store.ts +37 -41
  189. package/src/prerender.ts +198 -82
  190. package/src/redirect-origin.ts +100 -0
  191. package/src/regex-escape.ts +8 -0
  192. package/src/render-error-thrower.tsx +20 -0
  193. package/src/response-utils.ts +62 -0
  194. package/src/reverse.ts +65 -15
  195. package/src/root-error-boundary.tsx +1 -19
  196. package/src/route-content-wrapper.tsx +7 -72
  197. package/src/route-definition/dsl-helpers.ts +469 -276
  198. package/src/route-definition/helper-factories.ts +29 -139
  199. package/src/route-definition/helpers-types.ts +113 -37
  200. package/src/route-definition/index.ts +3 -0
  201. package/src/route-definition/redirect.ts +53 -12
  202. package/src/route-definition/resolve-handler-use.ts +161 -0
  203. package/src/route-definition/use-item-types.ts +32 -0
  204. package/src/route-map-builder.ts +7 -17
  205. package/src/route-types.ts +37 -41
  206. package/src/router/basename.ts +14 -0
  207. package/src/router/content-negotiation.ts +164 -17
  208. package/src/router/error-handling.ts +45 -18
  209. package/src/router/find-match.ts +45 -22
  210. package/src/router/handler-context.ts +83 -39
  211. package/src/router/instrument.ts +350 -0
  212. package/src/router/intercept-resolution.ts +50 -24
  213. package/src/router/lazy-includes.ts +19 -53
  214. package/src/router/loader-resolution.ts +274 -56
  215. package/src/router/logging.ts +5 -8
  216. package/src/router/manifest.ts +49 -45
  217. package/src/router/match-api.ts +120 -204
  218. package/src/router/match-context.ts +0 -22
  219. package/src/router/match-handlers.ts +58 -58
  220. package/src/router/match-middleware/background-revalidation.ts +33 -6
  221. package/src/router/match-middleware/cache-lookup.ts +214 -263
  222. package/src/router/match-middleware/cache-store.ts +73 -33
  223. package/src/router/match-middleware/intercept-resolution.ts +8 -28
  224. package/src/router/match-middleware/segment-resolution.ts +52 -18
  225. package/src/router/match-pipelines.ts +1 -42
  226. package/src/router/match-result.ts +104 -40
  227. package/src/router/metrics.ts +5 -34
  228. package/src/router/middleware-types.ts +13 -142
  229. package/src/router/middleware.ts +270 -172
  230. package/src/router/navigation-snapshot.ts +131 -0
  231. package/src/router/params-util.ts +23 -0
  232. package/src/router/pattern-matching.ts +132 -90
  233. package/src/router/prefetch-cache-ttl.ts +51 -0
  234. package/src/router/prerender-match.ts +195 -56
  235. package/src/router/preview-match.ts +32 -102
  236. package/src/router/request-classification.ts +276 -0
  237. package/src/router/revalidation.ts +123 -73
  238. package/src/router/route-snapshot.ts +244 -0
  239. package/src/router/router-context.ts +8 -28
  240. package/src/router/router-interfaces.ts +115 -35
  241. package/src/router/router-options.ts +172 -15
  242. package/src/router/router-registry.ts +2 -5
  243. package/src/router/segment-resolution/fresh.ts +264 -77
  244. package/src/router/segment-resolution/helpers.ts +115 -30
  245. package/src/router/segment-resolution/loader-cache.ts +63 -37
  246. package/src/router/segment-resolution/revalidation.ts +474 -385
  247. package/src/router/segment-resolution/static-store.ts +19 -5
  248. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  249. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  250. package/src/router/segment-resolution.ts +5 -1
  251. package/src/router/segment-wrappers.ts +8 -5
  252. package/src/router/state-cookie-name.ts +33 -0
  253. package/src/router/substitute-pattern-params.ts +56 -0
  254. package/src/router/telemetry-otel.ts +161 -199
  255. package/src/router/telemetry.ts +96 -19
  256. package/src/router/timeout.ts +0 -20
  257. package/src/router/tracing.ts +206 -0
  258. package/src/router/trie-matching.ts +163 -59
  259. package/src/router/types.ts +10 -63
  260. package/src/router/url-params.ts +44 -0
  261. package/src/router.ts +163 -55
  262. package/src/rsc/handler-context.ts +3 -2
  263. package/src/rsc/handler.ts +658 -511
  264. package/src/rsc/helpers.ts +168 -46
  265. package/src/rsc/index.ts +2 -5
  266. package/src/rsc/json-route-result.ts +38 -0
  267. package/src/rsc/loader-fetch.ts +127 -31
  268. package/src/rsc/manifest-init.ts +33 -42
  269. package/src/rsc/origin-guard.ts +39 -25
  270. package/src/rsc/progressive-enhancement.ts +77 -11
  271. package/src/rsc/redirect-guard.ts +99 -0
  272. package/src/rsc/response-cache-serve.ts +238 -0
  273. package/src/rsc/response-error.ts +79 -12
  274. package/src/rsc/response-route-handler.ts +99 -189
  275. package/src/rsc/rsc-rendering.ts +105 -72
  276. package/src/rsc/runtime-warnings.ts +23 -10
  277. package/src/rsc/server-action.ts +263 -112
  278. package/src/rsc/ssr-setup.ts +18 -2
  279. package/src/rsc/types.ts +32 -6
  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 +281 -129
  285. package/src/serialize.ts +243 -0
  286. package/src/server/context.ts +309 -61
  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 +26 -46
  291. package/src/server/request-context.ts +398 -172
  292. package/src/ssr/index.tsx +25 -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 +99 -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 +343 -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/vitest-stubs/cloudflare-email.ts +9 -0
  320. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  321. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  322. package/src/testing/vitest-stubs/version.ts +5 -0
  323. package/src/testing/vitest.ts +305 -0
  324. package/src/theme/ThemeProvider.tsx +20 -58
  325. package/src/theme/ThemeScript.tsx +7 -9
  326. package/src/theme/constants.ts +52 -13
  327. package/src/theme/index.ts +0 -7
  328. package/src/theme/theme-context.ts +1 -5
  329. package/src/theme/theme-script.ts +22 -21
  330. package/src/theme/use-theme.ts +0 -3
  331. package/src/types/boundaries.ts +0 -35
  332. package/src/types/cache-types.ts +17 -8
  333. package/src/types/error-types.ts +30 -90
  334. package/src/types/global-namespace.ts +54 -41
  335. package/src/types/handler-context.ts +233 -81
  336. package/src/types/index.ts +1 -10
  337. package/src/types/loader-types.ts +44 -15
  338. package/src/types/request-scope.ts +112 -0
  339. package/src/types/route-config.ts +6 -50
  340. package/src/types/route-entry.ts +19 -7
  341. package/src/types/segments.ts +37 -14
  342. package/src/urls/include-helper.ts +33 -70
  343. package/src/urls/index.ts +1 -11
  344. package/src/urls/path-helper-types.ts +58 -11
  345. package/src/urls/path-helper.ts +57 -111
  346. package/src/urls/pattern-types.ts +48 -19
  347. package/src/urls/response-types.ts +25 -22
  348. package/src/urls/type-extraction.ts +58 -139
  349. package/src/urls/urls-function.ts +1 -18
  350. package/src/use-loader.tsx +346 -89
  351. package/src/vite/debug.ts +185 -0
  352. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  353. package/src/vite/discovery/discover-routers.ts +130 -85
  354. package/src/vite/discovery/discovery-errors.ts +194 -0
  355. package/src/vite/discovery/gate-state.ts +171 -0
  356. package/src/vite/discovery/prerender-collection.ts +214 -132
  357. package/src/vite/discovery/route-types-writer.ts +40 -84
  358. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  359. package/src/vite/discovery/state.ts +57 -6
  360. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  361. package/src/vite/index.ts +6 -0
  362. package/src/vite/inject-client-debug.ts +36 -0
  363. package/src/vite/plugin-types.ts +155 -65
  364. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  365. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  366. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  367. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  368. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  369. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  370. package/src/vite/plugins/expose-action-id.ts +49 -98
  371. package/src/vite/plugins/expose-id-utils.ts +96 -51
  372. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  373. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  374. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  375. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  376. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  377. package/src/vite/plugins/performance-tracks.ts +89 -0
  378. package/src/vite/plugins/refresh-cmd.ts +89 -27
  379. package/src/vite/plugins/use-cache-transform.ts +73 -83
  380. package/src/vite/plugins/version-injector.ts +21 -25
  381. package/src/vite/plugins/version-plugin.ts +46 -37
  382. package/src/vite/plugins/virtual-entries.ts +13 -18
  383. package/src/vite/rango.ts +238 -295
  384. package/src/vite/router-discovery.ts +940 -149
  385. package/src/vite/utils/ast-handler-extract.ts +26 -35
  386. package/src/vite/utils/banner.ts +4 -4
  387. package/src/vite/utils/bundle-analysis.ts +10 -15
  388. package/src/vite/utils/client-chunks.ts +184 -0
  389. package/src/vite/utils/directive-prologue.ts +40 -0
  390. package/src/vite/utils/forward-user-plugins.ts +171 -0
  391. package/src/vite/utils/manifest-utils.ts +4 -59
  392. package/src/vite/utils/package-resolution.ts +20 -52
  393. package/src/vite/utils/prerender-utils.ts +81 -34
  394. package/src/vite/utils/shared-utils.ts +92 -42
  395. package/src/browser/action-response-classifier.ts +0 -99
  396. package/src/browser/react/use-client-cache.ts +0 -58
  397. package/src/browser/shallow.ts +0 -40
  398. package/src/handles/index.ts +0 -7
  399. package/src/network-error-thrower.tsx +0 -23
  400. package/src/router/middleware-cookies.ts +0 -55
@@ -0,0 +1,44 @@
1
+ /**
2
+ * URL param encode/decode at the route boundary.
3
+ *
4
+ * Extraction (decode): regex/trie matchers keep param values URL-encoded;
5
+ * `safeDecodeURIComponent` turns them back into raw strings so `ctx.params`
6
+ * matches the contract apps expect (Express/React Router/Fastify/Koa) and
7
+ * round-trips through reverse stay stable. Malformed %-encoding is
8
+ * preserved as-is so a broken URL doesn't crash matching.
9
+ *
10
+ * Reversal (encode): `encodePathSegment` escapes only what RFC 3986
11
+ * requires for a path segment — `/`, `?`, `#`, space, control chars,
12
+ * non-ASCII — and leaves pchar sub-delims (`@ : $ & + , ; =` and friends)
13
+ * readable. `encodeURIComponent` over-encodes for path segments, which
14
+ * makes generated URLs harder for humans to read in the address bar
15
+ * (e.g. mailbox IDs like `ivo@example.com` would become
16
+ * `ivo%40example.com` even though `@` is path-legal).
17
+ */
18
+
19
+ export function safeDecodeURIComponent(raw: string): string {
20
+ if (raw === "" || raw.indexOf("%") === -1) return raw;
21
+ try {
22
+ return decodeURIComponent(raw);
23
+ } catch {
24
+ return raw;
25
+ }
26
+ }
27
+
28
+ const PATH_SAFE_ESCAPES: Record<string, string> = {
29
+ "%3A": ":",
30
+ "%40": "@",
31
+ "%24": "$",
32
+ "%26": "&",
33
+ "%2B": "+",
34
+ "%2C": ",",
35
+ "%3B": ";",
36
+ "%3D": "=",
37
+ };
38
+
39
+ export function encodePathSegment(value: string): string {
40
+ return encodeURIComponent(value).replace(
41
+ /%(?:3A|40|24|26|2B|2C|3B|3D)/gi,
42
+ (match) => PATH_SAFE_ESCAPES[match.toUpperCase()] ?? match,
43
+ );
44
+ }
package/src/router.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { createCacheScope } from "./cache/cache-scope.js";
3
- import {
4
- setCacheProfiles,
5
- resolveCacheProfiles,
6
- } from "./cache/profile-registry.js";
3
+ import { resolveCacheProfiles } from "./cache/profile-registry.js";
7
4
  import { isCachedFunction } from "./cache/taint.js";
8
5
  import { assertClientComponent } from "./component-utils.js";
9
6
  import { DefaultDocument } from "./components/DefaultDocument.js";
@@ -19,11 +16,13 @@ import {
19
16
  import MapRootLayout from "./server/root-layout.js";
20
17
  import type { AllUseItems } from "./route-types.js";
21
18
  import type { UrlPatterns } from "./urls.js";
19
+ import type { UrlBuilder } from "./urls/pattern-types.js";
20
+ import { urls } from "./urls.js";
21
+ import { buildPrecomputedByPrefix } from "./build/prefix-tree-utils.js";
22
22
  import {
23
- EntryData,
24
- InterceptSelectorContext,
23
+ type EntryData,
25
24
  getContext,
26
- RSCRouterContext,
25
+ RangoContext,
27
26
  type MetricsStore,
28
27
  } from "./server/context";
29
28
  import { createHandleStore, type HandleStore } from "./server/handle-store.js";
@@ -55,6 +54,7 @@ import { buildDebugManifest } from "./router/debug-manifest.js";
55
54
 
56
55
  import type { SegmentResolutionDeps, MatchApiDeps } from "./router/types.js";
57
56
  import { createHandlerContext } from "./router/handler-context.js";
57
+ import { normalizeBasename } from "./router/basename.js";
58
58
  import {
59
59
  setupLoaderAccess,
60
60
  setupLoaderAccessSilent,
@@ -63,15 +63,17 @@ import {
63
63
  import { loadManifest } from "./router/manifest.js";
64
64
  import { createMetricsStore } from "./router/metrics.js";
65
65
  import {
66
- parsePattern,
66
+ compileMiddlewarePattern,
67
67
  type MiddlewareEntry,
68
68
  type MiddlewareFn,
69
69
  } from "./router/middleware.js";
70
70
  import {
71
71
  extractStaticPrefix,
72
+ joinPrefix,
72
73
  traverseBack,
73
74
  } from "./router/pattern-matching.js";
74
75
  import { resolveSink, safeEmit, getRequestId } from "./router/telemetry.js";
76
+ import { resolveTracing } from "./router/tracing.js";
75
77
  import { evaluateRevalidation } from "./router/revalidation.js";
76
78
  import {
77
79
  type RouterContext,
@@ -89,13 +91,10 @@ import {
89
91
  RouterRegistry,
90
92
  nextRouterAutoId,
91
93
  } from "./router/router-registry.js";
94
+ import type { RangoOptions, RootLayoutProps } from "./router/router-options.js";
92
95
  import type {
93
- RSCRouterOptions,
94
- RootLayoutProps,
95
- } from "./router/router-options.js";
96
- import type {
97
- RSCRouter,
98
- RSCRouterInternal,
96
+ Rango,
97
+ RangoInternal,
99
98
  RouterRequestInput,
100
99
  } from "./router/router-interfaces.js";
101
100
 
@@ -110,29 +109,32 @@ import {
110
109
  matchForPrerender as _matchForPrerender,
111
110
  renderStaticSegment as _renderStaticSegment,
112
111
  } from "./router/prerender-match.js";
112
+ import { resolveStateCookieName } from "./router/state-cookie-name.js";
113
+ import { resolvePrefetchCacheTTL } from "./router/prefetch-cache-ttl.js";
113
114
 
114
115
  // Re-export public types and values from extracted modules
115
116
  export { RSC_ROUTER_BRAND, RouterRegistry } from "./router/router-registry.js";
116
117
  export type {
117
- RSCRouterOptions,
118
+ RangoOptions,
118
119
  RootLayoutProps,
119
120
  SSRStreamMode,
120
121
  SSROptions,
121
122
  ResolveStreamingContext,
122
123
  } from "./router/router-options.js";
123
124
  export type {
124
- RSCRouter,
125
- RSCRouterInternal,
125
+ Rango,
126
+ RangoInternal,
126
127
  RouterRequestInput,
127
128
  } from "./router/router-interfaces.js";
128
129
  export { toInternal } from "./router/router-interfaces.js";
129
130
 
130
131
  export function createRouter<TEnv = any>(
131
- options: RSCRouterOptions<TEnv> = {},
132
- ): RSCRouter<TEnv, {}> {
132
+ options: RangoOptions<TEnv> = {},
133
+ ): Rango<TEnv, {}> {
133
134
  const {
134
135
  id: userProvidedId,
135
136
  $$id: injectedId,
137
+ basename: basenameOption,
136
138
  debugPerformance = false,
137
139
  document: documentOption,
138
140
  defaultErrorBoundary,
@@ -148,24 +150,46 @@ export function createRouter<TEnv = any>(
148
150
  nonce,
149
151
  version,
150
152
  prefetchCacheTTL: prefetchCacheTTLOption,
153
+ stateCookiePrefix: stateCookiePrefixOption,
151
154
  warmup: warmupOption,
152
155
  allowDebugManifest: allowDebugManifestOption = false,
153
156
  telemetry: telemetrySink,
157
+ tracing: tracingOption,
154
158
  ssr: ssrOption,
155
159
  timeout: timeoutShorthand,
156
160
  timeouts: timeoutsOption,
157
161
  onTimeout,
158
162
  originCheck: originCheckOption,
163
+ viewTransition: viewTransitionOption = "auto",
164
+ debugCacheSignal: debugCacheSignalOption = false,
165
+ strictMode: strictModeOption = true,
159
166
  } = options;
160
167
 
168
+ // Debug cache signal gate (DEVELOPMENT/TEST ONLY). Enabled by the
169
+ // debugCacheSignal option OR the RANGO_TEST_SIGNALS=1 env flag. When off,
170
+ // no X-Rango-Cache header is emitted and output is byte-identical.
171
+ const cacheSignalEnabled =
172
+ debugCacheSignalOption ||
173
+ (typeof process !== "undefined" &&
174
+ (process as { env?: Record<string, string | undefined> }).env
175
+ ?.RANGO_TEST_SIGNALS === "1");
176
+
177
+ // Normalize basename: ensure leading slash, strip trailing slash.
178
+ // A bare "/" is equivalent to no basename. Shared with the testing
179
+ // primitives via normalizeBasename so they can never drift.
180
+ const basename = normalizeBasename(basenameOption);
181
+
161
182
  // Resolve telemetry sink (no-op when not configured)
162
183
  const telemetry = resolveSink(telemetrySink);
163
184
 
164
- // Resolve cache profiles: merge user config with guaranteed default profile.
165
- // This resolved map is both stored on the router (for per-request context)
166
- // and written to the global registry (for DSL-time cache("profileName")).
185
+ // Resolve span tracing (undefined when not configured; every traceSpan() call
186
+ // is then a direct pass-through with zero behavior change).
187
+ const resolvedTracing = resolveTracing(tracingOption);
188
+
189
+ // Resolve cache profiles: merge user config with the guaranteed default
190
+ // profile. This resolved map is threaded onto each request context; the
191
+ // "use cache: <profile>" runtime path reads it request-scoped.
167
192
  const resolvedCacheProfiles = resolveCacheProfiles(cacheProfilesOption);
168
- setCacheProfiles(resolvedCacheProfiles);
169
193
 
170
194
  // Source file: prefer Vite-injected path (zero cost), fall back to
171
195
  // stack trace parsing for non-Vite environments (e.g. tests).
@@ -200,21 +224,32 @@ export function createRouter<TEnv = any>(
200
224
  const routerId =
201
225
  userProvidedId ?? injectedId ?? `router_${nextRouterAutoId()}`;
202
226
 
203
- // Resolve prefetch cache TTL (default: 300 seconds / 5 minutes)
204
- // Clamp to a non-negative integer for valid Cache-Control max-age.
205
- const rawTTL =
206
- prefetchCacheTTLOption !== undefined ? prefetchCacheTTLOption : 300;
207
- const prefetchCacheTTLSeconds =
208
- rawTTL === false ? 0 : Math.max(0, Math.floor(rawTTL));
209
- const prefetchCacheTTL = prefetchCacheTTLSeconds * 1000;
227
+ // Resolve the rango state cookie name once, here, so the two cookie writers
228
+ // (the client document.cookie writer and the server Set-Cookie writer)
229
+ // consume one pre-composed name and cannot drift.
230
+ const resolvedStateCookieName = resolveStateCookieName(
231
+ stateCookiePrefixOption,
232
+ routerId,
233
+ );
234
+
235
+ // Resolve prefetch cache TTL (default: 300 seconds / 5 minutes). Clamps to a
236
+ // non-negative integer and guards non-finite (NaN/Infinity) inputs so a
237
+ // malformed `Cache-Control: max-age=NaN` can never reach the wire.
238
+ const resolvedPrefetchCacheTTL = resolvePrefetchCacheTTL(
239
+ prefetchCacheTTLOption,
240
+ );
241
+ const prefetchCacheTTL = resolvedPrefetchCacheTTL.ms;
210
242
  const prefetchCacheControl: string | false =
211
- prefetchCacheTTLSeconds === 0
212
- ? false
213
- : `private, max-age=${prefetchCacheTTLSeconds}`;
243
+ resolvedPrefetchCacheTTL.cacheControl;
214
244
 
215
245
  // Resolve warmup enabled flag (default: true)
216
246
  const warmupEnabled = warmupOption !== false;
217
247
 
248
+ // Resolve StrictMode flag (default: true). Shipped to the client in payload
249
+ // metadata; the browser entry reads it once to decide whether to wrap the
250
+ // hydrated tree in React.StrictMode.
251
+ const strictMode = strictModeOption !== false;
252
+
218
253
  // Resolve theme config (null if theme not enabled)
219
254
  const resolvedThemeConfig = themeOption
220
255
  ? resolveThemeConfig(themeOption)
@@ -246,9 +281,14 @@ export function createRouter<TEnv = any>(
246
281
  invokeOnError(onError, error, phase, context, "Router");
247
282
  }
248
283
 
249
- // Validate document is a client component
284
+ // Validate document is a client component. Under a test runner the "use
285
+ // client" transform has not run, so a real exported document has no marker;
286
+ // allowServerInTest lets the router construct in a bare unit test (for
287
+ // dispatch / assertGeneratedRoutesMatch) while a real build still throws.
250
288
  if (documentOption !== undefined) {
251
- assertClientComponent(documentOption, "document");
289
+ assertClientComponent(documentOption, "document", {
290
+ allowServerInTest: true,
291
+ });
252
292
  }
253
293
 
254
294
  // Use default document if none provided (keeps internal name as rootLayout)
@@ -312,7 +352,7 @@ export function createRouter<TEnv = any>(
312
352
  let regex: RegExp | null = null;
313
353
  let paramNames: string[] = [];
314
354
  if (fullPattern) {
315
- const parsed = parsePattern(fullPattern);
355
+ const parsed = compileMiddlewarePattern(fullPattern);
316
356
  regex = parsed.regex;
317
357
  paramNames = parsed.paramNames;
318
358
  }
@@ -322,7 +362,6 @@ export function createRouter<TEnv = any>(
322
362
  regex,
323
363
  paramNames,
324
364
  handler,
325
- mountPrefix,
326
365
  });
327
366
  }
328
367
 
@@ -356,9 +395,11 @@ export function createRouter<TEnv = any>(
356
395
  getRouterPrecomputedEntries(routerId) ?? getPrecomputedEntries();
357
396
  if (current !== precomputedSource) {
358
397
  precomputedSource = current;
359
- precomputedByPrefix = current
360
- ? new Map(current.map((e) => [e.staticPrefix, e.routes]))
361
- : null;
398
+ // buildPrecomputedByPrefix drops any staticPrefix owned by more than one
399
+ // leaf include instead of collapsing it last-wins (which would mis-assign
400
+ // one include's routes to another's entry and 500 a valid sibling route).
401
+ // Such shared-prefix includes resolve via the handler path instead.
402
+ precomputedByPrefix = current ? buildPrecomputedByPrefix(current) : null;
362
403
  }
363
404
  return precomputedByPrefix;
364
405
  }
@@ -526,7 +567,9 @@ export function createRouter<TEnv = any>(
526
567
  trackHandler,
527
568
  findNearestErrorBoundary,
528
569
  findNearestNotFoundBoundary,
570
+ notFoundComponent: notFound,
529
571
  callOnError,
572
+ viewTransitionDefault: viewTransitionOption,
530
573
  };
531
574
 
532
575
  // Match API dependencies
@@ -560,6 +603,7 @@ export function createRouter<TEnv = any>(
560
603
  mergedRouteMap,
561
604
  nextMountIndex: () => mountIndex++,
562
605
  getPrecomputedByPrefix,
606
+ routerId,
563
607
  };
564
608
 
565
609
  function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
@@ -613,6 +657,8 @@ export function createRouter<TEnv = any>(
613
657
  params: Record<string, string>,
614
658
  buildVars?: Record<string, any>,
615
659
  isPassthroughRoute?: boolean,
660
+ buildEnv?: TEnv,
661
+ devMode?: boolean,
616
662
  ) {
617
663
  return _matchForPrerender(
618
664
  pathname,
@@ -620,6 +666,8 @@ export function createRouter<TEnv = any>(
620
666
  prerenderDeps,
621
667
  buildVars,
622
668
  isPassthroughRoute,
669
+ buildEnv,
670
+ devMode,
623
671
  );
624
672
  }
625
673
 
@@ -627,12 +675,16 @@ export function createRouter<TEnv = any>(
627
675
  handler: Function,
628
676
  handlerId: string,
629
677
  routeName?: string,
678
+ buildEnv?: TEnv,
679
+ devMode?: boolean,
630
680
  ) {
631
681
  return _renderStaticSegment<TEnv>(
632
682
  handler,
633
683
  handlerId,
634
684
  mergedRouteMap,
635
685
  routeName,
686
+ buildEnv,
687
+ devMode,
636
688
  );
637
689
  }
638
690
 
@@ -645,6 +697,7 @@ export function createRouter<TEnv = any>(
645
697
  findMatch,
646
698
  findInterceptForRoute,
647
699
  telemetry: telemetrySink,
700
+ cacheSignalEnabled,
648
701
  });
649
702
 
650
703
  const { match, matchPartial, matchError, previewMatch } = matchHandlers;
@@ -654,11 +707,18 @@ export function createRouter<TEnv = any>(
654
707
  * The type system tracks accumulated routes through the builder chain
655
708
  * Initial TRoutes is {} (empty) to avoid poisoning accumulated types with Record<string, string>
656
709
  */
657
- const router: RSCRouterInternal<TEnv, {}> = {
710
+ const router: RangoInternal<TEnv, {}> = {
658
711
  __brand: RSC_ROUTER_BRAND,
659
712
  id: routerId,
713
+ basename,
714
+
715
+ routes(patternsOrBuilder: UrlPatterns<TEnv> | UrlBuilder<TEnv>): any {
716
+ // Wrap builder functions in urls() automatically
717
+ const urlPatterns: UrlPatterns<TEnv> =
718
+ typeof patternsOrBuilder === "function"
719
+ ? (urls(patternsOrBuilder) as UrlPatterns<TEnv>)
720
+ : patternsOrBuilder;
660
721
 
661
- routes(urlPatterns: UrlPatterns<TEnv>): any {
662
722
  // Store reference for runtime manifest generation
663
723
  storedUrlPatterns = urlPatterns;
664
724
  const currentMountIndex = mountIndex++;
@@ -689,13 +749,13 @@ export function createRouter<TEnv = any>(
689
749
  errorBoundary: [],
690
750
  notFoundBoundary: [],
691
751
  layout: [],
692
- parallel: [],
752
+ parallel: {},
693
753
  intercept: [],
694
754
  loader: [],
695
755
  };
696
756
 
697
757
  let handlerResult: AllUseItems[] = [];
698
- RSCRouterContext.run(
758
+ RangoContext.run(
699
759
  {
700
760
  manifest,
701
761
  patterns: routePatterns,
@@ -706,6 +766,10 @@ export function createRouter<TEnv = any>(
706
766
  counters: {},
707
767
  mountIndex: currentMountIndex,
708
768
  cacheProfiles: resolvedCacheProfiles,
769
+ // basename sets the initial URL prefix so all path() patterns
770
+ // are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
771
+ // No namePrefix — route names stay unprefixed.
772
+ ...(basename ? { urlPrefix: basename } : {}),
709
773
  },
710
774
  () => {
711
775
  handlerResult = urlPatterns.handler() as AllUseItems[];
@@ -725,7 +789,7 @@ export function createRouter<TEnv = any>(
725
789
  if (entry.type === "route" && entry.isPrerender) {
726
790
  if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
727
791
  prerenderRouteKeys.add(name);
728
- if (entry.prerenderDef?.options?.passthrough === true) {
792
+ if (entry.isPassthrough === true) {
729
793
  if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
730
794
  passthroughRouteKeys.add(name);
731
795
  }
@@ -751,6 +815,7 @@ export function createRouter<TEnv = any>(
751
815
  trailingSlash: trailingSlashConfig,
752
816
  handler: urlPatterns.handler,
753
817
  mountIndex: currentMountIndex,
818
+ routerId,
754
819
  cacheProfiles: resolvedCacheProfiles,
755
820
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
756
821
  ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
@@ -770,6 +835,7 @@ export function createRouter<TEnv = any>(
770
835
  trailingSlash: trailingSlashConfig,
771
836
  handler: urlPatterns.handler,
772
837
  mountIndex: currentMountIndex,
838
+ routerId,
773
839
  cacheProfiles: resolvedCacheProfiles,
774
840
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
775
841
  ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
@@ -801,10 +867,13 @@ export function createRouter<TEnv = any>(
801
867
 
802
868
  // Create placeholder RouteEntry for each lazy include
803
869
  for (const lazyInclude of lazyIncludes) {
804
- // Compute the full URL prefix (combining parent prefix if any)
805
- const fullPrefix = lazyInclude.context.urlPrefix
806
- ? lazyInclude.context.urlPrefix + lazyInclude.prefix
807
- : lazyInclude.prefix;
870
+ // Compute the full URL prefix (combining parent prefix if any). Use the
871
+ // slash-collapsing join so a trailing-slash parent prefix does not
872
+ // produce a double-slash staticPrefix the trie's sp can never match.
873
+ const fullPrefix = joinPrefix(
874
+ lazyInclude.context.urlPrefix,
875
+ lazyInclude.prefix,
876
+ );
808
877
 
809
878
  const lazyEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
810
879
  prefix: "",
@@ -813,6 +882,7 @@ export function createRouter<TEnv = any>(
813
882
  trailingSlash: trailingSlashConfig,
814
883
  handler: urlPatterns.handler,
815
884
  mountIndex: mountIndex++,
885
+ routerId,
816
886
  // Lazy evaluation fields
817
887
  lazy: true,
818
888
  lazyPatterns: lazyInclude.patterns,
@@ -851,8 +921,18 @@ export function createRouter<TEnv = any>(
851
921
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
852
922
  middleware?: MiddlewareFn<TEnv>,
853
923
  ): any {
854
- // Global middleware - no mount prefix
855
- addMiddleware(patternOrMiddleware, middleware, null);
924
+ // Auto-prefix pattern with basename so router-level middleware
925
+ // patterns are router-relative (e.g. "/users/*" matches "/app/users/*").
926
+ if (basename && typeof patternOrMiddleware === "string") {
927
+ const pattern = patternOrMiddleware;
928
+ const prefixed =
929
+ pattern === "/*" || pattern === "*"
930
+ ? `${basename}/*`
931
+ : `${basename}${pattern}`;
932
+ addMiddleware(prefixed, middleware, null);
933
+ } else {
934
+ addMiddleware(patternOrMiddleware, middleware, null);
935
+ }
856
936
  return router;
857
937
  },
858
938
 
@@ -889,12 +969,22 @@ export function createRouter<TEnv = any>(
889
969
  prefetchCacheControl,
890
970
  prefetchCacheTTL,
891
971
 
972
+ // Expose the resolved rango state cookie name for the server-side writer
973
+ // (invalidateClientCache) and for shipping to the client in metadata.
974
+ resolvedStateCookieName,
975
+
892
976
  // Expose warmup enabled flag for handler and client
893
977
  warmupEnabled,
894
978
 
979
+ // Expose StrictMode flag for the initial-render payload metadata
980
+ strictMode,
981
+
895
982
  // Expose router-wide performance debugging for request-level metrics setup
896
983
  debugPerformance,
897
984
 
985
+ // Expose resolved span tracing for the handler (Cloudflare custom spans)
986
+ tracing: resolvedTracing,
987
+
898
988
  // Expose debug manifest flag for handler
899
989
  allowDebugManifest: allowDebugManifestOption,
900
990
 
@@ -953,6 +1043,16 @@ export function createRouter<TEnv = any>(
953
1043
  // Expose source file for per-router type generation
954
1044
  __sourceFile,
955
1045
 
1046
+ // Expose basename for runtime manifest generation
1047
+ __basename: basename,
1048
+
1049
+ // Expose router-level boundary defaults for build-time clientChunks
1050
+ // discovery (so a "use client" default boundary lands in app-fallback).
1051
+ // These are createRouter options, never pushed onto EntryData.
1052
+ __defaultErrorBoundary: defaultErrorBoundary,
1053
+ __defaultNotFoundBoundary: defaultNotFoundBoundary,
1054
+ __notFound: notFound,
1055
+
956
1056
  // RSC request handler (lazily created on first call)
957
1057
  fetch: (() => {
958
1058
  // Handler is created on first call and reused
@@ -970,8 +1070,10 @@ export function createRouter<TEnv = any>(
970
1070
  if (!handler) {
971
1071
  // Lazy import deferred to first request to avoid dev mode issues
972
1072
  const { createRSCHandler } = await import("./rsc/handler.js");
973
- // Cast: handler.ts still accepts (request, env) will be updated
974
- // separately to accept RouterRequestInput.
1073
+ // Cast: createRSCHandler receives `router as any`, which erases TEnv
1074
+ // and infers its handler as RouterRequestInput<unknown>. Re-narrow the
1075
+ // returned handler to RouterRequestInput<TEnv> so the call below stays
1076
+ // typed. (The handler already accepts (request, RouterRequestInput).)
975
1077
  handler = createRSCHandler({
976
1078
  router: router as any,
977
1079
  cache,
@@ -986,6 +1088,10 @@ export function createRouter<TEnv = any>(
986
1088
  };
987
1089
  })(),
988
1090
 
1091
+ // Low-level route matching for request classification
1092
+ findMatch: (pathname: string, metricsStore?: any) =>
1093
+ findMatch(pathname, metricsStore),
1094
+
989
1095
  // Debug utility for manifest inspection
990
1096
  debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
991
1097
  };
@@ -994,8 +1100,10 @@ export function createRouter<TEnv = any>(
994
1100
  RouterRegistry.set(routerId, router);
995
1101
 
996
1102
  // If urls option was provided, auto-register them
997
- if (urlsOption) {
998
- return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
1103
+ if (typeof urlsOption === "function") {
1104
+ return router.routes(urlsOption) as Rango<TEnv, {}>;
1105
+ } else if (urlsOption) {
1106
+ return router.routes(urlsOption) as Rango<TEnv, {}>;
999
1107
  }
1000
1108
 
1001
1109
  return router;
@@ -6,14 +6,14 @@
6
6
  * RSC rendering) so they can be standalone modules without closure coupling.
7
7
  */
8
8
 
9
- import type { RSCRouterInternal } from "../router/router-interfaces.js";
9
+ import type { RangoInternal } from "../router/router-interfaces.js";
10
10
  import type { ErrorPhase } from "../types.js";
11
11
  import type { InvokeOnErrorContext } from "../router/error-handling.js";
12
12
  import type { RSCDependencies, LoadSSRModule } from "./types.js";
13
13
  import type { SSRStreamMode } from "../router/router-options.js";
14
14
 
15
15
  export interface HandlerContext<TEnv = unknown> {
16
- router: RSCRouterInternal<TEnv, any>;
16
+ router: RangoInternal<TEnv, any>;
17
17
  version: string;
18
18
  renderToReadableStream: RSCDependencies["renderToReadableStream"];
19
19
  decodeReply: RSCDependencies["decodeReply"];
@@ -31,6 +31,7 @@ export interface HandlerContext<TEnv = unknown> {
31
31
  createRedirectFlightResponse: (
32
32
  redirectUrl: string,
33
33
  locationState?: Record<string, unknown>,
34
+ external?: boolean,
34
35
  ) => Response;
35
36
 
36
37
  /**