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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +245 -49
  3. package/dist/bin/rango.js +440 -133
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3373 -1176
  6. package/dist/vite/index.js.bak +5448 -0
  7. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  8. package/package.json +68 -14
  9. package/skills/api-client/SKILL.md +211 -0
  10. package/skills/breadcrumbs/SKILL.md +64 -2
  11. package/skills/bundle-analysis/SKILL.md +159 -0
  12. package/skills/cache-guide/SKILL.md +224 -32
  13. package/skills/caching/SKILL.md +279 -17
  14. package/skills/composability/SKILL.md +27 -3
  15. package/skills/css/SKILL.md +76 -0
  16. package/skills/debug-manifest/SKILL.md +4 -2
  17. package/skills/document-cache/SKILL.md +78 -55
  18. package/skills/handler-use/SKILL.md +364 -0
  19. package/skills/hooks/SKILL.md +250 -30
  20. package/skills/host-router/SKILL.md +83 -23
  21. package/skills/i18n/SKILL.md +276 -0
  22. package/skills/intercept/SKILL.md +87 -18
  23. package/skills/layout/SKILL.md +35 -9
  24. package/skills/links/SKILL.md +249 -17
  25. package/skills/loader/SKILL.md +235 -9
  26. package/skills/middleware/SKILL.md +52 -13
  27. package/skills/migrate-nextjs/SKILL.md +584 -0
  28. package/skills/migrate-react-router/SKILL.md +771 -0
  29. package/skills/mime-routes/SKILL.md +28 -1
  30. package/skills/observability/SKILL.md +172 -0
  31. package/skills/parallel/SKILL.md +77 -7
  32. package/skills/prerender/SKILL.md +172 -125
  33. package/skills/rango/SKILL.md +251 -22
  34. package/skills/react-compiler/SKILL.md +168 -0
  35. package/skills/response-routes/SKILL.md +123 -48
  36. package/skills/route/SKILL.md +70 -5
  37. package/skills/router-setup/SKILL.md +65 -8
  38. package/skills/scripts/SKILL.md +179 -0
  39. package/skills/server-actions/SKILL.md +775 -0
  40. package/skills/streams-and-websockets/SKILL.md +283 -0
  41. package/skills/tailwind/SKILL.md +27 -3
  42. package/skills/testing/SKILL.md +130 -0
  43. package/skills/testing/bindings.md +103 -0
  44. package/skills/testing/cache-prerender.md +127 -0
  45. package/skills/testing/client-components.md +124 -0
  46. package/skills/testing/e2e-parity.md +125 -0
  47. package/skills/testing/flight.md +91 -0
  48. package/skills/testing/handles.md +129 -0
  49. package/skills/testing/loader.md +128 -0
  50. package/skills/testing/middleware.md +99 -0
  51. package/skills/testing/render-handler.md +122 -0
  52. package/skills/testing/response-routes.md +95 -0
  53. package/skills/testing/reverse-and-types.md +84 -0
  54. package/skills/testing/server-actions.md +107 -0
  55. package/skills/testing/server-tree.md +128 -0
  56. package/skills/testing/setup.md +123 -0
  57. package/skills/typesafety/SKILL.md +322 -29
  58. package/skills/use-cache/SKILL.md +57 -14
  59. package/skills/view-transitions/SKILL.md +337 -0
  60. package/src/__augment-tests__/augment.ts +81 -0
  61. package/src/__augment-tests__/augmented.check.ts +116 -0
  62. package/src/__internal.ts +1 -66
  63. package/src/browser/action-coordinator.ts +53 -36
  64. package/src/browser/action-fence.ts +47 -0
  65. package/src/browser/app-shell.ts +39 -0
  66. package/src/browser/app-version.ts +14 -0
  67. package/src/browser/connection-warmup.ts +134 -0
  68. package/src/browser/cookie-name.ts +140 -0
  69. package/src/browser/event-controller.ts +192 -150
  70. package/src/browser/history-state.ts +21 -0
  71. package/src/browser/index.ts +3 -3
  72. package/src/browser/invalidate-client-cache.ts +52 -0
  73. package/src/browser/navigation-bridge.ts +131 -30
  74. package/src/browser/navigation-client.ts +186 -100
  75. package/src/browser/navigation-store-handle.ts +38 -0
  76. package/src/browser/navigation-store.ts +157 -74
  77. package/src/browser/navigation-transaction.ts +9 -59
  78. package/src/browser/network-error-handler.ts +34 -7
  79. package/src/browser/partial-update.ts +165 -112
  80. package/src/browser/prefetch/cache.ts +205 -62
  81. package/src/browser/prefetch/fetch.ts +347 -39
  82. package/src/browser/prefetch/queue.ts +42 -8
  83. package/src/browser/rango-state.ts +158 -76
  84. package/src/browser/react/Link.tsx +102 -15
  85. package/src/browser/react/NavigationProvider.tsx +295 -119
  86. package/src/browser/react/ScrollRestoration.tsx +10 -6
  87. package/src/browser/react/context.ts +7 -2
  88. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  89. package/src/browser/react/filter-segment-order.ts +66 -7
  90. package/src/browser/react/index.ts +0 -48
  91. package/src/browser/react/location-state-shared.ts +178 -8
  92. package/src/browser/react/location-state.ts +39 -14
  93. package/src/browser/react/use-action.ts +6 -15
  94. package/src/browser/react/use-handle.ts +23 -69
  95. package/src/browser/react/use-href.tsx +8 -1
  96. package/src/browser/react/use-link-status.ts +33 -8
  97. package/src/browser/react/use-navigation.ts +32 -7
  98. package/src/browser/react/use-params.ts +20 -10
  99. package/src/browser/react/use-reverse.ts +106 -0
  100. package/src/browser/react/use-router.ts +46 -11
  101. package/src/browser/react/use-search-params.ts +0 -5
  102. package/src/browser/react/use-segments.ts +11 -21
  103. package/src/browser/response-adapter.ts +99 -8
  104. package/src/browser/rsc-router.tsx +114 -24
  105. package/src/browser/scroll-restoration.ts +37 -22
  106. package/src/browser/segment-reconciler.ts +36 -14
  107. package/src/browser/segment-structure-assert.ts +2 -2
  108. package/src/browser/server-action-bridge.ts +222 -72
  109. package/src/browser/types.ts +102 -12
  110. package/src/browser/validate-redirect-origin.ts +43 -16
  111. package/src/build/collect-fallback-refs.ts +107 -0
  112. package/src/build/generate-manifest.ts +65 -40
  113. package/src/build/generate-route-types.ts +5 -1
  114. package/src/build/index.ts +8 -2
  115. package/src/build/prefix-tree-utils.ts +123 -0
  116. package/src/build/route-trie.ts +165 -36
  117. package/src/build/route-types/ast-route-extraction.ts +15 -8
  118. package/src/build/route-types/codegen.ts +16 -5
  119. package/src/build/route-types/include-resolution.ts +125 -24
  120. package/src/build/route-types/param-extraction.ts +6 -3
  121. package/src/build/route-types/per-module-writer.ts +22 -6
  122. package/src/build/route-types/router-processing.ts +260 -94
  123. package/src/build/route-types/scan-filter.ts +9 -2
  124. package/src/build/route-types/source-scan.ts +216 -0
  125. package/src/build/runtime-discovery.ts +9 -20
  126. package/src/cache/cache-error.ts +104 -0
  127. package/src/cache/cache-key-utils.ts +29 -13
  128. package/src/cache/cache-policy.ts +108 -34
  129. package/src/cache/cache-runtime.ts +224 -41
  130. package/src/cache/cache-scope.ts +188 -82
  131. package/src/cache/cache-tag.ts +103 -0
  132. package/src/cache/cf/cf-base64.ts +33 -0
  133. package/src/cache/cf/cf-cache-constants.ts +127 -0
  134. package/src/cache/cf/cf-cache-store.ts +1989 -378
  135. package/src/cache/cf/cf-cache-types.ts +349 -0
  136. package/src/cache/cf/cf-kv-utils.ts +46 -0
  137. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  138. package/src/cache/cf/index.ts +6 -16
  139. package/src/cache/document-cache.ts +89 -21
  140. package/src/cache/handle-snapshot.ts +70 -0
  141. package/src/cache/index.ts +10 -20
  142. package/src/cache/memory-segment-store.ts +136 -37
  143. package/src/cache/profile-registry.ts +46 -31
  144. package/src/cache/read-through-swr.ts +56 -12
  145. package/src/cache/segment-codec.ts +9 -17
  146. package/src/cache/tag-invalidation.ts +230 -0
  147. package/src/cache/types.ts +37 -100
  148. package/src/client.rsc.tsx +44 -21
  149. package/src/client.tsx +119 -290
  150. package/src/cloudflare/index.ts +11 -0
  151. package/src/cloudflare/tracing.ts +109 -0
  152. package/src/component-utils.ts +19 -0
  153. package/src/components/DefaultDocument.tsx +8 -2
  154. package/src/context-var.ts +18 -6
  155. package/src/decode-loader-results.ts +52 -0
  156. package/src/defer.ts +196 -0
  157. package/src/deps/ssr.ts +0 -1
  158. package/src/encode-kv.ts +49 -0
  159. package/src/errors.ts +30 -4
  160. package/src/escape-script.ts +52 -0
  161. package/src/handle.ts +70 -22
  162. package/src/handles/MetaTags.tsx +62 -19
  163. package/src/handles/Scripts.tsx +183 -0
  164. package/src/handles/breadcrumbs.ts +37 -8
  165. package/src/handles/is-thenable.ts +19 -0
  166. package/src/handles/meta.ts +51 -40
  167. package/src/handles/script.ts +244 -0
  168. package/src/host/cookie-handler.ts +9 -60
  169. package/src/host/errors.ts +0 -24
  170. package/src/host/index.ts +8 -2
  171. package/src/host/pattern-matcher.ts +23 -52
  172. package/src/host/router.ts +107 -99
  173. package/src/host/testing.ts +40 -27
  174. package/src/host/types.ts +37 -4
  175. package/src/host/utils.ts +1 -1
  176. package/src/href-client.ts +137 -22
  177. package/src/index.rsc.ts +99 -13
  178. package/src/index.ts +139 -19
  179. package/src/internal-debug.ts +11 -10
  180. package/src/loader-store.ts +500 -0
  181. package/src/loader.rsc.ts +20 -13
  182. package/src/loader.ts +12 -11
  183. package/src/missing-id-error.ts +68 -0
  184. package/src/outlet-context.ts +1 -1
  185. package/src/outlet-provider.tsx +1 -5
  186. package/src/prerender/param-hash.ts +16 -16
  187. package/src/prerender/store.ts +37 -41
  188. package/src/prerender.ts +198 -82
  189. package/src/redirect-origin.ts +100 -0
  190. package/src/regex-escape.ts +8 -0
  191. package/src/render-error-thrower.tsx +20 -0
  192. package/src/response-utils.ts +62 -0
  193. package/src/reverse.ts +65 -15
  194. package/src/root-error-boundary.tsx +1 -19
  195. package/src/route-content-wrapper.tsx +19 -77
  196. package/src/route-definition/dsl-helpers.ts +461 -304
  197. package/src/route-definition/helper-factories.ts +28 -140
  198. package/src/route-definition/helpers-types.ts +143 -69
  199. package/src/route-definition/index.ts +4 -2
  200. package/src/route-definition/redirect.ts +51 -10
  201. package/src/route-definition/resolve-handler-use.ts +160 -0
  202. package/src/route-definition/use-item-types.ts +29 -0
  203. package/src/route-map-builder.ts +0 -16
  204. package/src/route-types.ts +37 -46
  205. package/src/router/basename.ts +14 -0
  206. package/src/router/content-negotiation.ts +164 -17
  207. package/src/router/error-handling.ts +45 -18
  208. package/src/router/find-match.ts +44 -23
  209. package/src/router/handler-context.ts +52 -31
  210. package/src/router/instrument.ts +350 -0
  211. package/src/router/intercept-resolution.ts +48 -24
  212. package/src/router/lazy-includes.ts +15 -52
  213. package/src/router/loader-resolution.ts +268 -56
  214. package/src/router/logging.ts +0 -6
  215. package/src/router/manifest.ts +40 -42
  216. package/src/router/match-api.ts +124 -204
  217. package/src/router/match-context.ts +0 -22
  218. package/src/router/match-handlers.ts +58 -58
  219. package/src/router/match-middleware/background-revalidation.ts +40 -24
  220. package/src/router/match-middleware/cache-lookup.ts +170 -276
  221. package/src/router/match-middleware/cache-store.ts +64 -52
  222. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  223. package/src/router/match-middleware/segment-resolution.ts +45 -14
  224. package/src/router/match-pipelines.ts +1 -42
  225. package/src/router/match-result.ts +87 -39
  226. package/src/router/metrics.ts +0 -34
  227. package/src/router/middleware-types.ts +7 -140
  228. package/src/router/middleware.ts +266 -169
  229. package/src/router/navigation-snapshot.ts +131 -0
  230. package/src/router/params-util.ts +23 -0
  231. package/src/router/pattern-matching.ts +132 -90
  232. package/src/router/prefetch-cache-ttl.ts +51 -0
  233. package/src/router/prerender-match.ts +195 -56
  234. package/src/router/preview-match.ts +32 -102
  235. package/src/router/request-classification.ts +276 -0
  236. package/src/router/revalidation.ts +123 -73
  237. package/src/router/route-snapshot.ts +244 -0
  238. package/src/router/router-context.ts +3 -28
  239. package/src/router/router-interfaces.ts +115 -35
  240. package/src/router/router-options.ts +172 -15
  241. package/src/router/router-registry.ts +2 -5
  242. package/src/router/segment-resolution/fresh.ts +162 -84
  243. package/src/router/segment-resolution/helpers.ts +86 -6
  244. package/src/router/segment-resolution/loader-cache.ts +76 -39
  245. package/src/router/segment-resolution/revalidation.ts +351 -321
  246. package/src/router/segment-resolution/static-store.ts +19 -5
  247. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  248. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  249. package/src/router/segment-resolution.ts +5 -1
  250. package/src/router/segment-wrappers.ts +6 -5
  251. package/src/router/state-cookie-name.ts +33 -0
  252. package/src/router/substitute-pattern-params.ts +56 -0
  253. package/src/router/telemetry-otel.ts +161 -199
  254. package/src/router/telemetry.ts +96 -19
  255. package/src/router/timeout.ts +0 -20
  256. package/src/router/tracing.ts +206 -0
  257. package/src/router/trie-matching.ts +163 -59
  258. package/src/router/types.ts +9 -63
  259. package/src/router/url-params.ts +44 -0
  260. package/src/router.ts +157 -54
  261. package/src/rsc/handler-context.ts +3 -2
  262. package/src/rsc/handler.ts +655 -529
  263. package/src/rsc/helpers.ts +168 -46
  264. package/src/rsc/index.ts +2 -5
  265. package/src/rsc/json-route-result.ts +38 -0
  266. package/src/rsc/loader-fetch.ts +122 -31
  267. package/src/rsc/manifest-init.ts +33 -42
  268. package/src/rsc/origin-guard.ts +39 -25
  269. package/src/rsc/progressive-enhancement.ts +131 -14
  270. package/src/rsc/redirect-guard.ts +99 -0
  271. package/src/rsc/response-cache-serve.ts +238 -0
  272. package/src/rsc/response-error.ts +79 -12
  273. package/src/rsc/response-route-handler.ts +99 -189
  274. package/src/rsc/rsc-rendering.ts +109 -74
  275. package/src/rsc/runtime-warnings.ts +23 -10
  276. package/src/rsc/server-action.ts +287 -115
  277. package/src/rsc/ssr-setup.ts +18 -2
  278. package/src/rsc/transition-gate.ts +89 -0
  279. package/src/rsc/types.ts +29 -9
  280. package/src/runtime-env.ts +18 -0
  281. package/src/search-params.ts +35 -30
  282. package/src/segment-content-promise.ts +67 -0
  283. package/src/segment-loader-promise.ts +149 -0
  284. package/src/segment-system.tsx +236 -202
  285. package/src/serialize.ts +243 -0
  286. package/src/server/context.ts +224 -52
  287. package/src/server/cookie-parse.ts +32 -0
  288. package/src/server/cookie-store.ts +80 -5
  289. package/src/server/handle-store.ts +40 -38
  290. package/src/server/loader-registry.ts +38 -46
  291. package/src/server/request-context.ts +401 -173
  292. package/src/ssr/index.tsx +24 -16
  293. package/src/static-handler.ts +27 -18
  294. package/src/testing/cache-status.ts +162 -0
  295. package/src/testing/collect-handle.ts +40 -0
  296. package/src/testing/dispatch.ts +701 -0
  297. package/src/testing/dom.entry.ts +22 -0
  298. package/src/testing/e2e/fixture.ts +188 -0
  299. package/src/testing/e2e/index.ts +128 -0
  300. package/src/testing/e2e/matchers.ts +35 -0
  301. package/src/testing/e2e/page-helpers.ts +272 -0
  302. package/src/testing/e2e/parity.ts +387 -0
  303. package/src/testing/e2e/server.ts +195 -0
  304. package/src/testing/flight-matchers.ts +97 -0
  305. package/src/testing/flight-normalize.ts +11 -0
  306. package/src/testing/flight-runtime.d.ts +57 -0
  307. package/src/testing/flight-tree.ts +682 -0
  308. package/src/testing/flight.entry.ts +52 -0
  309. package/src/testing/flight.ts +257 -0
  310. package/src/testing/generated-routes.ts +183 -0
  311. package/src/testing/index.ts +105 -0
  312. package/src/testing/internal/context.ts +371 -0
  313. package/src/testing/internal/flight-client-globals.ts +30 -0
  314. package/src/testing/internal/seed-vars.ts +54 -0
  315. package/src/testing/render-handler.ts +357 -0
  316. package/src/testing/render-route.tsx +581 -0
  317. package/src/testing/run-loader.ts +385 -0
  318. package/src/testing/run-middleware.ts +205 -0
  319. package/src/testing/run-transition-when.ts +164 -0
  320. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  321. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  322. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  323. package/src/testing/vitest-stubs/version.ts +5 -0
  324. package/src/testing/vitest.ts +305 -0
  325. package/src/theme/ThemeProvider.tsx +20 -58
  326. package/src/theme/ThemeScript.tsx +7 -9
  327. package/src/theme/constants.ts +52 -13
  328. package/src/theme/index.ts +0 -7
  329. package/src/theme/theme-context.ts +1 -5
  330. package/src/theme/theme-script.ts +22 -21
  331. package/src/theme/use-theme.ts +0 -3
  332. package/src/types/boundaries.ts +0 -35
  333. package/src/types/cache-types.ts +17 -8
  334. package/src/types/error-types.ts +30 -90
  335. package/src/types/global-namespace.ts +54 -41
  336. package/src/types/handler-context.ts +125 -71
  337. package/src/types/index.ts +3 -10
  338. package/src/types/loader-types.ts +40 -11
  339. package/src/types/request-scope.ts +112 -0
  340. package/src/types/route-config.ts +6 -50
  341. package/src/types/route-entry.ts +12 -7
  342. package/src/types/segments.ts +136 -15
  343. package/src/urls/include-helper.ts +33 -70
  344. package/src/urls/index.ts +1 -11
  345. package/src/urls/path-helper-types.ts +68 -18
  346. package/src/urls/path-helper.ts +57 -111
  347. package/src/urls/pattern-types.ts +48 -19
  348. package/src/urls/response-types.ts +25 -22
  349. package/src/urls/type-extraction.ts +58 -139
  350. package/src/urls/urls-function.ts +1 -19
  351. package/src/use-loader.tsx +346 -89
  352. package/src/vite/debug.ts +185 -0
  353. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  354. package/src/vite/discovery/discover-routers.ts +130 -85
  355. package/src/vite/discovery/discovery-errors.ts +194 -0
  356. package/src/vite/discovery/gate-state.ts +171 -0
  357. package/src/vite/discovery/prerender-collection.ts +214 -132
  358. package/src/vite/discovery/route-types-writer.ts +40 -84
  359. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  360. package/src/vite/discovery/state.ts +57 -4
  361. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  362. package/src/vite/index.ts +6 -0
  363. package/src/vite/inject-client-debug.ts +36 -0
  364. package/src/vite/plugin-types.ts +178 -5
  365. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  366. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  367. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  368. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  369. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  370. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  371. package/src/vite/plugins/expose-action-id.ts +48 -95
  372. package/src/vite/plugins/expose-id-utils.ts +96 -51
  373. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  374. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  375. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  376. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  377. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  378. package/src/vite/plugins/performance-tracks.ts +64 -170
  379. package/src/vite/plugins/refresh-cmd.ts +89 -27
  380. package/src/vite/plugins/use-cache-transform.ts +73 -83
  381. package/src/vite/plugins/version-injector.ts +40 -29
  382. package/src/vite/plugins/version-plugin.ts +37 -40
  383. package/src/vite/plugins/virtual-entries.ts +39 -25
  384. package/src/vite/rango.ts +118 -114
  385. package/src/vite/router-discovery.ts +941 -142
  386. package/src/vite/utils/ast-handler-extract.ts +26 -35
  387. package/src/vite/utils/banner.ts +1 -1
  388. package/src/vite/utils/bundle-analysis.ts +10 -15
  389. package/src/vite/utils/client-chunks.ts +184 -0
  390. package/src/vite/utils/directive-prologue.ts +40 -0
  391. package/src/vite/utils/forward-user-plugins.ts +171 -0
  392. package/src/vite/utils/manifest-utils.ts +4 -59
  393. package/src/vite/utils/package-resolution.ts +20 -52
  394. package/src/vite/utils/prerender-utils.ts +81 -34
  395. package/src/vite/utils/shared-utils.ts +92 -42
  396. package/src/browser/action-response-classifier.ts +0 -99
  397. package/src/browser/debug-channel.ts +0 -93
  398. package/src/browser/react/use-client-cache.ts +0 -58
  399. package/src/browser/shallow.ts +0 -40
  400. package/src/handles/index.ts +0 -7
  401. package/src/network-error-thrower.tsx +0 -23
  402. package/src/router/middleware-cookies.ts +0 -55
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { Handle } from "../handle.js";
3
+ import type { HandlePush } from "../defer.js";
3
4
  import type { ContextVar } from "../context-var.js";
4
5
  import type { MiddlewareFn } from "../router/middleware.js";
5
6
  import type { Theme } from "../theme/types.js";
@@ -19,6 +20,8 @@ import type {
19
20
  ResolvedRouteMap,
20
21
  } from "./route-config.js";
21
22
  import type { LoaderDefinition } from "./loader-types.js";
23
+ import type { UseItems, HandlerUseItem } from "../route-types.js";
24
+ import type { RequestScope } from "./request-scope.js";
22
25
 
23
26
  // Re-export MiddlewareFn for internal/advanced use
24
27
  export type { MiddlewareFn } from "../router/middleware.js";
@@ -41,7 +44,7 @@ export type { MiddlewareFn } from "../router/middleware.js";
41
44
  */
42
45
  export type ScopedRouteMap<
43
46
  TPrefix extends string,
44
- TMap = RSCRouter.GeneratedRouteMap,
47
+ TMap = Rango.GeneratedRouteMap,
45
48
  > = {
46
49
  [K in keyof TMap as K extends `${TPrefix}.${infer Rest}`
47
50
  ? Rest
@@ -105,14 +108,6 @@ type StrictLocalParamsWithExtras<TEntry> =
105
108
  ? Record<string, string>
106
109
  : ExtractParamsFromEntry<TEntry, {}> & Record<string, string>;
107
110
 
108
- // HandlerContext.reverse is the only reverse surface with runtime param autofill
109
- // from the current matched request. Middleware/loaders/request context do not
110
- // have the same local-route guarantees, so they keep plain ScopedReverseFunction.
111
- //
112
- // When a handler has an explicit local route map, enforce that local route
113
- // params declared by that map are present while still allowing extra mount
114
- // params to be passed through. Global names remain autofill-friendly because
115
- // parent include() params are often unknown at the module definition site.
116
111
  type StrictLocalAutofillGlobalReverseFunction<TLocalRoutes, TGlobalRoutes> =
117
112
  ScopedReverseFunction<TLocalRoutes, TGlobalRoutes> & {
118
113
  <TName extends keyof TGlobalRoutes & string>(
@@ -135,7 +130,7 @@ export type Handler<
135
130
  | Record<string, any> = {},
136
131
  TRouteMap extends {} = DefaultHandlerRouteMap,
137
132
  TEnv = DefaultEnv,
138
- > = (
133
+ > = ((
139
134
  ctx: HandlerContext<
140
135
  T extends `.${infer Local}`
141
136
  ? Local extends keyof TRouteMap
@@ -160,7 +155,10 @@ export type Handler<
160
155
  : ExtractSearchFromEntry<DefaultHandlerRouteMap, T>,
161
156
  TRouteMap extends DefaultHandlerRouteMap ? never : TRouteMap
162
157
  >,
163
- ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>;
158
+ ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>) & {
159
+ /** Composable default DSL items merged when the handler is mounted. */
160
+ use?: () => UseItems<HandlerUseItem>;
161
+ };
164
162
 
165
163
  /**
166
164
  * Context passed to handlers (Hono-inspired type-safe context)
@@ -170,7 +168,7 @@ export type Handler<
170
168
  * - Cleaned route URL (`url`, `searchParams`, `pathname` — no `_rsc*` params)
171
169
  * - Original request (`request` — raw transport URL, headers, method, body)
172
170
  * - Platform bindings (env.DB, env.KV, env.SECRETS)
173
- * - Middleware variables (var.user, var.permissions)
171
+ * - Middleware variables (`get("user")`, `get("permissions")`)
174
172
  * - Getter/setter for variables (get('user'), set('user', ...))
175
173
  *
176
174
  * @example
@@ -178,8 +176,7 @@ export type Handler<
178
176
  * const handler = (ctx: HandlerContext<{ slug: string }, AppEnv>) => {
179
177
  * ctx.params.slug // Route param (string)
180
178
  * ctx.env.DB // Binding (D1Database)
181
- * ctx.var.user // Variable (User | undefined)
182
- * ctx.get('user') // Alternative getter
179
+ * ctx.get('user') // Variable (User | undefined)
183
180
  * ctx.set('user', {...}) // Setter
184
181
  * ctx.url // Clean URL (no _rsc* params)
185
182
  * ctx.searchParams // Clean params (no _rsc* params)
@@ -192,7 +189,7 @@ export type HandlerContext<
192
189
  TEnv = DefaultEnv,
193
190
  TSearch extends SearchSchema = {},
194
191
  TRouteMap = never,
195
- > = {
192
+ > = RequestScope<TEnv> & {
196
193
  /**
197
194
  * Route parameters extracted from the URL pattern.
198
195
  * Type-safe when using Handler<"/path/:param"> or Handler<{ param: string }>.
@@ -207,51 +204,19 @@ export type HandlerContext<
207
204
  */
208
205
  build: boolean;
209
206
  /**
210
- * The original incoming Request object (transport URL intact).
211
- * Use `ctx.url` / `ctx.searchParams` for application logic those have
212
- * internal `_rsc*` params stripped. `ctx.request` preserves the raw URL
213
- * for cases where you need original headers, method, or body.
207
+ * True when running in Vite dev mode, false during production build or
208
+ * live request rendering. Use this to branch on runtime mode without
209
+ * changing build semantics (e.g., skip expensive operations in dev).
214
210
  */
215
- request: Request;
216
- /**
217
- * Query parameters from the URL (system params like `_rsc*` are filtered).
218
- * Always a standard URLSearchParams instance.
219
- */
220
- searchParams: URLSearchParams;
211
+ dev: boolean;
221
212
  /**
222
213
  * Typed search parameters parsed from URL query string via the route's
223
214
  * search schema. Empty object when no schema is defined.
224
215
  */
225
216
  search: {} extends TSearch ? {} : ResolveSearchSchema<TSearch>;
226
- /**
227
- * The pathname portion of the request URL.
228
- */
229
- pathname: string;
230
- /**
231
- * The full URL object (with internal `_rsc*` params stripped).
232
- * Use this for application logic — routing, link generation, display.
233
- */
234
- url: URL;
235
- /**
236
- * The original request URL with all parameters intact, including
237
- * internal `_rsc*` transport params. Use `ctx.url` for application
238
- * logic — this is only needed for advanced cases like debugging
239
- * or custom cache keying.
240
- */
241
- originalUrl: URL;
242
- /**
243
- * Platform bindings (DB, KV, secrets, etc.).
244
- * Access resources like `ctx.env.DB`, `ctx.env.KV`.
245
- */
246
- env: TEnv;
247
- /**
248
- * Middleware-injected variables.
249
- * Access values like `ctx.var.user`, `ctx.var.permissions`.
250
- */
251
- var: DefaultVars;
252
217
  /**
253
218
  * Type-safe getter for middleware variables.
254
- * Alternative to `ctx.var.key` with better autocomplete.
219
+ * Preferred way to read middleware-injected variables.
255
220
  *
256
221
  * @example
257
222
  * ```typescript
@@ -310,6 +275,8 @@ export type HandlerContext<
310
275
  * For handles: Returns a push function to add data for this segment.
311
276
  * Handle data accumulates across all matched route segments.
312
277
  * Push accepts: direct value, Promise, or async callback (executed immediately).
278
+ * Or call `.defer()` to reserve the slot now and resolve it later (e.g. from a
279
+ * deep async component), with a timeout safety net — see {@link HandlePush}.
313
280
  *
314
281
  * @example
315
282
  * ```typescript
@@ -343,6 +310,13 @@ export type HandlerContext<
343
310
  * });
344
311
  * return <ProductPage />;
345
312
  * });
313
+ *
314
+ * // Handle usage - deferred (reserve the slot now, resolve from a deep component)
315
+ * route("product", (ctx) => {
316
+ * const resolve = ctx.use(Breadcrumbs).defer({ timeoutMs: 5000, else: null });
317
+ * loadCrumb(ctx.params.id).then(resolve); // resolver is push-equal
318
+ * return <ProductPage />; // auto-resolves to `else` on timeout
319
+ * });
346
320
  * ```
347
321
  */
348
322
  use: {
@@ -351,7 +325,7 @@ export type HandlerContext<
351
325
  ): Promise<T>;
352
326
  <TData, TAccumulated = TData[]>(
353
327
  handle: Handle<TData, TAccumulated>,
354
- ): (data: TData | Promise<TData> | (() => Promise<TData>)) => void;
328
+ ): HandlePush<TData>;
355
329
  };
356
330
  /**
357
331
  * Current theme (from cookie or default).
@@ -448,6 +422,8 @@ export type InternalHandlerContext<
448
422
  > = HandlerContext<TParams, TEnv, TSearch> & {
449
423
  /** @internal Stub response for collecting headers/cookies. */
450
424
  res: Response;
425
+ /** @internal Shared variable backing store for ctx.get()/ctx.set(). */
426
+ _variables: Record<string, any>;
451
427
  /** Prerender-only control flow helper, attached when the runtime context supports it. */
452
428
  passthrough?: () => unknown;
453
429
  /** Current segment ID for handle data attribution. */
@@ -456,6 +432,18 @@ export type InternalHandlerContext<
456
432
  _responseType?: string;
457
433
  /** Route name for cache key scoping (prevents cross-route collisions). */
458
434
  _routeName?: string;
435
+ /**
436
+ * @internal Loader-cache override table: loaderId -> memoized data promise.
437
+ * A single stable ctx.use interceptor consults this instead of chaining one
438
+ * wrapper per cached loader (avoids O(N) dispatch). See loader-cache.ts.
439
+ */
440
+ _loaderCacheOverrides?: Map<string, Promise<any>>;
441
+ /**
442
+ * @internal ctx.use captured before the loader-cache interceptor was installed.
443
+ * The cache-miss execute runs the loader through this, bypassing the override
444
+ * table (so a loader cannot await its own in-flight memoized promise).
445
+ */
446
+ _loaderCacheOriginalUse?: (item: any) => any;
459
447
  };
460
448
 
461
449
  /**
@@ -497,13 +485,16 @@ export type RevalidateParams<TParams = GenericParams, TEnv = any> = Parameters<
497
485
  * **Return Types:**
498
486
  * - `boolean` - Hard decision: immediately returns this value (short-circuits)
499
487
  * - `{ defaultShouldRevalidate: boolean }` - Soft decision: updates suggestion for next revalidator
488
+ * - `void` / `null` / `undefined` - Defer to the current suggestion (no opinion); the
489
+ * loop continues to the next revalidator without changing the running default
500
490
  *
501
491
  * **Execution Flow:**
502
492
  * 1. Start with built-in `defaultShouldRevalidate` (true if params changed)
503
493
  * 2. Execute global revalidators first, then route-specific
504
494
  * 3. Hard decision (boolean): stop immediately and use that value
505
495
  * 4. Soft decision (object): update suggestion and continue to next revalidator
506
- * 5. If all return soft decisions: use the final suggestion
496
+ * 5. Defer (`void` / `null` / `undefined`): leave suggestion unchanged and continue
497
+ * 6. If no hard decision was returned: use the final running suggestion
507
498
  *
508
499
  * @param args.currentParams - Previous route params (generic by default, can be narrowed)
509
500
  * @param args.currentUrl - Previous URL
@@ -513,9 +504,10 @@ export type RevalidateParams<TParams = GenericParams, TEnv = any> = Parameters<
513
504
  * @param args.context - App context (db, user, etc.)
514
505
  * @param args.actionResult - Result from action (future support)
515
506
  * @param args.formData - Form data from action (future support)
516
- * @param args.formMethod - HTTP method from action (future support)
507
+ * @param args.method - HTTP method: "GET" for navigation, "POST" for server actions
517
508
  *
518
- * @returns Hard decision (boolean) or soft suggestion (object)
509
+ * @returns Hard decision (boolean), soft suggestion (object), or defer
510
+ * (`void` / `null` / `undefined`) to keep the running suggestion as-is.
519
511
  *
520
512
  * @example
521
513
  * ```typescript
@@ -535,20 +527,46 @@ export type RevalidateParams<TParams = GenericParams, TEnv = any> = Parameters<
535
527
  * })
536
528
  * ```
537
529
  */
530
+ /**
531
+ * A reference to a server action, used by `isAction()` in a revalidate predicate.
532
+ *
533
+ * Either a directly imported action (`import { addToCart }`) or a namespace
534
+ * import of an action module (`import * as CartActions`). Matching resolves the
535
+ * action's build-injected id (`path#export`) — the same identity the router uses
536
+ * for `actionId` — so a renamed or moved action breaks at compile time instead
537
+ * of silently failing to match.
538
+ */
539
+ export type ActionRef =
540
+ | ((...args: never[]) => unknown)
541
+ | Record<string, unknown>;
542
+
538
543
  /**
539
544
  * Revalidation function called during client-side navigation to decide whether
540
545
  * a segment (layout, route, parallel slot, or loader) should be re-rendered.
541
546
  *
542
547
  * Return `true` to re-render, `false` to skip (keep client's current version),
543
- * or `{ defaultShouldRevalidate: boolean }` to override the default for
544
- * downstream segments.
548
+ * `{ defaultShouldRevalidate: boolean }` to update the running suggestion for
549
+ * downstream revalidators, or nothing (`void` / `null` / `undefined`) to defer
550
+ * to the current suggestion without changing it.
551
+ *
552
+ * Two idioms cover almost every case; they differ only in what an _unrelated_
553
+ * action does. Match actions by reference with `ctx.isAction()` (rename-safe)
554
+ * rather than `actionId?.includes("...")` (a renamed or moved action silently
555
+ * stops matching). Because `isAction` returns a raw boolean, combine it with
556
+ * `|| undefined` to defer or leave it bare to suppress.
545
557
  *
546
558
  * @example
547
559
  * ```ts
548
- * // Re-render only when a cart action happened or browser signals staleness
549
- * revalidate(({ actionId, stale }) =>
550
- * actionId?.includes("cart") || stale || false
551
- * )
560
+ * import * as CartActions from "./actions/cart";
561
+ *
562
+ * // Idiom A — "mine, else defer": re-render on my actions, otherwise return
563
+ * // undefined so the segment's default decision still applies (and downstream
564
+ * // revalidators get a say).
565
+ * revalidate((ctx) => ctx.isAction(CartActions) || undefined)
566
+ *
567
+ * // Idiom B — "mine only": re-render on my actions and suppress everything
568
+ * // else (isAction returns a raw boolean, so an unrelated action yields false).
569
+ * revalidate((ctx) => ctx.isAction(CartActions))
552
570
  *
553
571
  * // Always re-render when params change (default behavior made explicit)
554
572
  * revalidate(({ defaultShouldRevalidate }) => defaultShouldRevalidate)
@@ -574,8 +592,11 @@ export type ShouldRevalidateFn<TParams = GenericParams, TEnv = any> = (args: {
574
592
 
575
593
  // ── Segment metadata (which segment is being evaluated) ──────────────
576
594
 
577
- /** The type of segment being revalidated. */
578
- segmentType: "layout" | "route" | "parallel";
595
+ /**
596
+ * The type of segment being revalidated. `"loader"` is passed to revalidate
597
+ * functions attached to a `loader(Fn, () => [revalidate(...)])` registration.
598
+ */
599
+ segmentType: "layout" | "route" | "parallel" | "loader";
579
600
  /** Layout name (e.g., `"root"`, `"shop"`, `"auth"`). Only set for layout segments. */
580
601
  layoutName?: string;
581
602
  /** Slot name (e.g., `"@sidebar"`, `"@modal"`). Only set for parallel segments. */
@@ -591,21 +612,54 @@ export type ShouldRevalidateFn<TParams = GenericParams, TEnv = any> = (args: {
591
612
  * relative to the project root, followed by `#` and the exported function name.
592
613
  *
593
614
  * This is stable and can be used for path-based matching to revalidate
594
- * when any action in a module or directory fires:
615
+ * when any action in a module or directory fires. Prefer `|| undefined`
616
+ * (defer to the segment default / downstream revalidators) over `?? false`
617
+ * (hard short-circuit that suppresses the default and ends the chain):
595
618
  *
596
619
  * @example
597
620
  * ```ts
598
621
  * // Match a specific action
599
- * revalidate(({ actionId }) => actionId === "src/actions/cart.ts#addToCart")
622
+ * revalidate(({ actionId }) => actionId === "src/actions/cart.ts#addToCart" || undefined)
600
623
  *
601
624
  * // Match any action in the cart module
602
- * revalidate(({ actionId }) => actionId?.includes("cart") ?? false)
625
+ * revalidate(({ actionId }) => actionId?.includes("cart") || undefined)
603
626
  *
604
627
  * // Match any action under src/apps/store/actions/
605
- * revalidate(({ actionId }) => actionId?.startsWith("src/apps/store/actions/") ?? false)
628
+ * revalidate(({ actionId }) => actionId?.startsWith("src/apps/store/actions/") || undefined)
606
629
  * ```
607
630
  */
608
631
  actionId?: string;
632
+ /**
633
+ * Typed, rename-safe action matching. Returns `true` when the action that
634
+ * triggered this revalidation is one of the given references — or, for a
635
+ * namespace import (`import * as CartActions`), any export of that module —
636
+ * and `false` otherwise (including plain navigation with no action).
637
+ *
638
+ * Called with NO arguments it answers "is this request an action at all?":
639
+ * `true` for any action, `false` on plain navigation. Use the bare form when
640
+ * you want to revalidate on every action regardless of which one fired.
641
+ *
642
+ * Prefer this over hand-written `actionId` substring matches: it resolves the
643
+ * action's stable `path#export` id from the imported reference, so a rename is
644
+ * a type error in one place instead of silent drift across consumers. It
645
+ * resolves the reference the same way the action boundary derives `actionId`
646
+ * (`$id ?? $$id`), so it matches in both dev and production.
647
+ *
648
+ * Returns a raw boolean, so for the common "revalidate on match, else defer"
649
+ * intent combine with `|| undefined`:
650
+ *
651
+ * @example
652
+ * ```ts
653
+ * import { addToCart, removeFromCart } from "./actions/cart";
654
+ * import * as CartActions from "./actions/cart";
655
+ *
656
+ * revalidate((ctx) => ctx.isAction() || undefined); // any action
657
+ * revalidate((ctx) => ctx.isAction(addToCart) || undefined); // one action
658
+ * revalidate((ctx) => ctx.isAction(addToCart, removeFromCart) || undefined); // several
659
+ * revalidate((ctx) => ctx.isAction(CartActions) || undefined); // any in the module
660
+ * ```
661
+ */
662
+ isAction: (...actions: ActionRef[]) => boolean;
609
663
  /** URL where the action was executed (the page the user was on when they triggered the action). */
610
664
  actionUrl?: URL;
611
665
  /** Return value from the action execution. Can be used to conditionally revalidate based on the action's outcome. */
@@ -641,7 +695,7 @@ export type ShouldRevalidateFn<TParams = GenericParams, TEnv = any> = (args: {
641
695
  * action that may have mutated backend state.
642
696
  */
643
697
  stale?: boolean;
644
- }) => boolean | { defaultShouldRevalidate: boolean };
698
+ }) => boolean | { defaultShouldRevalidate: boolean } | null | void;
645
699
 
646
700
  // MiddlewareFn is imported from "../router/middleware.js" and re-exported
647
701
 
@@ -746,7 +800,7 @@ export type Revalidate<
746
800
  * Middleware function with typed params and environment
747
801
  *
748
802
  * @template TParams - Params object (defaults to generic)
749
- * @template TEnv - Environment type (defaults to global RSCRouter.Env)
803
+ * @template TEnv - Environment type (defaults to global Rango.Env)
750
804
  *
751
805
  * Note: Middleware cannot directly use route names for params typing because
752
806
  * middleware is defined during router setup, before RegisteredRoutes is populated.
@@ -754,7 +808,7 @@ export type Revalidate<
754
808
  *
755
809
  * @example
756
810
  * ```typescript
757
- * // Basic middleware (uses global RSCRouter.Env via module augmentation)
811
+ * // Basic middleware (uses global Rango.Env via module augmentation)
758
812
  * const middleware: Middleware = async (ctx, next) => {
759
813
  * ctx.set("user", { id: "123" }); // Type-safe!
760
814
  * await next();
@@ -1,14 +1,11 @@
1
- // Global namespace (must be imported for side effects: `declare global`)
2
1
  export type {
3
2
  GetRegisteredRoutes,
4
3
  DefaultHandlerRouteMap,
5
4
  DefaultReverseRouteMap,
6
5
  DefaultEnv,
7
6
  } from "./global-namespace.js";
8
- // Ensure the global namespace declaration is evaluated
9
7
  import "./global-namespace.js";
10
8
 
11
- // Route configuration
12
9
  export type {
13
10
  DocumentProps,
14
11
  ExtractParams,
@@ -19,7 +16,6 @@ export type {
19
16
  ResolvedRouteMap,
20
17
  } from "./route-config.js";
21
18
 
22
- // Boundaries (error/notFound)
23
19
  export type {
24
20
  ErrorInfo,
25
21
  ErrorBoundaryFallbackProps,
@@ -32,7 +28,6 @@ export type {
32
28
  } from "./boundaries.js";
33
29
  export { isLoaderDataResult } from "./boundaries.js";
34
30
 
35
- // Handler context and related types
36
31
  export type {
37
32
  MiddlewareFn,
38
33
  ScopedRouteMap,
@@ -42,6 +37,7 @@ export type {
42
37
  GenericParams,
43
38
  RevalidateParams,
44
39
  ShouldRevalidateFn,
40
+ ActionRef,
45
41
  RouteKeys,
46
42
  ExtractRouteParams,
47
43
  HandlersForRouteMap,
@@ -49,10 +45,11 @@ export type {
49
45
  Middleware,
50
46
  } from "./handler-context.js";
51
47
 
52
- // Segments
53
48
  export type {
54
49
  ViewTransitionClass,
55
50
  TransitionConfig,
51
+ TransitionWhenFn,
52
+ TransitionWhenContext,
56
53
  ResolvedSegment,
57
54
  SegmentMetadata,
58
55
  SlotState,
@@ -60,10 +57,8 @@ export type {
60
57
  MatchResult,
61
58
  } from "./segments.js";
62
59
 
63
- // Route entries
64
60
  export type { LazyIncludeContext, RouteEntry } from "./route-entry.js";
65
61
 
66
- // Loader types
67
62
  export type {
68
63
  LoaderContext,
69
64
  LoaderFn,
@@ -72,7 +67,6 @@ export type {
72
67
  LoaderDefinition,
73
68
  } from "./loader-types.js";
74
69
 
75
- // Cache types
76
70
  export type {
77
71
  CacheContext,
78
72
  CacheOptions,
@@ -80,7 +74,6 @@ export type {
80
74
  EntryCacheConfig,
81
75
  } from "./cache-types.js";
82
76
 
83
- // Error handling types
84
77
  export type {
85
78
  ErrorPhase,
86
79
  OnErrorContext,
@@ -1,12 +1,15 @@
1
1
  import type { ContextVar } from "../context-var.js";
2
+ import type { Handle } from "../handle.js";
2
3
  import type { MiddlewareFn } from "../router/middleware.js";
3
4
  import type { ScopedReverseFunction } from "../reverse.js";
4
5
  import type { SearchSchema, ResolveSearchSchema } from "../search-params.js";
6
+ import type { UseItems, LoaderUseItem } from "../route-types.js";
5
7
  import type {
6
8
  DefaultEnv,
7
9
  DefaultReverseRouteMap,
8
10
  DefaultVars,
9
11
  } from "./global-namespace.js";
12
+ import type { RequestScope } from "./request-scope.js";
10
13
 
11
14
  /**
12
15
  * Context passed to loader functions during execution
@@ -38,7 +41,7 @@ export type LoaderContext<
38
41
  TEnv = DefaultEnv,
39
42
  TBody = unknown,
40
43
  TSearch extends SearchSchema = {},
41
- > = {
44
+ > = RequestScope<TEnv> & {
42
45
  params: TParams;
43
46
  /**
44
47
  * Route params extracted from the URL pattern match (server-side only).
@@ -47,22 +50,46 @@ export type LoaderContext<
47
50
  * resource scoping.
48
51
  */
49
52
  routeParams: Record<string, string>;
50
- request: Request;
51
- searchParams: URLSearchParams;
52
53
  search: {} extends TSearch ? {} : ResolveSearchSchema<TSearch>;
53
- pathname: string;
54
- url: URL;
55
- env: TEnv;
56
- var: DefaultVars;
57
54
  get: {
58
55
  <T>(contextVar: ContextVar<T>): T | undefined;
59
56
  } & (<K extends keyof DefaultVars>(key: K) => DefaultVars[K]);
60
57
  /**
61
- * Access another loader's data (returns promise since loaders run in parallel)
58
+ * Access another loader's data, or read handle data after rendered().
59
+ *
60
+ * For loaders: returns a promise (loaders run in parallel).
61
+ * For handles: returns collected data (only after `await ctx.rendered()`).
62
+ */
63
+ use: {
64
+ <T, TLoaderParams = any>(
65
+ loader: LoaderDefinition<T, TLoaderParams>,
66
+ ): Promise<T>;
67
+ <TData, TAccumulated = TData[]>(
68
+ handle: Handle<TData, TAccumulated>,
69
+ ): TAccumulated;
70
+ };
71
+ /**
72
+ * **Experimental.** Wait for all non-loader segments to settle.
73
+ *
74
+ * After the returned promise resolves, handle data is available via
75
+ * `ctx.use(handle)`. Supported in DSL loaders, including on streaming
76
+ * trees that use `loading()` — the barrier waits for the streaming
77
+ * handlers to finish pushing before it resolves. Throws if called from a
78
+ * handler-invoked loader, or if a handler is already awaiting this loader
79
+ * via `ctx.use()` (that would deadlock — use a loader-to-loader
80
+ * dependency instead).
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * const PricesLoader = createLoader(async (ctx) => {
85
+ * "use server";
86
+ * await ctx.rendered();
87
+ * const products = ctx.use(Products); // reads handle data
88
+ * return pricing.getLive(products.map(p => p.id));
89
+ * });
90
+ * ```
62
91
  */
63
- use: <T, TLoaderParams = any>(
64
- loader: LoaderDefinition<T, TLoaderParams>,
65
- ) => Promise<T>;
92
+ rendered: () => Promise<void>;
66
93
  /**
67
94
  * HTTP method (GET, POST, PUT, PATCH, DELETE)
68
95
  * Available when loader is called via load({ method: "POST", ... })
@@ -180,4 +207,6 @@ export type LoaderDefinition<
180
207
  __brand: "loader";
181
208
  $$id: string; // Injected by Vite plugin (exposeInternalIds) - unique identifier
182
209
  fn?: LoaderFn<T, TParams, any>; // Optional - server-side only, stored in registry for RSC
210
+ /** Composable default DSL items merged when the loader is mounted. */
211
+ use?: () => UseItems<LoaderUseItem>;
183
212
  };
@@ -0,0 +1,112 @@
1
+ import type { DefaultEnv } from "./global-namespace.js";
2
+
3
+ /**
4
+ * Minimal subset of Cloudflare Workers' ExecutionContext that the router
5
+ * uses. Defined locally so the package does not depend on
6
+ * `@cloudflare/workers-types`. Consumers that want the full type can cast.
7
+ *
8
+ * On non-Cloudflare runtimes (Node, dev server, tests), this is undefined
9
+ * — portable apps should prefer `ctx.waitUntil(...)`, which degrades
10
+ * gracefully. `ctx.executionContext` is the escape hatch for libraries
11
+ * (MCP, Durable Object routing, etc.) that type their arguments as the
12
+ * raw ExecutionContext.
13
+ */
14
+ export interface ExecutionContext {
15
+ waitUntil(promise: Promise<any>): void;
16
+ passThroughOnException(): void;
17
+ }
18
+
19
+ /**
20
+ * Fallback `waitUntil` body used when no Cloudflare `ExecutionContext`
21
+ * is available (Node, dev, tests). Runs the work fire-and-forget and
22
+ * logs errors so they don't silently swallow.
23
+ *
24
+ * Exported so every `waitUntil` call site degrades identically instead
25
+ * of inventing its own fallback policy.
26
+ */
27
+ export function fireAndForgetWaitUntil(fn: () => Promise<void>): void {
28
+ // Defer fn() invocation to a microtask so a SYNCHRONOUS throw in a non-async
29
+ // callback (e.g. `() => { somethingThatThrows(); return p; }`) becomes a
30
+ // rejected promise we catch here, not an exception that escapes into the
31
+ // request flow. waitUntil is fire-and-forget: a background-task failure must
32
+ // never break the response.
33
+ Promise.resolve()
34
+ .then(fn)
35
+ .catch((err) => console.error("[waitUntil] Background task failed:", err));
36
+ }
37
+
38
+ /**
39
+ * Fields present on every user-facing request context.
40
+ *
41
+ * @template TEnv - Platform bindings type (Cloudflare env, etc.).
42
+ */
43
+ export interface RequestScope<TEnv = DefaultEnv> {
44
+ /**
45
+ * The original incoming Request object (transport URL intact).
46
+ * Use `url` / `searchParams` for application logic — those have
47
+ * internal `_rsc*` params stripped. `request` preserves the raw URL
48
+ * when you need original headers, method, or body.
49
+ */
50
+ request: Request;
51
+
52
+ /**
53
+ * The request URL with internal `_rsc*` transport params stripped.
54
+ * Use this for routing, link generation, and display.
55
+ */
56
+ url: URL;
57
+
58
+ /**
59
+ * The original request URL with all parameters intact, including
60
+ * internal `_rsc*` transport params. Use `url` for application logic
61
+ * — this is only needed for advanced cases like debugging or custom
62
+ * cache keying.
63
+ */
64
+ originalUrl: URL;
65
+
66
+ /** URL pathname (same as `url.pathname`). */
67
+ pathname: string;
68
+
69
+ /**
70
+ * Query parameters from the URL (system params like `_rsc*` are
71
+ * filtered). Always a standard `URLSearchParams` instance.
72
+ */
73
+ searchParams: URLSearchParams;
74
+
75
+ /**
76
+ * Platform bindings (DB, KV, secrets, etc.). On Cloudflare Workers
77
+ * these are the `env` object passed to the Worker's `fetch()` handler.
78
+ */
79
+ env: TEnv;
80
+
81
+ /**
82
+ * Schedule work to run after the response is sent.
83
+ * On Cloudflare Workers, delegates to `executionContext.waitUntil()`.
84
+ * On Node / dev / tests, runs as fire-and-forget with error logging.
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * ctx.waitUntil(async () => {
89
+ * await cacheStore.set(key, data, ttl);
90
+ * });
91
+ * ```
92
+ */
93
+ waitUntil(fn: () => Promise<void>): void;
94
+
95
+ /**
96
+ * Raw Cloudflare Workers `ExecutionContext`, when running on a
97
+ * Cloudflare-compatible runtime. Undefined elsewhere.
98
+ *
99
+ * Escape hatch for libraries that type their arguments as
100
+ * `ExecutionContext` (MCP `fetch`, `routeAgentRequest`, etc.).
101
+ * For the common "do work after the response" case, prefer
102
+ * `ctx.waitUntil(...)` — it is platform-neutral.
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * path.any("/mcp", (ctx) =>
107
+ * emailMcp.fetch(ctx.request, ctx.env, ctx.executionContext!),
108
+ * );
109
+ * ```
110
+ */
111
+ executionContext?: ExecutionContext;
112
+ }