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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +198 -44
  3. package/dist/bin/rango.js +287 -105
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3248 -1117
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +73 -21
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +107 -1
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +245 -21
  12. package/skills/caching/SKILL.md +302 -6
  13. package/skills/composability/SKILL.md +27 -2
  14. package/skills/css/SKILL.md +76 -0
  15. package/skills/document-cache/SKILL.md +78 -55
  16. package/skills/handler-use/SKILL.md +364 -0
  17. package/skills/hooks/SKILL.md +270 -30
  18. package/skills/host-router/SKILL.md +82 -22
  19. package/skills/i18n/SKILL.md +276 -0
  20. package/skills/intercept/SKILL.md +49 -5
  21. package/skills/layout/SKILL.md +35 -9
  22. package/skills/links/SKILL.md +249 -17
  23. package/skills/loader/SKILL.md +294 -30
  24. package/skills/middleware/SKILL.md +52 -13
  25. package/skills/migrate-nextjs/SKILL.md +584 -0
  26. package/skills/migrate-react-router/SKILL.md +769 -0
  27. package/skills/mime-routes/SKILL.md +27 -0
  28. package/skills/observability/SKILL.md +137 -0
  29. package/skills/parallel/SKILL.md +203 -7
  30. package/skills/prerender/SKILL.md +123 -100
  31. package/skills/rango/SKILL.md +250 -22
  32. package/skills/react-compiler/SKILL.md +168 -0
  33. package/skills/response-routes/SKILL.md +122 -47
  34. package/skills/route/SKILL.md +97 -5
  35. package/skills/router-setup/SKILL.md +90 -5
  36. package/skills/server-actions/SKILL.md +775 -0
  37. package/skills/streams-and-websockets/SKILL.md +283 -0
  38. package/skills/tailwind/SKILL.md +27 -3
  39. package/skills/testing/SKILL.md +129 -0
  40. package/skills/testing/bindings.md +89 -0
  41. package/skills/testing/cache-prerender.md +124 -0
  42. package/skills/testing/client-components.md +122 -0
  43. package/skills/testing/e2e-parity.md +125 -0
  44. package/skills/testing/flight.md +92 -0
  45. package/skills/testing/handles.md +129 -0
  46. package/skills/testing/loader.md +128 -0
  47. package/skills/testing/middleware.md +99 -0
  48. package/skills/testing/render-handler.md +121 -0
  49. package/skills/testing/response-routes.md +95 -0
  50. package/skills/testing/reverse-and-types.md +84 -0
  51. package/skills/testing/server-actions.md +107 -0
  52. package/skills/testing/server-tree.md +128 -0
  53. package/skills/testing/setup.md +120 -0
  54. package/skills/typesafety/SKILL.md +329 -27
  55. package/skills/use-cache/SKILL.md +36 -5
  56. package/skills/view-transitions/SKILL.md +294 -0
  57. package/src/__augment-tests__/augment.ts +81 -0
  58. package/src/__augment-tests__/augmented.check.ts +116 -0
  59. package/src/__internal.ts +67 -40
  60. package/src/browser/action-coordinator.ts +53 -36
  61. package/src/browser/action-fence.ts +47 -0
  62. package/src/browser/app-shell.ts +39 -0
  63. package/src/browser/app-version.ts +14 -0
  64. package/src/browser/cookie-name.ts +140 -0
  65. package/src/browser/event-controller.ts +86 -147
  66. package/src/browser/history-state.ts +21 -0
  67. package/src/browser/index.ts +3 -3
  68. package/src/browser/invalidate-client-cache.ts +52 -0
  69. package/src/browser/link-interceptor.ts +4 -0
  70. package/src/browser/navigation-bridge.ts +148 -19
  71. package/src/browser/navigation-client.ts +187 -67
  72. package/src/browser/navigation-store-handle.ts +38 -0
  73. package/src/browser/navigation-store.ts +76 -67
  74. package/src/browser/navigation-transaction.ts +18 -66
  75. package/src/browser/partial-update.ts +123 -94
  76. package/src/browser/prefetch/cache.ts +214 -36
  77. package/src/browser/prefetch/fetch.ts +260 -38
  78. package/src/browser/prefetch/policy.ts +6 -0
  79. package/src/browser/prefetch/queue.ts +126 -20
  80. package/src/browser/prefetch/resource-ready.ts +77 -0
  81. package/src/browser/rango-state.ts +158 -76
  82. package/src/browser/react/Link.tsx +93 -11
  83. package/src/browser/react/NavigationProvider.tsx +115 -34
  84. package/src/browser/react/ScrollRestoration.tsx +10 -6
  85. package/src/browser/react/context.ts +7 -2
  86. package/src/browser/react/filter-segment-order.ts +49 -7
  87. package/src/browser/react/index.ts +0 -48
  88. package/src/browser/react/location-state-shared.ts +166 -8
  89. package/src/browser/react/location-state.ts +39 -14
  90. package/src/browser/react/use-action.ts +6 -15
  91. package/src/browser/react/use-handle.ts +23 -69
  92. package/src/browser/react/use-link-status.ts +0 -4
  93. package/src/browser/react/use-navigation.ts +22 -5
  94. package/src/browser/react/use-params.ts +20 -10
  95. package/src/browser/react/use-reverse.ts +106 -0
  96. package/src/browser/react/use-router.ts +46 -11
  97. package/src/browser/react/use-search-params.ts +0 -5
  98. package/src/browser/react/use-segments.ts +11 -21
  99. package/src/browser/response-adapter.ts +52 -1
  100. package/src/browser/rsc-router.tsx +215 -76
  101. package/src/browser/scroll-restoration.ts +46 -39
  102. package/src/browser/segment-reconciler.ts +36 -9
  103. package/src/browser/segment-structure-assert.ts +2 -2
  104. package/src/browser/server-action-bridge.ts +176 -50
  105. package/src/browser/types.ts +95 -11
  106. package/src/browser/validate-redirect-origin.ts +43 -16
  107. package/src/build/collect-fallback-refs.ts +107 -0
  108. package/src/build/generate-manifest.ts +65 -40
  109. package/src/build/generate-route-types.ts +5 -0
  110. package/src/build/index.ts +8 -2
  111. package/src/build/prefix-tree-utils.ts +123 -0
  112. package/src/build/route-trie.ts +137 -32
  113. package/src/build/route-types/codegen.ts +4 -4
  114. package/src/build/route-types/include-resolution.ts +9 -2
  115. package/src/build/route-types/param-extraction.ts +6 -3
  116. package/src/build/route-types/per-module-writer.ts +7 -4
  117. package/src/build/route-types/router-processing.ts +278 -96
  118. package/src/build/route-types/scan-filter.ts +9 -2
  119. package/src/build/route-types/source-scan.ts +118 -0
  120. package/src/build/runtime-discovery.ts +9 -20
  121. package/src/cache/cache-error.ts +104 -0
  122. package/src/cache/cache-policy.ts +68 -28
  123. package/src/cache/cache-runtime.ts +149 -43
  124. package/src/cache/cache-scope.ts +148 -81
  125. package/src/cache/cache-tag.ts +98 -0
  126. package/src/cache/cf/cf-cache-store.ts +2550 -93
  127. package/src/cache/cf/index.ts +11 -17
  128. package/src/cache/document-cache.ts +78 -27
  129. package/src/cache/handle-snapshot.ts +63 -0
  130. package/src/cache/index.ts +23 -20
  131. package/src/cache/memory-segment-store.ts +136 -37
  132. package/src/cache/profile-registry.ts +6 -30
  133. package/src/cache/read-through-swr.ts +41 -11
  134. package/src/cache/segment-codec.ts +0 -16
  135. package/src/cache/tag-invalidation.ts +230 -0
  136. package/src/cache/taint.ts +55 -0
  137. package/src/cache/types.ts +33 -100
  138. package/src/cache/vercel/index.ts +11 -0
  139. package/src/cache/vercel/vercel-cache-store.ts +799 -0
  140. package/src/client.rsc.tsx +6 -21
  141. package/src/client.tsx +108 -290
  142. package/src/component-utils.ts +19 -0
  143. package/src/context-var.ts +84 -2
  144. package/src/debug.ts +2 -2
  145. package/src/decode-loader-results.ts +36 -0
  146. package/src/defer.ts +196 -0
  147. package/src/deps/ssr.ts +0 -1
  148. package/src/errors.ts +30 -4
  149. package/src/handle.ts +70 -22
  150. package/src/handles/MetaTags.tsx +0 -14
  151. package/src/handles/breadcrumbs.ts +16 -5
  152. package/src/handles/meta.ts +0 -39
  153. package/src/host/cookie-handler.ts +0 -36
  154. package/src/host/errors.ts +0 -24
  155. package/src/host/index.ts +8 -2
  156. package/src/host/pattern-matcher.ts +7 -50
  157. package/src/host/router.ts +107 -99
  158. package/src/host/testing.ts +40 -27
  159. package/src/host/types.ts +37 -4
  160. package/src/host/utils.ts +1 -1
  161. package/src/href-client.ts +137 -22
  162. package/src/index.rsc.ts +52 -26
  163. package/src/index.ts +100 -38
  164. package/src/internal-debug.ts +2 -4
  165. package/src/loader-store.ts +500 -0
  166. package/src/loader.rsc.ts +20 -13
  167. package/src/loader.ts +12 -11
  168. package/src/missing-id-error.ts +68 -0
  169. package/src/network-error-thrower.tsx +1 -6
  170. package/src/outlet-context.ts +1 -1
  171. package/src/outlet-provider.tsx +1 -5
  172. package/src/prerender/param-hash.ts +10 -11
  173. package/src/prerender/store.ts +37 -41
  174. package/src/prerender.ts +198 -82
  175. package/src/redirect-origin.ts +100 -0
  176. package/src/response-utils.ts +37 -0
  177. package/src/reverse.ts +65 -15
  178. package/src/root-error-boundary.tsx +1 -19
  179. package/src/route-content-wrapper.tsx +7 -72
  180. package/src/route-definition/dsl-helpers.ts +437 -274
  181. package/src/route-definition/helper-factories.ts +29 -139
  182. package/src/route-definition/helpers-types.ts +113 -37
  183. package/src/route-definition/index.ts +3 -0
  184. package/src/route-definition/redirect.ts +52 -10
  185. package/src/route-definition/resolve-handler-use.ts +161 -0
  186. package/src/route-definition/use-item-types.ts +32 -0
  187. package/src/route-map-builder.ts +7 -17
  188. package/src/route-types.ts +37 -41
  189. package/src/router/basename.ts +14 -0
  190. package/src/router/content-negotiation.ts +108 -9
  191. package/src/router/error-handling.ts +13 -17
  192. package/src/router/find-match.ts +45 -22
  193. package/src/router/handler-context.ts +83 -41
  194. package/src/router/intercept-resolution.ts +25 -23
  195. package/src/router/lazy-includes.ts +19 -53
  196. package/src/router/loader-resolution.ts +213 -30
  197. package/src/router/logging.ts +5 -8
  198. package/src/router/manifest.ts +49 -45
  199. package/src/router/match-api.ts +120 -204
  200. package/src/router/match-context.ts +0 -22
  201. package/src/router/match-handlers.ts +58 -58
  202. package/src/router/match-middleware/background-revalidation.ts +27 -6
  203. package/src/router/match-middleware/cache-lookup.ts +205 -249
  204. package/src/router/match-middleware/cache-store.ts +45 -32
  205. package/src/router/match-middleware/intercept-resolution.ts +8 -28
  206. package/src/router/match-middleware/segment-resolution.ts +52 -18
  207. package/src/router/match-pipelines.ts +1 -42
  208. package/src/router/match-result.ts +104 -40
  209. package/src/router/metrics.ts +5 -34
  210. package/src/router/middleware-types.ts +13 -142
  211. package/src/router/middleware.ts +173 -143
  212. package/src/router/navigation-snapshot.ts +131 -0
  213. package/src/router/params-util.ts +23 -0
  214. package/src/router/pattern-matching.ts +109 -63
  215. package/src/router/prerender-match.ts +190 -54
  216. package/src/router/preview-match.ts +32 -102
  217. package/src/router/request-classification.ts +276 -0
  218. package/src/router/revalidation.ts +63 -55
  219. package/src/router/route-snapshot.ts +244 -0
  220. package/src/router/router-context.ts +6 -28
  221. package/src/router/router-interfaces.ts +100 -35
  222. package/src/router/router-options.ts +91 -11
  223. package/src/router/router-registry.ts +2 -5
  224. package/src/router/segment-resolution/fresh.ts +242 -75
  225. package/src/router/segment-resolution/helpers.ts +63 -24
  226. package/src/router/segment-resolution/loader-cache.ts +41 -37
  227. package/src/router/segment-resolution/revalidation.ts +456 -372
  228. package/src/router/segment-resolution/static-store.ts +19 -5
  229. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  230. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  231. package/src/router/segment-resolution.ts +4 -1
  232. package/src/router/segment-wrappers.ts +2 -3
  233. package/src/router/state-cookie-name.ts +33 -0
  234. package/src/router/substitute-pattern-params.ts +56 -0
  235. package/src/router/telemetry-otel.ts +0 -20
  236. package/src/router/telemetry.ts +96 -19
  237. package/src/router/timeout.ts +0 -20
  238. package/src/router/trie-matching.ts +91 -46
  239. package/src/router/types.ts +10 -63
  240. package/src/router/url-params.ts +44 -0
  241. package/src/router.ts +134 -43
  242. package/src/rsc/handler-context.ts +3 -2
  243. package/src/rsc/handler.ts +492 -383
  244. package/src/rsc/helpers.ts +162 -46
  245. package/src/rsc/index.ts +1 -1
  246. package/src/rsc/json-route-result.ts +38 -0
  247. package/src/rsc/loader-fetch.ts +23 -3
  248. package/src/rsc/manifest-init.ts +33 -42
  249. package/src/rsc/origin-guard.ts +39 -25
  250. package/src/rsc/progressive-enhancement.ts +30 -3
  251. package/src/rsc/redirect-guard.ts +99 -0
  252. package/src/rsc/response-error.ts +79 -12
  253. package/src/rsc/response-route-handler.ts +90 -63
  254. package/src/rsc/rsc-rendering.ts +56 -54
  255. package/src/rsc/runtime-warnings.ts +23 -10
  256. package/src/rsc/server-action.ts +74 -67
  257. package/src/rsc/ssr-setup.ts +18 -2
  258. package/src/rsc/types.ts +25 -6
  259. package/src/runtime-env.ts +18 -0
  260. package/src/search-params.ts +4 -20
  261. package/src/segment-content-promise.ts +67 -0
  262. package/src/segment-loader-promise.ts +134 -0
  263. package/src/segment-system.tsx +272 -129
  264. package/src/serialize.ts +243 -0
  265. package/src/server/context.ts +309 -61
  266. package/src/server/cookie-store.ts +80 -5
  267. package/src/server/handle-store.ts +26 -24
  268. package/src/server/loader-registry.ts +10 -28
  269. package/src/server/request-context.ts +338 -126
  270. package/src/ssr/index.tsx +23 -15
  271. package/src/static-handler.ts +27 -18
  272. package/src/testing/cache-status.ts +162 -0
  273. package/src/testing/collect-handle.ts +40 -0
  274. package/src/testing/dispatch.ts +618 -0
  275. package/src/testing/dom.entry.ts +22 -0
  276. package/src/testing/e2e/fixture.ts +188 -0
  277. package/src/testing/e2e/index.ts +128 -0
  278. package/src/testing/e2e/matchers.ts +35 -0
  279. package/src/testing/e2e/page-helpers.ts +272 -0
  280. package/src/testing/e2e/parity.ts +387 -0
  281. package/src/testing/e2e/server.ts +195 -0
  282. package/src/testing/flight-matchers.ts +97 -0
  283. package/src/testing/flight-normalize.ts +11 -0
  284. package/src/testing/flight-runtime.d.ts +57 -0
  285. package/src/testing/flight-tree.ts +682 -0
  286. package/src/testing/flight.entry.ts +52 -0
  287. package/src/testing/flight.ts +232 -0
  288. package/src/testing/generated-routes.ts +183 -0
  289. package/src/testing/index.ts +99 -0
  290. package/src/testing/internal/context.ts +348 -0
  291. package/src/testing/internal/flight-client-globals.ts +30 -0
  292. package/src/testing/internal/seed-vars.ts +54 -0
  293. package/src/testing/render-handler.ts +330 -0
  294. package/src/testing/render-route.tsx +566 -0
  295. package/src/testing/run-loader.ts +378 -0
  296. package/src/testing/run-middleware.ts +205 -0
  297. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  298. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  299. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  300. package/src/testing/vitest-stubs/version.ts +5 -0
  301. package/src/testing/vitest.ts +305 -0
  302. package/src/theme/ThemeProvider.tsx +0 -52
  303. package/src/theme/ThemeScript.tsx +0 -6
  304. package/src/theme/constants.ts +0 -12
  305. package/src/theme/index.ts +0 -7
  306. package/src/theme/theme-context.ts +1 -5
  307. package/src/theme/theme-script.ts +0 -14
  308. package/src/theme/use-theme.ts +0 -3
  309. package/src/types/boundaries.ts +0 -35
  310. package/src/types/cache-types.ts +17 -8
  311. package/src/types/error-types.ts +30 -90
  312. package/src/types/global-namespace.ts +54 -41
  313. package/src/types/handler-context.ts +233 -81
  314. package/src/types/index.ts +1 -10
  315. package/src/types/loader-types.ts +44 -15
  316. package/src/types/request-scope.ts +107 -0
  317. package/src/types/route-config.ts +6 -50
  318. package/src/types/route-entry.ts +19 -7
  319. package/src/types/segments.ts +37 -14
  320. package/src/urls/include-helper.ts +33 -70
  321. package/src/urls/index.ts +1 -11
  322. package/src/urls/path-helper-types.ts +58 -11
  323. package/src/urls/path-helper.ts +57 -111
  324. package/src/urls/pattern-types.ts +48 -19
  325. package/src/urls/response-types.ts +25 -22
  326. package/src/urls/type-extraction.ts +58 -139
  327. package/src/urls/urls-function.ts +1 -18
  328. package/src/use-loader.tsx +346 -89
  329. package/src/vite/debug.ts +185 -0
  330. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  331. package/src/vite/discovery/discover-routers.ts +130 -85
  332. package/src/vite/discovery/discovery-errors.ts +194 -0
  333. package/src/vite/discovery/gate-state.ts +171 -0
  334. package/src/vite/discovery/prerender-collection.ts +192 -99
  335. package/src/vite/discovery/route-types-writer.ts +40 -84
  336. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  337. package/src/vite/discovery/state.ts +51 -6
  338. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  339. package/src/vite/index.ts +8 -0
  340. package/src/vite/plugin-types.ts +187 -69
  341. package/src/vite/plugins/cjs-to-esm.ts +8 -18
  342. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  343. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  344. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  345. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  346. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  347. package/src/vite/plugins/expose-action-id.ts +49 -98
  348. package/src/vite/plugins/expose-id-utils.ts +11 -50
  349. package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
  350. package/src/vite/plugins/expose-ids/handler-transform.ts +10 -48
  351. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
  352. package/src/vite/plugins/expose-ids/router-transform.ts +20 -16
  353. package/src/vite/plugins/expose-internal-ids.ts +554 -317
  354. package/src/vite/plugins/performance-tracks.ts +89 -0
  355. package/src/vite/plugins/refresh-cmd.ts +89 -27
  356. package/src/vite/plugins/use-cache-transform.ts +73 -83
  357. package/src/vite/plugins/vercel-output.ts +258 -0
  358. package/src/vite/plugins/version-injector.ts +21 -25
  359. package/src/vite/plugins/version-plugin.ts +41 -20
  360. package/src/vite/plugins/virtual-entries.ts +2 -17
  361. package/src/vite/rango.ts +257 -289
  362. package/src/vite/router-discovery.ts +930 -140
  363. package/src/vite/utils/ast-handler-extract.ts +15 -31
  364. package/src/vite/utils/banner.ts +4 -4
  365. package/src/vite/utils/bundle-analysis.ts +10 -15
  366. package/src/vite/utils/client-chunks.ts +184 -0
  367. package/src/vite/utils/forward-user-plugins.ts +171 -0
  368. package/src/vite/utils/manifest-utils.ts +4 -59
  369. package/src/vite/utils/package-resolution.ts +20 -52
  370. package/src/vite/utils/prerender-utils.ts +27 -29
  371. package/src/vite/utils/shared-utils.ts +92 -42
  372. package/src/browser/action-response-classifier.ts +0 -99
  373. package/src/browser/react/use-client-cache.ts +0 -58
  374. package/src/browser/shallow.ts +0 -40
  375. package/src/handles/index.ts +0 -7
  376. package/src/router/middleware-cookies.ts +0 -55
@@ -37,7 +37,10 @@ import type {
37
37
  UseItems,
38
38
  } from "../route-types.js";
39
39
  import type { SearchSchema } from "../search-params.js";
40
- import type { PrerenderHandlerDefinition } from "../prerender.js";
40
+ import type {
41
+ PrerenderHandlerDefinition,
42
+ PassthroughHandlerDefinition,
43
+ } from "../prerender.js";
41
44
  import type { StaticHandlerDefinition } from "../static-handler.js";
42
45
  import type { InterceptWhenFn } from "../server/context";
43
46
  import type {
@@ -70,6 +73,7 @@ export type PathFn<TEnv> = <
70
73
  ctx: HandlerContext<TParams, TEnv, TSearch>,
71
74
  ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>)
72
75
  | PrerenderHandlerDefinition<TParams>
76
+ | PassthroughHandlerDefinition<TParams, TEnv>
73
77
  | StaticHandlerDefinition<TParams>,
74
78
  optionsOrUse?: PathOptions<TName, TSearch> | (() => UseItems<RouteUseItem>),
75
79
  use?: () => UseItems<RouteUseItem>,
@@ -110,6 +114,12 @@ export type ResponsePathFn<TEnv> = <
110
114
  * Path function for JSON response routes (path.json()).
111
115
  * Handler can return plain JSON-serializable values or Response.
112
116
  * TData is inferred from the handler's return type (excluding Response/Promise wrappers).
117
+ *
118
+ * Note: a nested Promise in the return (a forgotten await) is caught at runtime
119
+ * by response-route-handler.ts (it throws instead of silently emitting `{}`). A
120
+ * compile-time JsonValue constraint was evaluated and rejected — it breaks
121
+ * interface-typed returns (interfaces lack the index signature JsonValue
122
+ * requires) and preserves literal types in the inferred response shape.
113
123
  */
114
124
  export type JsonResponsePathFn<TEnv> = <
115
125
  const TPattern extends string,
@@ -229,12 +239,27 @@ export type PathHelpers<TEnv> = {
229
239
  include: IncludeFn<TEnv>;
230
240
 
231
241
  /**
232
- * Define parallel routes that render simultaneously in named slots
242
+ * Define parallel routes that render simultaneously in named slots.
243
+ *
244
+ * A slot value can be a Handler / ReactNode / StaticHandlerDefinition
245
+ * (legacy form, broadcast use applies to every slot) or a slot descriptor
246
+ * `{ handler, use? }` whose `use` is scoped to that slot only. Per-slot
247
+ * merge order is `handler.use` → shared `use` → slot-local `use`, with
248
+ * narrowest scope winning for last-write-wins items like `loading()`.
233
249
  */
234
250
  parallel: <
235
251
  TSlots extends Record<
236
252
  `@${string}`,
237
- Handler<any, any, TEnv> | ReactNode | StaticHandlerDefinition
253
+ | Handler<any, any, TEnv>
254
+ | ReactNode
255
+ | StaticHandlerDefinition
256
+ | {
257
+ handler:
258
+ | Handler<any, any, TEnv>
259
+ | ReactNode
260
+ | StaticHandlerDefinition;
261
+ use?: () => ParallelUseItem[];
262
+ }
238
263
  >,
239
264
  >(
240
265
  slots: TSlots,
@@ -245,7 +270,7 @@ export type PathHelpers<TEnv> = {
245
270
  * Define an intercepting route for soft navigation
246
271
  * Note: routeName must match a named path() in this urlpatterns
247
272
  */
248
- intercept: keyof RSCRouter.GeneratedRouteMap extends never
273
+ intercept: keyof Rango.GeneratedRouteMap extends never
249
274
  ? (
250
275
  slotName: `@${string}`,
251
276
  routeName: string,
@@ -254,15 +279,26 @@ export type PathHelpers<TEnv> = {
254
279
  ) => InterceptItem
255
280
  : (
256
281
  slotName: `@${string}`,
257
- routeName: (keyof RSCRouter.GeneratedRouteMap & string) | `.${string}`,
282
+ routeName: (keyof Rango.GeneratedRouteMap & string) | `.${string}`,
258
283
  handler: ReactNode | Handler<any, any, TEnv>,
259
284
  use?: () => InterceptUseItem[],
260
285
  ) => InterceptItem;
261
286
 
262
287
  /**
263
- * Attach middleware to the current route/layout
288
+ * Attach middleware to the current route/layout, or wrap child segments
264
289
  */
265
- middleware: (...fns: MiddlewareFn<TEnv>[]) => MiddlewareItem;
290
+ middleware: {
291
+ (fn: MiddlewareFn<TEnv>): MiddlewareItem;
292
+ (
293
+ fn: MiddlewareFn<TEnv>,
294
+ children: () => UseItems<LayoutUseItem>,
295
+ ): MiddlewareItem;
296
+ (fns: MiddlewareFn<TEnv>[]): MiddlewareItem;
297
+ (
298
+ fns: MiddlewareFn<TEnv>[],
299
+ children: () => UseItems<LayoutUseItem>,
300
+ ): MiddlewareItem;
301
+ };
266
302
 
267
303
  /**
268
304
  * Control when a segment should revalidate during navigation
@@ -280,7 +316,10 @@ export type PathHelpers<TEnv> = {
280
316
  /**
281
317
  * Attach a loading component to the current route/layout
282
318
  */
283
- loading: (component: ReactNode, options?: { ssr?: boolean }) => LoadingItem;
319
+ loading: (
320
+ component: ReactNode | (() => ReactNode),
321
+ options?: { ssr?: boolean },
322
+ ) => LoadingItem;
284
323
 
285
324
  /**
286
325
  * Attach an error boundary to catch errors in this segment
@@ -309,15 +348,23 @@ export type PathHelpers<TEnv> = {
309
348
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
310
349
  children: () => TChildren,
311
350
  ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
312
- (options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
351
+ (options: PartialCacheOptions<TEnv> | false): TypedCacheItem<{}, {}>;
313
352
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
314
- options: PartialCacheOptions | false,
353
+ options: PartialCacheOptions<TEnv> | false,
315
354
  use: () => TChildren,
316
355
  ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
317
356
  };
318
357
 
319
358
  /**
320
- * Attach a ViewTransition boundary to the current segment or a group of routes
359
+ * Opt a route (or group of routes) into transition-driven navigation.
360
+ *
361
+ * Two independent layers: (1) startTransition, on all React versions, holds
362
+ * the previous content across a same-route nav (no skeleton flash) and is the
363
+ * precondition for any view transition; (2) on experimental React, an
364
+ * additional `<ViewTransition>` boundary cross-fades/morphs the swap. Pass
365
+ * `{ viewTransition: false }` to keep #1 without the router boundary. A view
366
+ * transition cannot fire without a startTransition. See
367
+ * skills/view-transitions for the startTransition x ViewTransition matrix.
321
368
  */
322
369
  transition: {
323
370
  (): TransitionItem;
@@ -1,21 +1,17 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { Handler } from "../types.js";
3
- import type {
4
- AllUseItems,
5
- RouteItem,
6
- RouteUseItem,
7
- UseItems,
8
- } from "../route-types.js";
3
+ import type { RouteItem, RouteUseItem, UseItems } from "../route-types.js";
9
4
  import {
10
- getContext,
11
5
  getUrlPrefix,
12
6
  getNamePrefix,
13
7
  getRootScoped,
8
+ requireDslContext,
14
9
  } from "../server/context";
15
- import { invariant } from "../errors";
10
+ import { invariant, DataNotFoundError } from "../errors";
16
11
  import { validateUserRouteName } from "../route-name.js";
17
12
  import {
18
13
  isPrerenderHandler,
14
+ isPassthroughHandler,
19
15
  type PrerenderHandlerDefinition,
20
16
  } from "../prerender.js";
21
17
  import {
@@ -34,40 +30,15 @@ import type {
34
30
  JsonResponsePathFn,
35
31
  TextResponsePathFn,
36
32
  } from "./path-helper-types.js";
33
+ import {
34
+ resolveHandlerUse,
35
+ mergeHandlerUse,
36
+ } from "../route-definition/resolve-handler-use.js";
37
+ import {
38
+ emptySegmentBase,
39
+ runAndValidateUseItems,
40
+ } from "../route-definition/dsl-helpers.js";
37
41
 
38
- /**
39
- * Check if a value is a valid use item
40
- */
41
- const isValidUseItem = (item: any): item is AllUseItems | undefined | null => {
42
- return (
43
- typeof item === "undefined" ||
44
- item === null ||
45
- (item &&
46
- typeof item === "object" &&
47
- "type" in item &&
48
- [
49
- "layout",
50
- "route",
51
- "middleware",
52
- "revalidate",
53
- "parallel",
54
- "intercept",
55
- "loader",
56
- "loading",
57
- "errorBoundary",
58
- "notFoundBoundary",
59
- "when",
60
- "cache",
61
- "transition",
62
- "include",
63
- ].includes(item.type))
64
- );
65
- };
66
-
67
- /**
68
- * Apply URL prefix to a pattern
69
- * Handles edge cases like "/" patterns and double slashes
70
- */
71
42
  function applyUrlPrefix(prefix: string, pattern: string): string {
72
43
  if (!prefix) return pattern;
73
44
  if (pattern === "/") return prefix;
@@ -77,29 +48,17 @@ function applyUrlPrefix(prefix: string, pattern: string): string {
77
48
  return prefix + pattern;
78
49
  }
79
50
 
80
- /**
81
- * Apply name prefix to a route name
82
- */
83
51
  function applyNamePrefix(prefix: string | undefined, name: string): string {
84
52
  if (!prefix) return name;
85
53
  return `${prefix}.${name}`;
86
54
  }
87
55
 
88
- /**
89
- * Resolve response type from path options (set by path.json(), path.text(), etc.)
90
- */
91
56
  function resolveResponseType(
92
57
  options: PathOptions | undefined,
93
58
  ): string | undefined {
94
59
  return options?.[RESPONSE_TYPE];
95
60
  }
96
61
 
97
- /**
98
- * Create path() helper
99
- *
100
- * The path() function is the key new feature - it combines URL pattern
101
- * with handler at the definition site.
102
- */
103
62
  export function createPathHelper<TEnv>(): PathFn<TEnv> {
104
63
  return ((
105
64
  pattern: string,
@@ -107,17 +66,15 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
107
66
  optionsOrUse?: PathOptions | (() => UseItems<RouteUseItem>),
108
67
  maybeUse?: () => UseItems<RouteUseItem>,
109
68
  ): RouteItem => {
110
- const store = getContext();
111
- const ctx = store.getStore();
112
- if (!ctx) throw new Error("path() must be called inside urls()");
69
+ const { store, ctx } = requireDslContext(
70
+ "path() must be called inside urls()",
71
+ );
113
72
 
114
73
  invariant(
115
74
  !ctx.parent || ctx.parent.type !== "parallel",
116
75
  "path() cannot be used inside parallel()",
117
76
  );
118
77
 
119
- // Walk the parent chain to prevent path() nested under another path(),
120
- // even when separated by intermediate layouts (e.g. path(layout(path())))
121
78
  {
122
79
  let ancestor = ctx.parent;
123
80
  while (ancestor) {
@@ -129,7 +86,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
129
86
  }
130
87
  }
131
88
 
132
- // Determine options and use based on argument types
133
89
  let options: PathOptions | undefined;
134
90
  let use: (() => UseItems<RouteUseItem>) | undefined;
135
91
 
@@ -142,73 +98,74 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
142
98
  use = maybeUse;
143
99
  }
144
100
 
145
- // Get prefixes from context (set by include())
101
+ const handlerUseFn = resolveHandlerUse(handler);
102
+ const mountSite = resolveResponseType(options) ? "response" : "path";
103
+ const mergedUse = mergeHandlerUse(handlerUseFn, use, mountSite);
104
+
146
105
  const urlPrefix = getUrlPrefix();
147
106
  const namePrefix = getNamePrefix();
148
107
 
149
- // Apply URL prefix to pattern
150
108
  const prefixedPattern = applyUrlPrefix(urlPrefix, pattern);
151
109
 
152
- // Generate route name - use provided name or generate from pattern
153
110
  const localName =
154
111
  options?.name || `$path_${pattern.replace(/[/:*?]/g, "_")}`;
155
112
  if (options?.name) {
156
113
  validateUserRouteName(options.name);
157
114
  }
158
- // Apply name prefix if set (from include())
159
115
  const routeName = applyNamePrefix(namePrefix, localName);
160
116
 
161
117
  const namespace = `${ctx.namespace}.${store.getNextIndex("route")}.${routeName}`;
162
118
 
163
- // Per-request pruning: skip registration for routes that won't be rendered.
164
- // forRoute is set by loadManifest() to the matched route name. During
165
- // evaluateLazyEntry() (route matching), forRoute is unset so all routes
166
- // register normally. We still increment counters to keep shortCodes stable
167
- // across different routes (needed for segment reconciliation on navigation).
168
- //
169
- // include() does not need its own forRoute pruning. include() creates lazy
170
- // entries that defer handler execution until route matching. When the lazy
171
- // handler eventually runs inside loadManifest(), this path() check already
172
- // covers all routes defined inside the include.
173
119
  if (ctx.forRoute && routeName !== ctx.forRoute) {
174
120
  store.getShortCode("route");
175
121
  return { type: "route" } as RouteItem;
176
122
  }
177
123
 
178
- // Ensure handler is always a function (wrap ReactNode or extract from prerender/static def)
179
124
  const wrappedHandler: Handler<any, any, TEnv> =
180
125
  typeof handler === "function"
181
126
  ? (handler as Handler<any, any, TEnv>)
182
- : isPrerenderHandler(handler)
183
- ? (handler.handler as Handler<any, any, TEnv>)
184
- : isStaticHandler(handler)
185
- ? (handler.handler as Handler<any, any, TEnv>)
186
- : () => handler;
127
+ : isPassthroughHandler(handler)
128
+ ? typeof handler.prerenderDef.handler === "function"
129
+ ? (handler.prerenderDef.handler as Handler<any, any, TEnv>)
130
+ : () => {
131
+ throw new DataNotFoundError(
132
+ "No prerender data found for this route",
133
+ );
134
+ }
135
+ : isPrerenderHandler(handler)
136
+ ? typeof handler.handler === "function"
137
+ ? (handler.handler as Handler<any, any, TEnv>)
138
+ : () => {
139
+ throw new DataNotFoundError(
140
+ "No prerender data found for this route",
141
+ );
142
+ }
143
+ : isStaticHandler(handler)
144
+ ? (handler.handler as Handler<any, any, TEnv>)
145
+ : () => handler;
187
146
 
188
147
  const entry = {
148
+ ...emptySegmentBase(),
189
149
  id: namespace,
190
150
  shortCode: store.getShortCode("route"),
191
151
  type: "route" as const,
192
152
  parent: ctx.parent,
193
153
  handler: wrappedHandler,
194
- // Store the PREFIXED pattern for route matching
195
154
  pattern: prefixedPattern,
196
- loading: undefined,
197
- middleware: [],
198
- revalidate: [],
199
- errorBoundary: [],
200
- notFoundBoundary: [],
201
- layout: [],
202
- parallel: [],
203
- intercept: [],
204
- loader: [],
205
155
  ...(urlPrefix ? { mountPath: urlPrefix } : {}),
206
- ...(isPrerenderHandler(handler)
156
+ ...(isPassthroughHandler(handler)
207
157
  ? {
208
158
  isPrerender: true as const,
209
- prerenderDef: handler as PrerenderHandlerDefinition,
159
+ prerenderDef: handler.prerenderDef as PrerenderHandlerDefinition,
160
+ isPassthrough: true as const,
161
+ liveHandler: handler.liveHandler as Handler<any, any, TEnv>,
210
162
  }
211
- : {}),
163
+ : isPrerenderHandler(handler)
164
+ ? {
165
+ isPrerender: true as const,
166
+ prerenderDef: handler as PrerenderHandlerDefinition,
167
+ }
168
+ : {}),
212
169
  ...(isStaticHandler(handler)
213
170
  ? {
214
171
  isStaticPrerender: true as const,
@@ -220,29 +177,23 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
220
177
  : {}),
221
178
  };
222
179
 
223
- // Capture namespace prefix on static handler for build-time reverse() resolution
224
180
  if (isStaticHandler(handler) && handler.$$id && ctx.namePrefix) {
225
181
  (handler as any).$$routePrefix = ctx.namePrefix;
226
182
  }
227
183
 
228
- // Check for duplicate route names (TypeScript should catch this, but runtime check too)
229
184
  invariant(
230
185
  ctx.manifest.get(routeName) === undefined,
231
186
  `Duplicate route name: ${routeName} at ${namespace}`,
232
187
  );
233
188
 
234
- // Register route entry with prefixed name
235
189
  ctx.manifest.set(routeName, entry);
236
190
 
237
- // Register root-scope flag for dot-local reverse resolution
238
191
  registerRouteRootScope(routeName, getRootScoped());
239
192
 
240
- // Also store pattern in a separate map for URL generation
241
193
  if (ctx.patterns) {
242
194
  ctx.patterns.set(routeName, prefixedPattern);
243
195
  }
244
196
 
245
- // Store pattern grouped by URL prefix for separate entry creation
246
197
  if (ctx.patternsByPrefix) {
247
198
  const urlPrefix = getUrlPrefix() || "";
248
199
  if (!ctx.patternsByPrefix.has(urlPrefix)) {
@@ -251,12 +202,10 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
251
202
  ctx.patternsByPrefix.get(urlPrefix)!.set(routeName, prefixedPattern);
252
203
  }
253
204
 
254
- // Store trailing slash config if specified
255
205
  if (options?.trailingSlash && ctx.trailingSlash) {
256
206
  ctx.trailingSlash.set(routeName, options.trailingSlash);
257
207
  }
258
208
 
259
- // Store search schema if specified
260
209
  if (options?.search) {
261
210
  if (ctx.searchSchemas) {
262
211
  ctx.searchSchemas.set(routeName, options.search);
@@ -264,12 +213,14 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
264
213
  registerSearchSchema(routeName, options.search);
265
214
  }
266
215
 
267
- // Run use callback if provided
268
- if (use && typeof use === "function") {
269
- const result = store.run(namespace, entry, use)?.flat(3);
270
- invariant(
271
- Array.isArray(result) && result.every((item) => isValidUseItem(item)),
272
- `path() use() callback must return an array of use items [${namespace}]`,
216
+ if (mergedUse) {
217
+ const result = runAndValidateUseItems(
218
+ store,
219
+ namespace,
220
+ entry,
221
+ mergedUse,
222
+ "path",
223
+ "use",
273
224
  );
274
225
  return { name: namespace, type: "route", uses: result } as RouteItem;
275
226
  }
@@ -278,10 +229,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
278
229
  }) as PathFn<TEnv>;
279
230
  }
280
231
 
281
- /**
282
- * Attach response type tag methods (.json, .text, .html, .xml, .md, .image, .stream, .any) to a path helper.
283
- * Each tag wraps the original path() call with the RESPONSE_TYPE option set.
284
- */
285
232
  export function attachPathResponseTags<TEnv>(
286
233
  pathFn: PathFn<TEnv>,
287
234
  ): PathFn<TEnv> & {
@@ -303,7 +250,6 @@ export function attachPathResponseTags<TEnv>(
303
250
  ) => {
304
251
  let options: PathOptions;
305
252
  let use: (() => any[]) | undefined;
306
-
307
253
  if (typeof optionsOrUse === "function") {
308
254
  options = { [RESPONSE_TYPE]: responseType };
309
255
  use = optionsOrUse;
@@ -1,12 +1,19 @@
1
- import type { ReactNode } from "react";
2
- import type { Handler, TrailingSlashMode } from "../types.js";
3
- import type {
4
- AllUseItems,
5
- RouteUseItem,
6
- UrlPatternsBrand,
7
- } from "../route-types.js";
1
+ import type { TrailingSlashMode } from "../types.js";
2
+ import type { AllUseItems, UrlPatternsBrand } from "../route-types.js";
8
3
  import type { SearchSchema } from "../search-params.js";
9
4
  import { RESPONSE_TYPE } from "./response-types.js";
5
+ import type { DefaultEnv } from "../types.js";
6
+ import type { PathHelpers } from "./path-helper-types.js";
7
+
8
+ /**
9
+ * Builder function accepted by urls() and as a shorthand for routes()/urls option.
10
+ * When passed directly to routes() or createRouter({ urls }), it is wrapped in urls() automatically.
11
+ */
12
+ export type UrlBuilder<
13
+ TEnv = DefaultEnv,
14
+ TItems extends readonly (AllUseItems | readonly AllUseItems[])[] =
15
+ readonly AllUseItems[],
16
+ > = (helpers: PathHelpers<TEnv>) => TItems;
10
17
 
11
18
  /**
12
19
  * Sentinel type for unnamed routes.
@@ -42,16 +49,6 @@ export interface PathOptions<
42
49
  [RESPONSE_TYPE]?: string;
43
50
  }
44
51
 
45
- /**
46
- * Internal representation of a URL pattern definition
47
- */
48
- export interface PathDefinition {
49
- pattern: string;
50
- name?: string;
51
- handler: ReactNode | Handler<any, any, any>;
52
- use?: RouteUseItem[];
53
- }
54
-
55
52
  /**
56
53
  * Result of urls() - contains the route definitions
57
54
  */
@@ -60,8 +57,6 @@ export interface UrlPatterns<
60
57
  TRoutes extends Record<string, any> = Record<string, string>,
61
58
  TResponses extends Record<string, unknown> = Record<string, unknown>,
62
59
  > {
63
- /** Internal: route definitions */
64
- readonly definitions: PathDefinition[];
65
60
  /** Internal: compiled handler function */
66
61
  readonly handler: () => AllUseItems[];
67
62
  /** Internal: trailing slash config per route name */
@@ -76,6 +71,40 @@ export interface UrlPatterns<
76
71
  readonly _responses?: TResponses;
77
72
  }
78
73
 
74
+ /**
75
+ * Extract the phantom env type carried by a UrlPatterns value.
76
+ */
77
+ export type UrlPatternsEnv<T> =
78
+ T extends UrlPatterns<infer TEnv, any, any> ? TEnv : never;
79
+
80
+ /**
81
+ * Guards `routes()` env compatibility without over-constraining.
82
+ *
83
+ * - An env-agnostic block (its env is `unknown` — e.g. a shared urls() module,
84
+ * or an app that does not augment `Rango.Env`) attaches to any router.
85
+ * - A block carrying a concrete env is accepted only when the router env
86
+ * (`TRouterEnv`) satisfies it; resolves to `never` otherwise, so a
87
+ * `urls<{ DB: D1Database }>()` cannot be mounted on a `createRouter<{}>()`.
88
+ *
89
+ * Use as `patterns: T & EnvCompatible<T, TEnv>` so `T` still infers from the
90
+ * argument — a bare `EnvCompatible<T, TEnv>` parameter sits in a non-inferrable
91
+ * conditional position and would collapse `T` to its constraint.
92
+ *
93
+ * Known limitation: `TRouterEnv extends ...` distributes over a union router env,
94
+ * so a `urls<A>()` block is accepted on `createRouter<A | B>()` even though the
95
+ * `B` arm cannot supply `A`'s env. Suppressing distribution with
96
+ * `[TRouterEnv] extends [...]` would close that edge but breaks the common
97
+ * generic-`TEnv` call sites (a deferred type parameter can't resolve the tuple
98
+ * conditional, so the intersection stops reducing to `T`). A router has one env,
99
+ * so a union env is not a supported pattern; the distributive form is kept.
100
+ */
101
+ export type EnvCompatible<TPatterns, TRouterEnv> =
102
+ unknown extends UrlPatternsEnv<TPatterns>
103
+ ? TPatterns
104
+ : TRouterEnv extends UrlPatternsEnv<TPatterns>
105
+ ? TPatterns
106
+ : never;
107
+
79
108
  /**
80
109
  * Options for include()
81
110
  */
@@ -4,6 +4,8 @@ import type {
4
4
  DefaultReverseRouteMap,
5
5
  DefaultVars,
6
6
  } from "../types/global-namespace.js";
7
+ import type { UseItems, ResponseRouteUseItem } from "../route-types.js";
8
+ import type { RequestScope } from "../types/request-scope.js";
7
9
 
8
10
  /**
9
11
  * Reverse function for response handler contexts.
@@ -30,17 +32,31 @@ type ResponseReverseFunction = [DefaultReverseRouteMap] extends [
30
32
  * Symbol marking a route as a response route (non-RSC).
31
33
  * Stored on PathOptions and UrlPatterns to signal the trie to short-circuit.
32
34
  */
33
- export const RESPONSE_TYPE: unique symbol = Symbol.for(
34
- "rangojs.responseType",
35
- ) as any;
35
+ export const RESPONSE_TYPE: unique symbol = Symbol.for("rangojs.responseType");
36
+
37
+ /**
38
+ * Shared shape of a response-route handler: a function returning TReturn (or a
39
+ * promise of it), plus an optional composable `use` thunk merged at mount time.
40
+ */
41
+ type ResponseHandlerOf<
42
+ TReturn,
43
+ TParams = Record<string, string>,
44
+ TEnv = any,
45
+ > = ((
46
+ ctx: ResponseHandlerContext<TParams, TEnv>,
47
+ ) => TReturn | Promise<TReturn>) & {
48
+ /** Composable default DSL items merged when the handler is mounted. */
49
+ use?: () => UseItems<ResponseRouteUseItem>;
50
+ };
36
51
 
37
52
  /**
38
53
  * Handler that must return Response (not ReactNode).
39
54
  * Used by path.image(), path.stream(), path.any() (binary/streaming data).
40
55
  */
41
- export type ResponseHandler<TParams = Record<string, string>, TEnv = any> = (
42
- ctx: ResponseHandlerContext<TParams, TEnv>,
43
- ) => Response | Promise<Response>;
56
+ export type ResponseHandler<
57
+ TParams = Record<string, string>,
58
+ TEnv = any,
59
+ > = ResponseHandlerOf<Response, TParams, TEnv>;
44
60
 
45
61
  /**
46
62
  * JSON-serializable value type for auto-wrap support.
@@ -60,9 +76,7 @@ export type JsonValue =
60
76
  export type JsonResponseHandler<
61
77
  TParams = Record<string, string>,
62
78
  TEnv = any,
63
- > = (
64
- ctx: ResponseHandlerContext<TParams, TEnv>,
65
- ) => JsonValue | Response | Promise<JsonValue | Response>;
79
+ > = ResponseHandlerOf<JsonValue | Response, TParams, TEnv>;
66
80
 
67
81
  /**
68
82
  * Handler for text-based response routes (text, html, xml).
@@ -71,9 +85,7 @@ export type JsonResponseHandler<
71
85
  export type TextResponseHandler<
72
86
  TParams = Record<string, string>,
73
87
  TEnv = any,
74
- > = (
75
- ctx: ResponseHandlerContext<TParams, TEnv>,
76
- ) => string | Response | Promise<string | Response>;
88
+ > = ResponseHandlerOf<string | Response, TParams, TEnv>;
77
89
 
78
90
  /**
79
91
  * Lighter handler context for response routes.
@@ -83,19 +95,10 @@ export type TextResponseHandler<
83
95
  export interface ResponseHandlerContext<
84
96
  TParams = Record<string, string>,
85
97
  TEnv = any,
86
- > {
87
- request: Request;
98
+ > extends RequestScope<TEnv> {
88
99
  params: TParams;
89
100
  /** @internal Phantom property for params type invariance. Prevents mounting handlers on wrong routes. */
90
101
  readonly _paramCheck?: (params: TParams) => TParams;
91
- /** Platform bindings (DB, KV, secrets, etc.). */
92
- env: TEnv;
93
- /** Query parameters from the URL (system params like `_rsc*` are filtered). */
94
- searchParams: URLSearchParams;
95
- /** The full URL object (with system params filtered). */
96
- url: URL;
97
- /** The pathname portion of the request URL. */
98
- pathname: string;
99
102
  reverse: ResponseReverseFunction;
100
103
  /** Read a variable set by middleware via ctx.set(key, value) or ctx.set(ContextVar, value). */
101
104
  get: {