@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa

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 (411) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +296 -887
  3. package/dist/bin/rango.js +459 -91
  4. package/dist/testing/vitest.js +36 -2
  5. package/dist/vite/index.js +1708 -414
  6. package/package.json +35 -10
  7. package/skills/api-client/SKILL.md +211 -0
  8. package/skills/breadcrumbs/SKILL.md +82 -5
  9. package/skills/bundle-analysis/SKILL.md +2 -2
  10. package/skills/cache-guide/SKILL.md +14 -9
  11. package/skills/caching/SKILL.md +221 -12
  12. package/skills/catalog.json +271 -0
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +83 -2
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +5 -3
  19. package/skills/defer-hydration/SKILL.md +235 -0
  20. package/skills/document-cache/SKILL.md +11 -3
  21. package/skills/fonts/SKILL.md +1 -1
  22. package/skills/handler-use/SKILL.md +9 -9
  23. package/skills/hooks/SKILL.md +73 -900
  24. package/skills/hooks/data.md +273 -0
  25. package/skills/hooks/handle-and-actions.md +103 -0
  26. package/skills/hooks/navigation.md +110 -0
  27. package/skills/hooks/outlets.md +41 -0
  28. package/skills/hooks/state.md +228 -0
  29. package/skills/hooks/urls.md +135 -0
  30. package/skills/host-router/SKILL.md +84 -7
  31. package/skills/i18n/SKILL.md +1 -1
  32. package/skills/intercept/SKILL.md +51 -17
  33. package/skills/layout/SKILL.md +38 -16
  34. package/skills/links/SKILL.md +1 -1
  35. package/skills/loader/SKILL.md +48 -20
  36. package/skills/middleware/SKILL.md +11 -5
  37. package/skills/migrate-nextjs/SKILL.md +203 -20
  38. package/skills/migrate-react-router/SKILL.md +59 -675
  39. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  40. package/skills/migrate-react-router/component-migration.md +196 -0
  41. package/skills/migrate-react-router/data-and-actions.md +225 -0
  42. package/skills/migrate-react-router/route-mapping.md +271 -0
  43. package/skills/mime-routes/SKILL.md +3 -3
  44. package/skills/observability/SKILL.md +70 -5
  45. package/skills/parallel/SKILL.md +32 -8
  46. package/skills/ppr/SKILL.md +622 -0
  47. package/skills/prerender/SKILL.md +59 -28
  48. package/skills/rango/SKILL.md +124 -50
  49. package/skills/response-routes/SKILL.md +78 -46
  50. package/skills/route/SKILL.md +85 -6
  51. package/skills/router-setup/SKILL.md +41 -6
  52. package/skills/scripts/SKILL.md +179 -0
  53. package/skills/server-actions/SKILL.md +28 -3
  54. package/skills/shell-manifest/SKILL.md +185 -0
  55. package/skills/streams-and-websockets/SKILL.md +1 -1
  56. package/skills/tailwind/SKILL.md +28 -4
  57. package/skills/testing/SKILL.md +68 -654
  58. package/skills/testing/bindings.md +103 -0
  59. package/skills/testing/cache-prerender.md +127 -0
  60. package/skills/testing/client-components.md +124 -0
  61. package/skills/testing/e2e-parity.md +125 -0
  62. package/skills/testing/flight.md +91 -0
  63. package/skills/testing/handles.md +131 -0
  64. package/skills/testing/loader.md +128 -0
  65. package/skills/testing/middleware.md +99 -0
  66. package/skills/testing/render-handler.md +122 -0
  67. package/skills/testing/response-routes.md +95 -0
  68. package/skills/testing/reverse-and-types.md +85 -0
  69. package/skills/testing/server-actions.md +107 -0
  70. package/skills/testing/server-tree.md +128 -0
  71. package/skills/testing/setup.md +123 -0
  72. package/skills/theme/SKILL.md +1 -1
  73. package/skills/typesafety/SKILL.md +45 -918
  74. package/skills/typesafety/env-and-bindings.md +254 -0
  75. package/skills/typesafety/generated-files-and-cli.md +335 -0
  76. package/skills/typesafety/params-and-search.md +153 -0
  77. package/skills/typesafety/route-types.md +209 -0
  78. package/skills/use-cache/SKILL.md +47 -17
  79. package/skills/vercel/SKILL.md +128 -0
  80. package/skills/view-transitions/SKILL.md +44 -1
  81. package/src/__augment-tests__/augmented.check.ts +2 -3
  82. package/src/__internal.ts +0 -65
  83. package/src/browser/action-coordinator.ts +1 -1
  84. package/src/browser/action-fence.ts +47 -0
  85. package/src/browser/app-shell.ts +14 -27
  86. package/src/browser/connection-warmup.ts +134 -0
  87. package/src/browser/cookie-name.ts +140 -0
  88. package/src/browser/event-controller.ts +178 -100
  89. package/src/browser/invalidate-client-cache.ts +52 -0
  90. package/src/browser/logging.ts +28 -0
  91. package/src/browser/merge-segment-loaders.ts +6 -4
  92. package/src/browser/navigation-bridge.ts +81 -68
  93. package/src/browser/navigation-client.ts +115 -70
  94. package/src/browser/navigation-store-handle.ts +38 -0
  95. package/src/browser/navigation-store.ts +153 -88
  96. package/src/browser/navigation-transaction.ts +0 -32
  97. package/src/browser/network-error-handler.ts +34 -7
  98. package/src/browser/partial-update.ts +157 -144
  99. package/src/browser/prefetch/cache.ts +148 -81
  100. package/src/browser/prefetch/fetch.ts +231 -51
  101. package/src/browser/prefetch/queue.ts +25 -7
  102. package/src/browser/rango-state.ts +157 -115
  103. package/src/browser/react/Link.tsx +40 -7
  104. package/src/browser/react/NavigationProvider.tsx +140 -99
  105. package/src/browser/react/ScrollRestoration.tsx +10 -6
  106. package/src/browser/react/filter-segment-order.ts +17 -2
  107. package/src/browser/react/index.ts +0 -51
  108. package/src/browser/react/location-state-shared.ts +14 -15
  109. package/src/browser/react/location-state.ts +0 -1
  110. package/src/browser/react/use-action.ts +6 -15
  111. package/src/browser/react/use-handle.ts +0 -5
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +33 -8
  114. package/src/browser/react/use-navigation.ts +10 -5
  115. package/src/browser/react/use-params.ts +0 -2
  116. package/src/browser/react/use-router.ts +6 -4
  117. package/src/browser/react/use-search-params.ts +0 -5
  118. package/src/browser/react/use-segments.ts +0 -13
  119. package/src/browser/response-adapter.ts +74 -8
  120. package/src/browser/rsc-router.tsx +97 -22
  121. package/src/browser/scroll-restoration.ts +15 -8
  122. package/src/browser/segment-reconciler.ts +31 -21
  123. package/src/browser/server-action-bridge.ts +216 -38
  124. package/src/browser/types.ts +94 -22
  125. package/src/browser/validate-redirect-origin.ts +43 -16
  126. package/src/build/generate-manifest.ts +155 -131
  127. package/src/build/generate-route-types.ts +1 -1
  128. package/src/build/index.ts +11 -5
  129. package/src/build/prefix-tree-utils.ts +123 -0
  130. package/src/build/route-trie.ts +152 -22
  131. package/src/build/route-types/ast-route-extraction.ts +15 -8
  132. package/src/build/route-types/codegen.ts +12 -1
  133. package/src/build/route-types/include-resolution.ts +455 -61
  134. package/src/build/route-types/param-extraction.ts +6 -3
  135. package/src/build/route-types/per-module-writer.ts +15 -2
  136. package/src/build/route-types/router-processing.ts +77 -41
  137. package/src/build/route-types/source-scan.ts +105 -7
  138. package/src/build/runtime-discovery.ts +4 -1
  139. package/src/cache/cache-error.ts +104 -0
  140. package/src/cache/cache-key-utils.ts +58 -13
  141. package/src/cache/cache-policy.ts +108 -34
  142. package/src/cache/cache-runtime.ts +454 -101
  143. package/src/cache/cache-scope.ts +159 -54
  144. package/src/cache/cache-tag.ts +149 -0
  145. package/src/cache/cf/cf-base64.ts +33 -0
  146. package/src/cache/cf/cf-cache-constants.ts +127 -0
  147. package/src/cache/cf/cf-cache-store.ts +2170 -377
  148. package/src/cache/cf/cf-cache-types.ts +349 -0
  149. package/src/cache/cf/cf-kv-utils.ts +46 -0
  150. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  151. package/src/cache/cf/index.ts +6 -16
  152. package/src/cache/document-cache.ts +126 -41
  153. package/src/cache/handle-snapshot.ts +70 -0
  154. package/src/cache/index.ts +23 -20
  155. package/src/cache/memory-segment-store.ts +243 -37
  156. package/src/cache/profile-registry.ts +46 -31
  157. package/src/cache/read-through-swr.ts +56 -12
  158. package/src/cache/segment-codec.ts +13 -21
  159. package/src/cache/shell-snapshot.ts +417 -0
  160. package/src/cache/tag-invalidation.ts +230 -0
  161. package/src/cache/types.ts +194 -99
  162. package/src/cache/vercel/index.ts +11 -0
  163. package/src/cache/vercel/vercel-cache-store.ts +1132 -0
  164. package/src/client.rsc.tsx +39 -22
  165. package/src/client.tsx +28 -58
  166. package/src/cloudflare/index.ts +11 -0
  167. package/src/cloudflare/tracing.ts +108 -0
  168. package/src/component-utils.ts +19 -0
  169. package/src/components/DefaultDocument.tsx +8 -2
  170. package/src/context-var.ts +13 -1
  171. package/src/decode-loader-results.ts +18 -2
  172. package/src/defer.ts +185 -0
  173. package/src/deps/ssr.ts +0 -1
  174. package/src/encode-kv.ts +49 -0
  175. package/src/errors.ts +0 -3
  176. package/src/escape-script.ts +52 -0
  177. package/src/handle.ts +57 -40
  178. package/src/handles/MetaTags.tsx +24 -53
  179. package/src/handles/Scripts.tsx +183 -0
  180. package/src/handles/breadcrumbs.ts +35 -8
  181. package/src/handles/deferred-resolution.ts +127 -0
  182. package/src/handles/is-thenable.ts +18 -0
  183. package/src/handles/meta.ts +14 -40
  184. package/src/handles/script.ts +244 -0
  185. package/src/host/cookie-handler.ts +9 -60
  186. package/src/host/errors.ts +13 -22
  187. package/src/host/index.ts +7 -0
  188. package/src/host/pattern-matcher.ts +23 -52
  189. package/src/host/router.ts +1 -65
  190. package/src/host/testing.ts +40 -27
  191. package/src/host/types.ts +6 -2
  192. package/src/href-client.ts +7 -12
  193. package/src/index.rsc.ts +88 -8
  194. package/src/index.ts +90 -16
  195. package/src/internal-debug.ts +11 -10
  196. package/src/loader.rsc.ts +19 -9
  197. package/src/loader.ts +12 -4
  198. package/src/outlet-provider.tsx +1 -5
  199. package/src/prerender/param-hash.ts +16 -16
  200. package/src/prerender/store.ts +32 -37
  201. package/src/prerender.ts +75 -7
  202. package/src/redirect-origin.ts +114 -0
  203. package/src/regex-escape.ts +8 -0
  204. package/src/render-error-thrower.tsx +20 -0
  205. package/src/response-utils.ts +25 -0
  206. package/src/root-error-boundary.tsx +1 -19
  207. package/src/route-content-wrapper.tsx +13 -49
  208. package/src/route-definition/dsl-helpers.ts +60 -53
  209. package/src/route-definition/helper-factories.ts +0 -2
  210. package/src/route-definition/helpers-types.ts +46 -46
  211. package/src/route-definition/index.ts +1 -2
  212. package/src/route-definition/redirect.ts +44 -11
  213. package/src/route-definition/resolve-handler-use.ts +6 -1
  214. package/src/route-definition/use-item-types.ts +3 -6
  215. package/src/route-map-builder.ts +41 -20
  216. package/src/route-types.ts +0 -5
  217. package/src/router/content-negotiation.ts +58 -23
  218. package/src/router/error-handling.ts +44 -17
  219. package/src/router/find-match.ts +129 -30
  220. package/src/router/handler-context.ts +6 -1
  221. package/src/router/instrument.ts +355 -0
  222. package/src/router/intercept-resolution.ts +35 -2
  223. package/src/router/lazy-includes.ts +79 -56
  224. package/src/router/loader-resolution.ts +151 -73
  225. package/src/router/logging.ts +0 -6
  226. package/src/router/manifest.ts +74 -40
  227. package/src/router/match-api.ts +76 -52
  228. package/src/router/match-context.ts +0 -22
  229. package/src/router/match-handlers.ts +181 -178
  230. package/src/router/match-middleware/background-revalidation.ts +40 -24
  231. package/src/router/match-middleware/cache-lookup.ts +115 -194
  232. package/src/router/match-middleware/cache-store.ts +61 -50
  233. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  234. package/src/router/match-middleware/segment-resolution.ts +0 -22
  235. package/src/router/match-pipelines.ts +1 -42
  236. package/src/router/match-result.ts +36 -67
  237. package/src/router/metrics.ts +0 -34
  238. package/src/router/middleware-types.ts +0 -116
  239. package/src/router/middleware.ts +231 -120
  240. package/src/router/navigation-snapshot.ts +7 -56
  241. package/src/router/params-util.ts +23 -0
  242. package/src/router/parse-pattern.ts +115 -0
  243. package/src/router/pattern-matching.ts +99 -152
  244. package/src/router/prefetch-cache-ttl.ts +51 -0
  245. package/src/router/prefetch-limits.ts +37 -0
  246. package/src/router/prerender-match.ts +111 -66
  247. package/src/router/preview-match.ts +3 -1
  248. package/src/router/request-classification.ts +47 -42
  249. package/src/router/revalidation.ts +75 -81
  250. package/src/router/route-snapshot.ts +14 -3
  251. package/src/router/router-context.ts +6 -29
  252. package/src/router/router-interfaces.ts +70 -8
  253. package/src/router/router-options.ts +126 -4
  254. package/src/router/segment-resolution/fresh.ts +104 -80
  255. package/src/router/segment-resolution/helpers.ts +86 -6
  256. package/src/router/segment-resolution/loader-cache.ts +155 -39
  257. package/src/router/segment-resolution/loader-mask.ts +60 -0
  258. package/src/router/segment-resolution/loader-snapshot.ts +259 -0
  259. package/src/router/segment-resolution/mask-nested.ts +83 -0
  260. package/src/router/segment-resolution/revalidation.ts +215 -304
  261. package/src/router/segment-resolution/static-store.ts +19 -5
  262. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  263. package/src/router/segment-resolution/view-transition-default.ts +35 -15
  264. package/src/router/segment-resolution.ts +5 -1
  265. package/src/router/segment-wrappers.ts +6 -5
  266. package/src/router/state-cookie-name.ts +33 -0
  267. package/src/router/substitute-pattern-params.ts +54 -35
  268. package/src/router/telemetry-otel.ts +160 -200
  269. package/src/router/telemetry.ts +9 -23
  270. package/src/router/timeout.ts +0 -20
  271. package/src/router/tracing.ts +215 -0
  272. package/src/router/trie-matching.ts +171 -64
  273. package/src/router/types.ts +1 -63
  274. package/src/router/url-params.ts +13 -5
  275. package/src/router.ts +119 -48
  276. package/src/rsc/full-payload.ts +70 -0
  277. package/src/rsc/handler-context.ts +1 -0
  278. package/src/rsc/handler.ts +267 -152
  279. package/src/rsc/helpers.ts +78 -4
  280. package/src/rsc/index.ts +1 -4
  281. package/src/rsc/json-route-result.ts +38 -0
  282. package/src/rsc/loader-fetch.ts +114 -38
  283. package/src/rsc/manifest-init.ts +29 -42
  284. package/src/rsc/nonce.ts +10 -1
  285. package/src/rsc/origin-guard.ts +11 -15
  286. package/src/rsc/progressive-enhancement.ts +120 -13
  287. package/src/rsc/redirect-guard.ts +100 -0
  288. package/src/rsc/response-cache-serve.ts +238 -0
  289. package/src/rsc/response-error.ts +79 -12
  290. package/src/rsc/response-route-handler.ts +58 -141
  291. package/src/rsc/rsc-rendering.ts +492 -49
  292. package/src/rsc/runtime-warnings.ts +14 -0
  293. package/src/rsc/server-action.ts +268 -82
  294. package/src/rsc/shell-capture.ts +1190 -0
  295. package/src/rsc/shell-serve.ts +181 -0
  296. package/src/rsc/transition-gate.ts +89 -0
  297. package/src/rsc/types.ts +45 -3
  298. package/src/runtime-env.ts +18 -0
  299. package/src/search-params.ts +31 -26
  300. package/src/segment-loader-promise.ts +49 -4
  301. package/src/segment-system.tsx +260 -95
  302. package/src/server/context.ts +99 -9
  303. package/src/server/cookie-parse.ts +32 -0
  304. package/src/server/cookie-store.ts +125 -2
  305. package/src/server/handle-store.ts +21 -38
  306. package/src/server/loader-registry.ts +33 -42
  307. package/src/server/request-context.ts +379 -138
  308. package/src/ssr/index.tsx +491 -182
  309. package/src/ssr/inject-rsc-eager.ts +167 -0
  310. package/src/ssr/ssr-root.tsx +228 -0
  311. package/src/static-handler.ts +10 -13
  312. package/src/testing/cache-status.ts +44 -48
  313. package/src/testing/collect-handle.ts +14 -31
  314. package/src/testing/dispatch.ts +533 -160
  315. package/src/testing/e2e/fixture.ts +45 -11
  316. package/src/testing/e2e/index.ts +1 -22
  317. package/src/testing/e2e/matchers.ts +0 -16
  318. package/src/testing/e2e/parity.ts +85 -4
  319. package/src/testing/e2e/server.ts +12 -0
  320. package/src/testing/flight-matchers.ts +7 -14
  321. package/src/testing/flight-normalize.ts +11 -0
  322. package/src/testing/flight-runtime.d.ts +36 -0
  323. package/src/testing/flight-tree.ts +682 -0
  324. package/src/testing/flight.entry.ts +30 -0
  325. package/src/testing/flight.ts +145 -70
  326. package/src/testing/generated-routes.ts +26 -50
  327. package/src/testing/index.ts +18 -19
  328. package/src/testing/internal/context.ts +184 -68
  329. package/src/testing/internal/flight-client-globals.ts +30 -0
  330. package/src/testing/internal/seed-vars.ts +54 -0
  331. package/src/testing/render-handler.ts +357 -0
  332. package/src/testing/render-route.tsx +134 -115
  333. package/src/testing/run-loader.ts +140 -51
  334. package/src/testing/run-middleware.ts +59 -33
  335. package/src/testing/run-transition-when.ts +164 -0
  336. package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
  337. package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
  338. package/src/testing/vitest.ts +138 -16
  339. package/src/theme/ThemeProvider.tsx +56 -84
  340. package/src/theme/ThemeScript.tsx +7 -9
  341. package/src/theme/constants.ts +52 -13
  342. package/src/theme/index.ts +0 -7
  343. package/src/theme/theme-context.ts +1 -5
  344. package/src/theme/theme-script.ts +22 -21
  345. package/src/theme/use-theme.ts +0 -3
  346. package/src/types/boundaries.ts +0 -35
  347. package/src/types/cache-types.ts +13 -4
  348. package/src/types/error-types.ts +30 -90
  349. package/src/types/global-namespace.ts +15 -15
  350. package/src/types/handler-context.ts +45 -15
  351. package/src/types/index.ts +2 -10
  352. package/src/types/loader-types.ts +6 -3
  353. package/src/types/request-scope.ts +8 -22
  354. package/src/types/route-config.ts +20 -52
  355. package/src/types/route-entry.ts +0 -6
  356. package/src/types/segments.ts +100 -13
  357. package/src/urls/include-helper.ts +10 -12
  358. package/src/urls/include-provider.ts +71 -0
  359. package/src/urls/index.ts +2 -8
  360. package/src/urls/path-helper-types.ts +52 -14
  361. package/src/urls/path-helper.ts +5 -54
  362. package/src/urls/pattern-types.ts +36 -0
  363. package/src/urls/type-extraction.ts +76 -42
  364. package/src/urls/urls-function.ts +0 -14
  365. package/src/use-loader.tsx +0 -186
  366. package/src/vercel/index.ts +11 -0
  367. package/src/vercel/tracing.ts +88 -0
  368. package/src/vite/discovery/bundle-postprocess.ts +2 -1
  369. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  370. package/src/vite/discovery/discover-routers.ts +34 -43
  371. package/src/vite/discovery/discovery-errors.ts +61 -0
  372. package/src/vite/discovery/prerender-collection.ts +33 -46
  373. package/src/vite/discovery/state.ts +12 -1
  374. package/src/vite/discovery/virtual-module-codegen.ts +1 -11
  375. package/src/vite/index.ts +9 -0
  376. package/src/vite/inject-client-debug.ts +88 -0
  377. package/src/vite/plugin-types.ts +143 -10
  378. package/src/vite/plugins/cjs-to-esm.ts +8 -12
  379. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  380. package/src/vite/plugins/client-ref-hashing.ts +0 -10
  381. package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
  382. package/src/vite/plugins/expose-action-id.ts +2 -73
  383. package/src/vite/plugins/expose-id-utils.ts +85 -56
  384. package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
  385. package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
  386. package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
  387. package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
  388. package/src/vite/plugins/expose-internal-ids.ts +10 -1
  389. package/src/vite/plugins/performance-tracks.ts +0 -3
  390. package/src/vite/plugins/refresh-cmd.ts +1 -1
  391. package/src/vite/plugins/use-cache-transform.ts +21 -46
  392. package/src/vite/plugins/vercel-output.ts +384 -0
  393. package/src/vite/plugins/version-injector.ts +22 -27
  394. package/src/vite/plugins/version-plugin.ts +6 -66
  395. package/src/vite/plugins/virtual-entries.ts +137 -26
  396. package/src/vite/rango.ts +146 -135
  397. package/src/vite/router-discovery.ts +189 -48
  398. package/src/vite/utils/ast-handler-extract.ts +11 -20
  399. package/src/vite/utils/bundle-analysis.ts +6 -13
  400. package/src/vite/utils/client-chunks.ts +0 -6
  401. package/src/vite/utils/directive-prologue.ts +40 -0
  402. package/src/vite/utils/forward-user-plugins.ts +0 -22
  403. package/src/vite/utils/manifest-utils.ts +4 -75
  404. package/src/vite/utils/package-resolution.ts +1 -73
  405. package/src/vite/utils/prerender-utils.ts +71 -44
  406. package/src/vite/utils/shared-utils.ts +55 -37
  407. package/src/browser/react/use-client-cache.ts +0 -58
  408. package/src/browser/shallow.ts +0 -40
  409. package/src/handles/index.ts +0 -7
  410. package/src/network-error-thrower.tsx +0 -23
  411. package/src/router/middleware-cookies.ts +0 -55
@@ -28,7 +28,6 @@ import type {
28
28
  ParallelUseItem,
29
29
  InterceptUseItem,
30
30
  LoaderUseItem,
31
- WhenItem,
32
31
  TypedCacheItem,
33
32
  TransitionItem,
34
33
  TypedTransitionItem,
@@ -42,7 +41,6 @@ import type {
42
41
  PassthroughHandlerDefinition,
43
42
  } from "../prerender.js";
44
43
  import type { StaticHandlerDefinition } from "../static-handler.js";
45
- import type { InterceptWhenFn } from "../server/context";
46
44
  import type {
47
45
  ResponseHandler,
48
46
  ResponseHandlerContext,
@@ -114,6 +112,12 @@ export type ResponsePathFn<TEnv> = <
114
112
  * Path function for JSON response routes (path.json()).
115
113
  * Handler can return plain JSON-serializable values or Response.
116
114
  * TData is inferred from the handler's return type (excluding Response/Promise wrappers).
115
+ *
116
+ * Note: a nested Promise in the return (a forgotten await) is caught at runtime
117
+ * by response-route-handler.ts (it throws instead of silently emitting `{}`). A
118
+ * compile-time JsonValue constraint was evaluated and rejected — it breaks
119
+ * interface-typed returns (interfaces lack the index signature JsonValue
120
+ * requires) and preserves literal types in the inferred response shape.
117
121
  */
118
122
  export type JsonResponsePathFn<TEnv> = <
119
123
  const TPattern extends string,
@@ -148,6 +152,30 @@ export type TextResponsePathFn<TEnv> = <
148
152
  use?: () => UseItems<ResponseRouteUseItem>,
149
153
  ) => TypedRouteItem<TName, TPattern, string, TSearch>;
150
154
 
155
+ /**
156
+ * What an async include() provider resolves to. Route types (`TRoutes`) are
157
+ * inferred from the resolved `urls()` value so `href()` and named routes stay
158
+ * type-safe through a code-split module (`() => import("./routes")`).
159
+ */
160
+ type IncludeResolved<
161
+ TEnv,
162
+ TRoutes extends Record<string, any>,
163
+ TResponses extends Record<string, unknown>,
164
+ > =
165
+ | UrlPatterns<TEnv, TRoutes, TResponses>
166
+ | { default: UrlPatterns<TEnv, TRoutes, TResponses> };
167
+
168
+ /** include() argument: an eager `urls()` value or an async provider thunk. */
169
+ export type IncludeArg<
170
+ TEnv,
171
+ TRoutes extends Record<string, any>,
172
+ TResponses extends Record<string, unknown>,
173
+ > =
174
+ | UrlPatterns<TEnv, TRoutes, TResponses>
175
+ | (() =>
176
+ | IncludeResolved<TEnv, TRoutes, TResponses>
177
+ | Promise<IncludeResolved<TEnv, TRoutes, TResponses>>);
178
+
151
179
  /**
152
180
  * Base include function signature.
153
181
  */
@@ -158,7 +186,7 @@ export type IncludeFn<TEnv> = <
158
186
  TResponses extends Record<string, unknown> = Record<string, unknown>,
159
187
  >(
160
188
  prefix: TUrlPrefix,
161
- patterns: UrlPatterns<TEnv, TRoutes, TResponses>,
189
+ patterns: IncludeArg<TEnv, TRoutes, TResponses>,
162
190
  options?: IncludeOptions<TNamePrefix>,
163
191
  ) => TypedIncludeItem<TRoutes, TNamePrefix, TUrlPrefix, TResponses>;
164
192
 
@@ -240,9 +268,16 @@ export type PathHelpers<TEnv> = {
240
268
  * `{ handler, use? }` whose `use` is scoped to that slot only. Per-slot
241
269
  * merge order is `handler.use` → shared `use` → slot-local `use`, with
242
270
  * narrowest scope winning for last-write-wins items like `loading()`.
271
+ *
272
+ * Not generic over the slots record: an inferred type parameter makes the
273
+ * object literal an inference site, which suppresses contextual typing of
274
+ * arrow slot handlers (`(ctx) => ...` was implicit any). Bare handlers infer
275
+ * now; a descriptor's `handler:` arrow still needs an explicit ctx annotation
276
+ * because StaticHandlerDefinition's own `.handler` joins the contextual union
277
+ * (two callables — see parallel-slot-handler-types.test.ts).
243
278
  */
244
- parallel: <
245
- TSlots extends Record<
279
+ parallel: (
280
+ slots: Record<
246
281
  `@${string}`,
247
282
  | Handler<any, any, TEnv>
248
283
  | ReactNode
@@ -255,8 +290,6 @@ export type PathHelpers<TEnv> = {
255
290
  use?: () => ParallelUseItem[];
256
291
  }
257
292
  >,
258
- >(
259
- slots: TSlots,
260
293
  use?: () => ParallelUseItem[],
261
294
  ) => ParallelItem;
262
295
 
@@ -269,12 +302,18 @@ export type PathHelpers<TEnv> = {
269
302
  slotName: `@${string}`,
270
303
  routeName: string,
271
304
  handler: ReactNode | Handler<any, any, TEnv>,
305
+ config?:
306
+ | import("../server/context.js").InterceptConfig<TEnv>
307
+ | (() => InterceptUseItem[]),
272
308
  use?: () => InterceptUseItem[],
273
309
  ) => InterceptItem
274
310
  : (
275
311
  slotName: `@${string}`,
276
312
  routeName: (keyof Rango.GeneratedRouteMap & string) | `.${string}`,
277
313
  handler: ReactNode | Handler<any, any, TEnv>,
314
+ config?:
315
+ | import("../server/context.js").InterceptConfig<TEnv>
316
+ | (() => InterceptUseItem[]),
278
317
  use?: () => InterceptUseItem[],
279
318
  ) => InterceptItem;
280
319
 
@@ -329,11 +368,6 @@ export type PathHelpers<TEnv> = {
329
368
  fallback: ReactNode | NotFoundBoundaryHandler,
330
369
  ) => NotFoundBoundaryItem;
331
370
 
332
- /**
333
- * Define a condition for when an intercept should activate
334
- */
335
- when: (fn: InterceptWhenFn) => WhenItem;
336
-
337
371
  /**
338
372
  * Define cache configuration for segments
339
373
  */
@@ -342,9 +376,9 @@ export type PathHelpers<TEnv> = {
342
376
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
343
377
  children: () => TChildren,
344
378
  ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
345
- (options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
379
+ (options: PartialCacheOptions<TEnv> | false): TypedCacheItem<{}, {}>;
346
380
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
347
- options: PartialCacheOptions | false,
381
+ options: PartialCacheOptions<TEnv> | false,
348
382
  use: () => TChildren,
349
383
  ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
350
384
  };
@@ -359,6 +393,10 @@ export type PathHelpers<TEnv> = {
359
393
  * `{ viewTransition: false }` to keep #1 without the router boundary. A view
360
394
  * transition cannot fire without a startTransition. See
361
395
  * skills/view-transitions for the startTransition x ViewTransition matrix.
396
+ *
397
+ * Pass `when: (ctx) => boolean` to gate the transition per request: it runs
398
+ * server-side after the route handler (can read `ctx.get(...)`), and returning
399
+ * false drops the transition so the navigation streams its loading() skeleton.
362
400
  */
363
401
  transition: {
364
402
  (): TransitionItem;
@@ -39,10 +39,6 @@ import {
39
39
  runAndValidateUseItems,
40
40
  } from "../route-definition/dsl-helpers.js";
41
41
 
42
- /**
43
- * Apply URL prefix to a pattern
44
- * Handles edge cases like "/" patterns and double slashes
45
- */
46
42
  function applyUrlPrefix(prefix: string, pattern: string): string {
47
43
  if (!prefix) return pattern;
48
44
  if (pattern === "/") return prefix;
@@ -52,29 +48,17 @@ function applyUrlPrefix(prefix: string, pattern: string): string {
52
48
  return prefix + pattern;
53
49
  }
54
50
 
55
- /**
56
- * Apply name prefix to a route name
57
- */
58
51
  function applyNamePrefix(prefix: string | undefined, name: string): string {
59
52
  if (!prefix) return name;
60
53
  return `${prefix}.${name}`;
61
54
  }
62
55
 
63
- /**
64
- * Resolve response type from path options (set by path.json(), path.text(), etc.)
65
- */
66
56
  function resolveResponseType(
67
57
  options: PathOptions | undefined,
68
58
  ): string | undefined {
69
59
  return options?.[RESPONSE_TYPE];
70
60
  }
71
61
 
72
- /**
73
- * Create path() helper
74
- *
75
- * The path() function is the key new feature - it combines URL pattern
76
- * with handler at the definition site.
77
- */
78
62
  export function createPathHelper<TEnv>(): PathFn<TEnv> {
79
63
  return ((
80
64
  pattern: string,
@@ -91,8 +75,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
91
75
  "path() cannot be used inside parallel()",
92
76
  );
93
77
 
94
- // Walk the parent chain to prevent path() nested under another path(),
95
- // even when separated by intermediate layouts (e.g. path(layout(path())))
96
78
  {
97
79
  let ancestor = ctx.parent;
98
80
  while (ancestor) {
@@ -104,7 +86,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
104
86
  }
105
87
  }
106
88
 
107
- // Determine options and use based on argument types
108
89
  let options: PathOptions | undefined;
109
90
  let use: (() => UseItems<RouteUseItem>) | undefined;
110
91
 
@@ -117,49 +98,29 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
117
98
  use = maybeUse;
118
99
  }
119
100
 
120
- // Merge handler.use() defaults with explicit use()
121
- // Response routes (path.json, path.text, etc.) only allow middleware + cache
122
101
  const handlerUseFn = resolveHandlerUse(handler);
123
102
  const mountSite = resolveResponseType(options) ? "response" : "path";
124
103
  const mergedUse = mergeHandlerUse(handlerUseFn, use, mountSite);
125
104
 
126
- // Get prefixes from context (set by include())
127
105
  const urlPrefix = getUrlPrefix();
128
106
  const namePrefix = getNamePrefix();
129
107
 
130
- // Apply URL prefix to pattern
131
108
  const prefixedPattern = applyUrlPrefix(urlPrefix, pattern);
132
109
 
133
- // Generate route name - use provided name or generate from pattern
134
110
  const localName =
135
111
  options?.name || `$path_${pattern.replace(/[/:*?]/g, "_")}`;
136
112
  if (options?.name) {
137
113
  validateUserRouteName(options.name);
138
114
  }
139
- // Apply name prefix if set (from include())
140
115
  const routeName = applyNamePrefix(namePrefix, localName);
141
116
 
142
117
  const namespace = `${ctx.namespace}.${store.getNextIndex("route")}.${routeName}`;
143
118
 
144
- // Per-request pruning: skip registration for routes that won't be rendered.
145
- // forRoute is set by loadManifest() to the matched route name. During
146
- // evaluateLazyEntry() (route matching), forRoute is unset so all routes
147
- // register normally. We still increment counters to keep shortCodes stable
148
- // across different routes (needed for segment reconciliation on navigation).
149
- //
150
- // include() does not need its own forRoute pruning. include() creates lazy
151
- // entries that defer handler execution until route matching. When the lazy
152
- // handler eventually runs inside loadManifest(), this path() check already
153
- // covers all routes defined inside the include.
154
119
  if (ctx.forRoute && routeName !== ctx.forRoute) {
155
120
  store.getShortCode("route");
156
121
  return { type: "route" } as RouteItem;
157
122
  }
158
123
 
159
- // Ensure handler is always a function (wrap ReactNode or extract from prerender/static def)
160
- // For prerender stubs (production builds where handler code is evicted),
161
- // handler.handler is undefined — provide a notFound fallback so requests
162
- // for non-prerendered params get 404 instead of "handler is not a function".
163
124
  const wrappedHandler: Handler<any, any, TEnv> =
164
125
  typeof handler === "function"
165
126
  ? (handler as Handler<any, any, TEnv>)
@@ -190,7 +151,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
190
151
  type: "route" as const,
191
152
  parent: ctx.parent,
192
153
  handler: wrappedHandler,
193
- // Store the PREFIXED pattern for route matching
194
154
  pattern: prefixedPattern,
195
155
  ...(urlPrefix ? { mountPath: urlPrefix } : {}),
196
156
  ...(isPassthroughHandler(handler)
@@ -215,31 +175,30 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
215
175
  ...(resolveResponseType(options)
216
176
  ? { responseType: resolveResponseType(options) }
217
177
  : {}),
178
+ // PPR shell-caching opt-in (document-level). Stored raw; the integrated
179
+ // serve path normalizes it via resolvePprConfig (rsc/shell-serve.ts).
180
+ ...(options?.ppr !== undefined && options.ppr !== false
181
+ ? { ppr: options.ppr }
182
+ : {}),
218
183
  };
219
184
 
220
- // Capture namespace prefix on static handler for build-time reverse() resolution
221
185
  if (isStaticHandler(handler) && handler.$$id && ctx.namePrefix) {
222
186
  (handler as any).$$routePrefix = ctx.namePrefix;
223
187
  }
224
188
 
225
- // Check for duplicate route names (TypeScript should catch this, but runtime check too)
226
189
  invariant(
227
190
  ctx.manifest.get(routeName) === undefined,
228
191
  `Duplicate route name: ${routeName} at ${namespace}`,
229
192
  );
230
193
 
231
- // Register route entry with prefixed name
232
194
  ctx.manifest.set(routeName, entry);
233
195
 
234
- // Register root-scope flag for dot-local reverse resolution
235
196
  registerRouteRootScope(routeName, getRootScoped());
236
197
 
237
- // Also store pattern in a separate map for URL generation
238
198
  if (ctx.patterns) {
239
199
  ctx.patterns.set(routeName, prefixedPattern);
240
200
  }
241
201
 
242
- // Store pattern grouped by URL prefix for separate entry creation
243
202
  if (ctx.patternsByPrefix) {
244
203
  const urlPrefix = getUrlPrefix() || "";
245
204
  if (!ctx.patternsByPrefix.has(urlPrefix)) {
@@ -248,12 +207,10 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
248
207
  ctx.patternsByPrefix.get(urlPrefix)!.set(routeName, prefixedPattern);
249
208
  }
250
209
 
251
- // Store trailing slash config if specified
252
210
  if (options?.trailingSlash && ctx.trailingSlash) {
253
211
  ctx.trailingSlash.set(routeName, options.trailingSlash);
254
212
  }
255
213
 
256
- // Store search schema if specified
257
214
  if (options?.search) {
258
215
  if (ctx.searchSchemas) {
259
216
  ctx.searchSchemas.set(routeName, options.search);
@@ -261,7 +218,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
261
218
  registerSearchSchema(routeName, options.search);
262
219
  }
263
220
 
264
- // Run merged use callback (handler.use defaults + explicit use) if present
265
221
  if (mergedUse) {
266
222
  const result = runAndValidateUseItems(
267
223
  store,
@@ -278,10 +234,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
278
234
  }) as PathFn<TEnv>;
279
235
  }
280
236
 
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
237
  export function attachPathResponseTags<TEnv>(
286
238
  pathFn: PathFn<TEnv>,
287
239
  ): PathFn<TEnv> & {
@@ -303,7 +255,6 @@ export function attachPathResponseTags<TEnv>(
303
255
  ) => {
304
256
  let options: PathOptions;
305
257
  let use: (() => any[]) | undefined;
306
-
307
258
  if (typeof optionsOrUse === "function") {
308
259
  options = { [RESPONSE_TYPE]: responseType };
309
260
  use = optionsOrUse;
@@ -35,12 +35,48 @@ export type LocalOnlyInclude = string & { [LOCAL_ONLY_BRAND]: void };
35
35
  /**
36
36
  * Options for path() function
37
37
  */
38
+ /**
39
+ * Options for the `ppr` path option (PPR shell caching — Axis 2, see
40
+ * docs/design/ppr-shell-resume.md and the /ppr skill). Declaring
41
+ * `ppr: true | PartialPrerenderProps` on a page route opts that DOCUMENT into
42
+ * shell capture: the rendered HTML shell (everything that is not a live hole) is
43
+ * cached and, on a later GET, flushed immediately while fizz resumes only the
44
+ * holes. Serving is integral to the router — there is no middleware to mount;
45
+ * the shell store is the app-level `createRouter({ cache })` store (which must
46
+ * implement the `getShell`/`putShell` family).
47
+ */
48
+ export interface PartialPrerenderProps {
49
+ /**
50
+ * Shell time-to-live in seconds. Defaults to 300 (`ppr: true` uses the same
51
+ * default).
52
+ */
53
+ ttl?: number;
54
+ /**
55
+ * Stale-while-revalidate window in seconds: a stale shell is still served
56
+ * while a background recapture refreshes it.
57
+ */
58
+ swr?: number;
59
+ /**
60
+ * Operational tags attached to the captured shell entry for
61
+ * `updateTag()`/`revalidateTag()`-driven eviction. UNIONED with the tags the
62
+ * capture render auto-collects (the shell's own non-loader request tags).
63
+ */
64
+ tags?: string[];
65
+ }
66
+
38
67
  export interface PathOptions<
39
68
  TName extends string = string,
40
69
  TSearch extends SearchSchema = {},
41
70
  > {
42
71
  /** Route name for href() lookups */
43
72
  name?: TName;
73
+ /**
74
+ * PPR shell caching opt-in for this page route (document-level). `true` uses
75
+ * the default policy (ttl 300); an object sets ttl/swr/tags. See
76
+ * {@link PartialPrerenderProps}. Routes without this option are pure axis 1 —
77
+ * no capture, no store reads, no logs.
78
+ */
79
+ ppr?: boolean | PartialPrerenderProps;
44
80
  /** Search param schema for typed query parameters */
45
81
  search?: TSearch;
46
82
  /** Trailing slash behavior: "never" (redirect /path/ to /path), "always" (redirect /path to /path/), "ignore" (match both) */
@@ -81,16 +81,26 @@ type ExtractRoutesFromItem<T> =
81
81
  // When search schema is non-empty, value becomes { path, search } object
82
82
  T extends TypedRouteItem<infer TName, infer TPattern, any, infer TSearch>
83
83
  ? TName extends string
84
- ? TName extends UnnamedRoute
85
- ? {} // Exclude unnamed routes from type map
86
- : {} extends TSearch
87
- ? { [K in TName]: TPattern }
88
- : {
89
- [K in TName]: {
90
- readonly path: TPattern;
91
- readonly search: TSearch;
92
- };
93
- }
84
+ ? // Widened-name guard (#642): some name-less call forms — notably the
85
+ // 3-arg children-fn overload path(pattern, component, () => [...]) —
86
+ // let TName infer to the bare `string` constraint instead of the
87
+ // UnnamedRoute sentinel, because the children-fn argument structurally
88
+ // satisfies the all-optional PathOptions<TName> union member. Mapping
89
+ // over a bare `string` key would emit `{ [K in string]: TPattern }`, an
90
+ // index signature that poisons the whole sibling map (Rango.Path
91
+ // collapses to never). Treat an unresolved name as unnamed.
92
+ string extends TName
93
+ ? {}
94
+ : TName extends UnnamedRoute
95
+ ? {} // Exclude unnamed routes from type map
96
+ : {} extends TSearch
97
+ ? { [K in TName]: TPattern }
98
+ : {
99
+ [K in TName]: {
100
+ readonly path: TPattern;
101
+ readonly search: TSearch;
102
+ };
103
+ }
94
104
  : {}
95
105
  : // TypedIncludeItem: extract prefixed routes (both name and URL prefix)
96
106
  T extends TypedIncludeItem<
@@ -128,9 +138,15 @@ type ExtractRoutesFromItems<T extends readonly any[]> = T extends readonly any[]
128
138
  ? UnionToIntersection<
129
139
  { [K in keyof T]: ExtractRoutesFromItem<T[K]> }[number]
130
140
  > extends infer R
131
- ? R extends Record<string, any>
132
- ? R
133
- : {}
141
+ ? // Blast-radius guard: never let a single malformed item collapse the
142
+ // whole map. A `never` intersection satisfies `extends Record<string,any>`
143
+ // (never extends everything), so check it explicitly first and fall back
144
+ // to `{}` rather than propagating `never`. See #642.
145
+ [R] extends [never]
146
+ ? {}
147
+ : R extends Record<string, any>
148
+ ? R
149
+ : {}
134
150
  : {}
135
151
  : {};
136
152
 
@@ -169,9 +185,15 @@ type PrefixKeys<
169
185
  type ExtractResponsesFromItem<T> =
170
186
  T extends TypedRouteItem<infer TName, any, infer TData>
171
187
  ? TName extends string
172
- ? TName extends UnnamedRoute
188
+ ? // Widened-name guard (#642), parallels ExtractRoutesFromItem. A name-less
189
+ // children-fn path.json(pattern, handler, () => [...]) infers TName as
190
+ // bare `string`; without this the response map picks up an index
191
+ // signature { [K in string]: TData } that wipes named siblings.
192
+ string extends TName
173
193
  ? {}
174
- : { [K in TName]: TData }
194
+ : TName extends UnnamedRoute
195
+ ? {}
196
+ : { [K in TName]: TData }
175
197
  : {}
176
198
  : T extends TypedIncludeItem<any, infer TNamePrefix, any, infer TResponses>
177
199
  ? TNamePrefix extends LocalOnlyInclude
@@ -206,9 +228,12 @@ type ExtractResponsesFromItems<T extends readonly any[]> =
206
228
  ? UnionToIntersection<
207
229
  { [K in keyof T]: ExtractResponsesFromItem<T[K]> }[number]
208
230
  > extends infer R
209
- ? R extends Record<string, unknown>
210
- ? R
211
- : {}
231
+ ? // Blast-radius guard (parallels ExtractRoutesFromItems). See #642.
232
+ [R] extends [never]
233
+ ? {}
234
+ : R extends Record<string, unknown>
235
+ ? R
236
+ : {}
212
237
  : {}
213
238
  : {};
214
239
 
@@ -220,44 +245,53 @@ export type ExtractResponses<T extends readonly any[]> =
220
245
  ExtractResponsesFromItems<T>;
221
246
 
222
247
  // ============================================================================
223
- // Response Envelope Types
248
+ // Response Error (RFC 9457 problem+json) Type
224
249
  // ============================================================================
225
250
 
226
251
  /**
227
- * Error shape returned in the `{ error }` side of a JSON response envelope.
228
- */
229
- export interface ResponseError {
230
- message: string;
231
- code?: string;
232
- type?: string;
233
- stack?: string;
234
- }
235
-
236
- /**
237
- * Discriminated union envelope for JSON response routes.
238
- * Consumers check `result.error` to discriminate between success and failure.
252
+ * RFC 9457 (problem+json) error body returned by JSON response routes on a
253
+ * non-2xx status. Sent verbatim as the response body (not wrapped) with
254
+ * content-type `application/problem+json`.
239
255
  *
240
256
  * @example
241
257
  * ```typescript
242
- * const result: ResponseEnvelope<Product> = await fetch(url).then(r => r.json());
243
- * if (result.error) {
244
- * console.log(result.error.message, result.error.code);
258
+ * const res = await fetch(url);
259
+ * if (!res.ok) {
260
+ * const problem: ProblemDetails = await res.json();
261
+ * console.log(problem.code, problem.detail); // "NOT_FOUND", "Product not found"
245
262
  * return;
246
263
  * }
247
- * result.data.name // fully typed
264
+ * const product = await res.json(); // bare value, no envelope
248
265
  * ```
249
266
  */
250
- export type ResponseEnvelope<T> =
251
- | { data: T; error?: undefined }
252
- | { data?: undefined; error: ResponseError };
267
+ export interface ProblemDetails {
268
+ /**
269
+ * URI reference identifying the problem type. Omitted in this phase (per RFC
270
+ * 9457 an absent `type` is treated as `"about:blank"` — no semantics beyond
271
+ * the HTTP status); per-route problem-type URIs arrive with the
272
+ * declared-errors map later.
273
+ */
274
+ type?: string;
275
+ /** Short, human-readable summary (the HTTP status reason phrase). */
276
+ title: string;
277
+ /** The HTTP status code. */
278
+ status: number;
279
+ /** Human-readable explanation specific to this occurrence (the error message). */
280
+ detail: string;
281
+ /** Stable machine-readable error code (`RouterError.code`, else `"INTERNAL"`). */
282
+ code: string;
283
+ /** Stack trace, included in development only. */
284
+ stack?: string;
285
+ }
253
286
 
254
287
  // ============================================================================
255
288
  // Response Type Consumer Utilities
256
289
  // ============================================================================
257
290
 
258
291
  /**
259
- * Extract the response data type for a named route from a UrlPatterns instance.
260
- * Wraps in ResponseEnvelope since JSON response routes return enveloped data.
292
+ * Extract the JSON response payload type for a named route from a UrlPatterns
293
+ * instance. JSON response routes send the handler's return value verbatim
294
+ * (bare), so this resolves to the wire value a consumer receives — no envelope.
261
295
  *
262
296
  * @example
263
297
  * ```typescript
@@ -266,7 +300,7 @@ export type ResponseEnvelope<T> =
266
300
  * ]);
267
301
  *
268
302
  * type HealthData = RouteResponse<typeof apiPatterns, "health">;
269
- * // ResponseEnvelope<{ status: string; timestamp: number }>
303
+ * // { status: string; timestamp: number }
270
304
  * ```
271
305
  *
272
306
  * The payload is the JSON wire shape (via `Rango.JsonSerialize`), matching
@@ -277,6 +311,6 @@ export type RouteResponse<TPatterns, TName extends string> = TPatterns extends {
277
311
  readonly _responses?: infer R;
278
312
  }
279
313
  ? TName extends keyof R
280
- ? ResponseEnvelope<JsonSerialize<Exclude<R[TName], Response>>>
314
+ ? JsonSerialize<Exclude<R[TName], Response>>
281
315
  : never
282
316
  : never;
@@ -34,24 +34,18 @@ export function urls<
34
34
  >(
35
35
  builder: (helpers: PathHelpers<TEnv>) => TItems,
36
36
  ): UrlPatterns<TEnv, ExtractRoutes<TItems>, ExtractResponses<TItems>> {
37
- // Create the handler function that will be called by the router
38
37
  const handler = () => {
39
38
  invariant(
40
39
  typeof builder === "function",
41
40
  "urls() expects a builder function as its argument",
42
41
  );
43
42
 
44
- // Get base helpers from the existing route-definition module
45
43
  const baseHelpers = createRouteHelpers<any, TEnv>();
46
44
 
47
- // Create the path helper (with .json, .text, .html, .xml, .image, .stream, .any tags)
48
45
  const pathHelper = attachPathResponseTags(createPathHelper<TEnv>());
49
46
 
50
- // Create the include helper
51
47
  const includeHelper = createIncludeHelper<TEnv>();
52
48
 
53
- // Combine all helpers
54
- // Note: layout and cache are cast to their typed versions - phantom types don't affect runtime
55
49
  const helpers: PathHelpers<TEnv> = {
56
50
  path: pathHelper as any,
57
51
  include: includeHelper as any,
@@ -64,25 +58,17 @@ export function urls<
64
58
  loading: baseHelpers.loading,
65
59
  errorBoundary: baseHelpers.errorBoundary,
66
60
  notFoundBoundary: baseHelpers.notFoundBoundary,
67
- when: baseHelpers.when,
68
61
  cache: baseHelpers.cache as PathHelpers<TEnv>["cache"],
69
62
  transition: baseHelpers.transition as PathHelpers<TEnv>["transition"],
70
63
  };
71
64
 
72
- // Execute builder directly - manifest.ts handles RootLayout wrapping
73
- // for inline handlers (non-Promise results).
74
- // For nested include() calls, routes inherit the outer RootLayout.
75
65
  const builderResult = builder(helpers).flat(3) as AllUseItems[];
76
66
  return processItems(builderResult);
77
67
  };
78
68
 
79
- // trailingSlash config is populated when handler() runs
80
- // We expose it via a getter that reads from the context after handler execution
81
69
  return {
82
70
  handler,
83
71
  get trailingSlash() {
84
- // Get the trailingSlash map from the current context
85
- // This will be populated after handler() is called
86
72
  const store = getContext();
87
73
  const ctx = store.context.getStore();
88
74
  if (!ctx?.trailingSlash) {