@rangojs/router 0.0.0-experimental.79 → 0.0.0-experimental.7c7e4327

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 (440) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +301 -797
  3. package/dist/bin/rango.js +603 -145
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3750 -1160
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +96 -24
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +85 -6
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +228 -33
  12. package/skills/caching/SKILL.md +336 -19
  13. package/skills/catalog.json +271 -0
  14. package/skills/comparison/SKILL.md +50 -0
  15. package/skills/comparison/agents/openai.yaml +4 -0
  16. package/skills/comparison/references/framework-comparison.md +837 -0
  17. package/skills/composability/SKILL.md +110 -4
  18. package/skills/css/SKILL.md +76 -0
  19. package/skills/debug-manifest/SKILL.md +5 -3
  20. package/skills/defer-hydration/SKILL.md +235 -0
  21. package/skills/document-cache/SKILL.md +87 -56
  22. package/skills/fonts/SKILL.md +1 -1
  23. package/skills/handler-use/SKILL.md +12 -10
  24. package/skills/hooks/SKILL.md +73 -691
  25. package/skills/hooks/data.md +273 -0
  26. package/skills/hooks/handle-and-actions.md +103 -0
  27. package/skills/hooks/navigation.md +110 -0
  28. package/skills/hooks/outlets.md +41 -0
  29. package/skills/hooks/state.md +228 -0
  30. package/skills/hooks/urls.md +135 -0
  31. package/skills/host-router/SKILL.md +129 -27
  32. package/skills/i18n/SKILL.md +276 -0
  33. package/skills/intercept/SKILL.md +75 -19
  34. package/skills/layout/SKILL.md +40 -19
  35. package/skills/links/SKILL.md +247 -17
  36. package/skills/loader/SKILL.md +248 -10
  37. package/skills/middleware/SKILL.md +25 -13
  38. package/skills/migrate-nextjs/SKILL.md +205 -20
  39. package/skills/migrate-react-router/SKILL.md +59 -670
  40. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  41. package/skills/migrate-react-router/component-migration.md +196 -0
  42. package/skills/migrate-react-router/data-and-actions.md +225 -0
  43. package/skills/migrate-react-router/route-mapping.md +271 -0
  44. package/skills/mime-routes/SKILL.md +29 -2
  45. package/skills/observability/SKILL.md +202 -0
  46. package/skills/parallel/SKILL.md +40 -10
  47. package/skills/ppr/SKILL.md +616 -0
  48. package/skills/prerender/SKILL.md +72 -60
  49. package/skills/rango/SKILL.md +318 -26
  50. package/skills/react-compiler/SKILL.md +168 -0
  51. package/skills/response-routes/SKILL.md +138 -49
  52. package/skills/route/SKILL.md +117 -9
  53. package/skills/router-setup/SKILL.md +44 -9
  54. package/skills/scripts/SKILL.md +179 -0
  55. package/skills/server-actions/SKILL.md +776 -0
  56. package/skills/shell-manifest/SKILL.md +185 -0
  57. package/skills/streams-and-websockets/SKILL.md +283 -0
  58. package/skills/tailwind/SKILL.md +28 -4
  59. package/skills/testing/SKILL.md +130 -0
  60. package/skills/testing/bindings.md +103 -0
  61. package/skills/testing/cache-prerender.md +127 -0
  62. package/skills/testing/client-components.md +124 -0
  63. package/skills/testing/e2e-parity.md +125 -0
  64. package/skills/testing/flight.md +91 -0
  65. package/skills/testing/handles.md +131 -0
  66. package/skills/testing/loader.md +128 -0
  67. package/skills/testing/middleware.md +99 -0
  68. package/skills/testing/render-handler.md +122 -0
  69. package/skills/testing/response-routes.md +95 -0
  70. package/skills/testing/reverse-and-types.md +85 -0
  71. package/skills/testing/server-actions.md +107 -0
  72. package/skills/testing/server-tree.md +128 -0
  73. package/skills/testing/setup.md +123 -0
  74. package/skills/theme/SKILL.md +1 -1
  75. package/skills/typesafety/SKILL.md +45 -626
  76. package/skills/typesafety/env-and-bindings.md +254 -0
  77. package/skills/typesafety/generated-files-and-cli.md +335 -0
  78. package/skills/typesafety/params-and-search.md +153 -0
  79. package/skills/typesafety/route-types.md +209 -0
  80. package/skills/use-cache/SKILL.md +74 -15
  81. package/skills/vercel/SKILL.md +128 -0
  82. package/skills/view-transitions/SKILL.md +337 -0
  83. package/src/__augment-tests__/augment.ts +81 -0
  84. package/src/__augment-tests__/augmented.check.ts +116 -0
  85. package/src/__internal.ts +0 -65
  86. package/src/browser/action-coordinator.ts +53 -36
  87. package/src/browser/action-fence.ts +47 -0
  88. package/src/browser/app-shell.ts +39 -0
  89. package/src/browser/connection-warmup.ts +134 -0
  90. package/src/browser/cookie-name.ts +140 -0
  91. package/src/browser/event-controller.ts +252 -158
  92. package/src/browser/history-state.ts +21 -0
  93. package/src/browser/index.ts +3 -3
  94. package/src/browser/invalidate-client-cache.ts +52 -0
  95. package/src/browser/logging.ts +28 -0
  96. package/src/browser/merge-segment-loaders.ts +6 -4
  97. package/src/browser/navigation-bridge.ts +94 -25
  98. package/src/browser/navigation-client.ts +144 -79
  99. package/src/browser/navigation-store-handle.ts +38 -0
  100. package/src/browser/navigation-store.ts +161 -73
  101. package/src/browser/navigation-transaction.ts +9 -59
  102. package/src/browser/network-error-handler.ts +34 -7
  103. package/src/browser/partial-update.ts +183 -144
  104. package/src/browser/prefetch/cache.ts +242 -77
  105. package/src/browser/prefetch/fetch.ts +325 -69
  106. package/src/browser/prefetch/queue.ts +61 -12
  107. package/src/browser/rango-state.ts +158 -76
  108. package/src/browser/react/Link.tsx +58 -20
  109. package/src/browser/react/NavigationProvider.tsx +202 -120
  110. package/src/browser/react/ScrollRestoration.tsx +10 -6
  111. package/src/browser/react/filter-segment-order.ts +66 -7
  112. package/src/browser/react/index.ts +0 -48
  113. package/src/browser/react/location-state-shared.ts +178 -8
  114. package/src/browser/react/location-state.ts +39 -14
  115. package/src/browser/react/use-action.ts +6 -15
  116. package/src/browser/react/use-handle.ts +17 -14
  117. package/src/browser/react/use-href.tsx +8 -1
  118. package/src/browser/react/use-link-status.ts +33 -8
  119. package/src/browser/react/use-navigation.ts +32 -7
  120. package/src/browser/react/use-params.ts +20 -10
  121. package/src/browser/react/use-reverse.ts +106 -0
  122. package/src/browser/react/use-router.ts +25 -3
  123. package/src/browser/react/use-search-params.ts +0 -5
  124. package/src/browser/react/use-segments.ts +11 -21
  125. package/src/browser/response-adapter.ts +99 -8
  126. package/src/browser/rsc-router.tsx +145 -28
  127. package/src/browser/scroll-restoration.ts +37 -22
  128. package/src/browser/segment-reconciler.ts +31 -21
  129. package/src/browser/segment-structure-assert.ts +2 -2
  130. package/src/browser/server-action-bridge.ts +236 -65
  131. package/src/browser/types.ts +102 -9
  132. package/src/browser/validate-redirect-origin.ts +43 -16
  133. package/src/build/collect-fallback-refs.ts +107 -0
  134. package/src/build/generate-manifest.ts +203 -154
  135. package/src/build/generate-route-types.ts +3 -1
  136. package/src/build/index.ts +11 -3
  137. package/src/build/prefix-tree-utils.ts +123 -0
  138. package/src/build/route-trie.ts +152 -21
  139. package/src/build/route-types/ast-route-extraction.ts +15 -8
  140. package/src/build/route-types/codegen.ts +16 -5
  141. package/src/build/route-types/include-resolution.ts +456 -62
  142. package/src/build/route-types/param-extraction.ts +6 -3
  143. package/src/build/route-types/per-module-writer.ts +22 -6
  144. package/src/build/route-types/router-processing.ts +128 -51
  145. package/src/build/route-types/scan-filter.ts +1 -1
  146. package/src/build/route-types/source-scan.ts +216 -0
  147. package/src/build/runtime-discovery.ts +13 -21
  148. package/src/cache/cache-error.ts +104 -0
  149. package/src/cache/cache-key-utils.ts +58 -13
  150. package/src/cache/cache-policy.ts +108 -34
  151. package/src/cache/cache-runtime.ts +421 -58
  152. package/src/cache/cache-scope.ts +187 -96
  153. package/src/cache/cache-tag.ts +149 -0
  154. package/src/cache/cf/cf-base64.ts +33 -0
  155. package/src/cache/cf/cf-cache-constants.ts +127 -0
  156. package/src/cache/cf/cf-cache-store.ts +2202 -372
  157. package/src/cache/cf/cf-cache-types.ts +349 -0
  158. package/src/cache/cf/cf-kv-utils.ts +46 -0
  159. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  160. package/src/cache/cf/index.ts +6 -16
  161. package/src/cache/document-cache.ts +126 -41
  162. package/src/cache/handle-snapshot.ts +70 -0
  163. package/src/cache/index.ts +23 -20
  164. package/src/cache/memory-segment-store.ts +243 -37
  165. package/src/cache/profile-registry.ts +46 -31
  166. package/src/cache/read-through-swr.ts +56 -12
  167. package/src/cache/segment-codec.ts +13 -21
  168. package/src/cache/shell-snapshot.ts +417 -0
  169. package/src/cache/tag-invalidation.ts +230 -0
  170. package/src/cache/types.ts +180 -99
  171. package/src/cache/vercel/index.ts +11 -0
  172. package/src/cache/vercel/vercel-cache-store.ts +1127 -0
  173. package/src/client.rsc.tsx +41 -21
  174. package/src/client.tsx +33 -61
  175. package/src/cloudflare/index.ts +11 -0
  176. package/src/cloudflare/tracing.ts +108 -0
  177. package/src/component-utils.ts +19 -0
  178. package/src/components/DefaultDocument.tsx +8 -2
  179. package/src/context-var.ts +18 -6
  180. package/src/decode-loader-results.ts +52 -0
  181. package/src/defer.ts +185 -0
  182. package/src/deps/ssr.ts +0 -1
  183. package/src/encode-kv.ts +49 -0
  184. package/src/errors.ts +30 -4
  185. package/src/escape-script.ts +52 -0
  186. package/src/handle.ts +67 -37
  187. package/src/handles/MetaTags.tsx +24 -53
  188. package/src/handles/Scripts.tsx +183 -0
  189. package/src/handles/breadcrumbs.ts +35 -8
  190. package/src/handles/deferred-resolution.ts +127 -0
  191. package/src/handles/is-thenable.ts +18 -0
  192. package/src/handles/meta.ts +14 -40
  193. package/src/handles/script.ts +244 -0
  194. package/src/host/cookie-handler.ts +9 -60
  195. package/src/host/errors.ts +13 -22
  196. package/src/host/index.ts +9 -2
  197. package/src/host/pattern-matcher.ts +23 -52
  198. package/src/host/router.ts +107 -99
  199. package/src/host/testing.ts +40 -27
  200. package/src/host/types.ts +37 -4
  201. package/src/host/utils.ts +1 -1
  202. package/src/href-client.ts +137 -22
  203. package/src/index.rsc.ts +97 -12
  204. package/src/index.ts +98 -14
  205. package/src/internal-debug.ts +11 -10
  206. package/src/loader-store.ts +500 -0
  207. package/src/loader.rsc.ts +20 -13
  208. package/src/loader.ts +12 -11
  209. package/src/missing-id-error.ts +68 -0
  210. package/src/outlet-context.ts +1 -1
  211. package/src/outlet-provider.tsx +1 -5
  212. package/src/prerender/param-hash.ts +16 -16
  213. package/src/prerender/store.ts +32 -37
  214. package/src/prerender.ts +78 -10
  215. package/src/redirect-origin.ts +114 -0
  216. package/src/regex-escape.ts +8 -0
  217. package/src/render-error-thrower.tsx +20 -0
  218. package/src/response-utils.ts +62 -0
  219. package/src/reverse.ts +65 -39
  220. package/src/root-error-boundary.tsx +1 -19
  221. package/src/route-content-wrapper.tsx +19 -77
  222. package/src/route-definition/dsl-helpers.ts +304 -309
  223. package/src/route-definition/helper-factories.ts +28 -140
  224. package/src/route-definition/helpers-types.ts +87 -59
  225. package/src/route-definition/index.ts +1 -2
  226. package/src/route-definition/redirect.ts +44 -11
  227. package/src/route-definition/resolve-handler-use.ts +12 -1
  228. package/src/route-definition/use-item-types.ts +29 -0
  229. package/src/route-map-builder.ts +41 -20
  230. package/src/route-types.ts +19 -46
  231. package/src/router/basename.ts +14 -0
  232. package/src/router/content-negotiation.ts +73 -25
  233. package/src/router/error-handling.ts +45 -18
  234. package/src/router/find-match.ts +129 -30
  235. package/src/router/handler-context.ts +27 -42
  236. package/src/router/instrument.ts +355 -0
  237. package/src/router/intercept-resolution.ts +39 -20
  238. package/src/router/lazy-includes.ts +82 -59
  239. package/src/router/loader-resolution.ts +167 -72
  240. package/src/router/logging.ts +0 -6
  241. package/src/router/manifest.ts +74 -40
  242. package/src/router/match-api.ts +80 -55
  243. package/src/router/match-context.ts +0 -22
  244. package/src/router/match-handlers.ts +211 -165
  245. package/src/router/match-middleware/background-revalidation.ts +40 -24
  246. package/src/router/match-middleware/cache-lookup.ts +159 -285
  247. package/src/router/match-middleware/cache-store.ts +64 -52
  248. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  249. package/src/router/match-middleware/segment-resolution.ts +0 -22
  250. package/src/router/match-pipelines.ts +1 -42
  251. package/src/router/match-result.ts +69 -79
  252. package/src/router/metrics.ts +0 -34
  253. package/src/router/middleware-types.ts +7 -134
  254. package/src/router/middleware.ts +298 -172
  255. package/src/router/navigation-snapshot.ts +7 -56
  256. package/src/router/params-util.ts +23 -0
  257. package/src/router/parse-pattern.ts +115 -0
  258. package/src/router/pattern-matching.ts +181 -150
  259. package/src/router/prefetch-cache-ttl.ts +51 -0
  260. package/src/router/prefetch-limits.ts +37 -0
  261. package/src/router/prerender-match.ts +112 -67
  262. package/src/router/preview-match.ts +6 -2
  263. package/src/router/request-classification.ts +50 -69
  264. package/src/router/revalidation.ts +123 -73
  265. package/src/router/route-snapshot.ts +14 -3
  266. package/src/router/router-context.ts +6 -29
  267. package/src/router/router-interfaces.ts +115 -36
  268. package/src/router/router-options.ts +166 -5
  269. package/src/router/router-registry.ts +2 -5
  270. package/src/router/segment-resolution/fresh.ts +131 -86
  271. package/src/router/segment-resolution/helpers.ts +86 -6
  272. package/src/router/segment-resolution/loader-cache.ts +139 -39
  273. package/src/router/segment-resolution/loader-mask.ts +67 -0
  274. package/src/router/segment-resolution/loader-snapshot.ts +251 -0
  275. package/src/router/segment-resolution/revalidation.ts +272 -320
  276. package/src/router/segment-resolution/static-store.ts +19 -5
  277. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  278. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  279. package/src/router/segment-resolution.ts +5 -1
  280. package/src/router/segment-wrappers.ts +6 -5
  281. package/src/router/state-cookie-name.ts +33 -0
  282. package/src/router/substitute-pattern-params.ts +75 -0
  283. package/src/router/telemetry-otel.ts +160 -200
  284. package/src/router/telemetry.ts +105 -20
  285. package/src/router/timeout.ts +0 -20
  286. package/src/router/tracing.ts +215 -0
  287. package/src/router/trie-matching.ts +171 -59
  288. package/src/router/types.ts +9 -63
  289. package/src/router/url-params.ts +57 -0
  290. package/src/router.ts +157 -71
  291. package/src/rsc/full-payload.ts +70 -0
  292. package/src/rsc/handler-context.ts +3 -2
  293. package/src/rsc/handler.ts +291 -217
  294. package/src/rsc/helpers.ts +168 -46
  295. package/src/rsc/index.ts +2 -5
  296. package/src/rsc/json-route-result.ts +38 -0
  297. package/src/rsc/loader-fetch.ts +114 -38
  298. package/src/rsc/manifest-init.ts +29 -42
  299. package/src/rsc/nonce.ts +10 -1
  300. package/src/rsc/origin-guard.ts +39 -25
  301. package/src/rsc/progressive-enhancement.ts +124 -13
  302. package/src/rsc/redirect-guard.ts +100 -0
  303. package/src/rsc/response-cache-serve.ts +238 -0
  304. package/src/rsc/response-error.ts +79 -12
  305. package/src/rsc/response-route-handler.ts +99 -189
  306. package/src/rsc/rsc-rendering.ts +421 -76
  307. package/src/rsc/runtime-warnings.ts +23 -10
  308. package/src/rsc/server-action.ts +282 -116
  309. package/src/rsc/shell-capture.ts +1158 -0
  310. package/src/rsc/shell-serve.ts +150 -0
  311. package/src/rsc/ssr-setup.ts +16 -0
  312. package/src/rsc/transition-gate.ts +89 -0
  313. package/src/rsc/types.ts +53 -5
  314. package/src/runtime-env.ts +18 -0
  315. package/src/search-params.ts +35 -30
  316. package/src/segment-loader-promise.ts +49 -4
  317. package/src/segment-system.tsx +350 -149
  318. package/src/serialize.ts +243 -0
  319. package/src/server/context.ts +208 -51
  320. package/src/server/cookie-parse.ts +32 -0
  321. package/src/server/cookie-store.ts +152 -5
  322. package/src/server/handle-store.ts +21 -38
  323. package/src/server/loader-registry.ts +33 -42
  324. package/src/server/request-context.ts +395 -176
  325. package/src/ssr/index.tsx +458 -178
  326. package/src/ssr/ssr-root.tsx +228 -0
  327. package/src/static-handler.ts +10 -13
  328. package/src/testing/cache-status.ts +162 -0
  329. package/src/testing/collect-handle.ts +46 -0
  330. package/src/testing/dispatch.ts +813 -0
  331. package/src/testing/dom.entry.ts +22 -0
  332. package/src/testing/e2e/fixture.ts +188 -0
  333. package/src/testing/e2e/index.ts +128 -0
  334. package/src/testing/e2e/matchers.ts +35 -0
  335. package/src/testing/e2e/page-helpers.ts +272 -0
  336. package/src/testing/e2e/parity.ts +387 -0
  337. package/src/testing/e2e/server.ts +195 -0
  338. package/src/testing/flight-matchers.ts +97 -0
  339. package/src/testing/flight-normalize.ts +11 -0
  340. package/src/testing/flight-runtime.d.ts +57 -0
  341. package/src/testing/flight-tree.ts +682 -0
  342. package/src/testing/flight.entry.ts +52 -0
  343. package/src/testing/flight.ts +257 -0
  344. package/src/testing/generated-routes.ts +199 -0
  345. package/src/testing/index.ts +105 -0
  346. package/src/testing/internal/context.ts +371 -0
  347. package/src/testing/internal/flight-client-globals.ts +30 -0
  348. package/src/testing/internal/seed-vars.ts +54 -0
  349. package/src/testing/render-handler.ts +357 -0
  350. package/src/testing/render-route.tsx +584 -0
  351. package/src/testing/run-loader.ts +385 -0
  352. package/src/testing/run-middleware.ts +205 -0
  353. package/src/testing/run-transition-when.ts +164 -0
  354. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  355. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  356. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  357. package/src/testing/vitest-stubs/version.ts +5 -0
  358. package/src/testing/vitest.ts +305 -0
  359. package/src/theme/ThemeProvider.tsx +56 -84
  360. package/src/theme/ThemeScript.tsx +7 -9
  361. package/src/theme/constants.ts +52 -13
  362. package/src/theme/index.ts +0 -7
  363. package/src/theme/theme-context.ts +1 -5
  364. package/src/theme/theme-script.ts +22 -21
  365. package/src/theme/use-theme.ts +0 -3
  366. package/src/types/boundaries.ts +0 -35
  367. package/src/types/cache-types.ts +13 -4
  368. package/src/types/error-types.ts +30 -90
  369. package/src/types/global-namespace.ts +54 -41
  370. package/src/types/handler-context.ts +110 -62
  371. package/src/types/index.ts +3 -10
  372. package/src/types/loader-types.ts +11 -9
  373. package/src/types/request-scope.ts +112 -0
  374. package/src/types/route-config.ts +20 -52
  375. package/src/types/route-entry.ts +0 -6
  376. package/src/types/segments.ts +135 -14
  377. package/src/urls/include-helper.ts +19 -64
  378. package/src/urls/include-provider.ts +71 -0
  379. package/src/urls/index.ts +2 -11
  380. package/src/urls/path-helper-types.ts +63 -17
  381. package/src/urls/path-helper.ts +22 -106
  382. package/src/urls/pattern-types.ts +72 -19
  383. package/src/urls/response-types.ts +22 -29
  384. package/src/urls/type-extraction.ts +98 -154
  385. package/src/urls/urls-function.ts +1 -19
  386. package/src/use-loader.tsx +292 -107
  387. package/src/vercel/index.ts +11 -0
  388. package/src/vercel/tracing.ts +88 -0
  389. package/src/vite/debug.ts +185 -0
  390. package/src/vite/discovery/bundle-postprocess.ts +8 -7
  391. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  392. package/src/vite/discovery/discover-routers.ts +127 -86
  393. package/src/vite/discovery/discovery-errors.ts +255 -0
  394. package/src/vite/discovery/gate-state.ts +171 -0
  395. package/src/vite/discovery/prerender-collection.ts +96 -68
  396. package/src/vite/discovery/route-types-writer.ts +40 -84
  397. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  398. package/src/vite/discovery/state.ts +45 -1
  399. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  400. package/src/vite/index.ts +4 -0
  401. package/src/vite/inject-client-debug.ts +88 -0
  402. package/src/vite/plugin-types.ts +210 -10
  403. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  404. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  405. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  406. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  407. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  408. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  409. package/src/vite/plugins/expose-action-id.ts +48 -95
  410. package/src/vite/plugins/expose-id-utils.ts +88 -55
  411. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  412. package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
  413. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  414. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  415. package/src/vite/plugins/expose-internal-ids.ts +505 -486
  416. package/src/vite/plugins/performance-tracks.ts +26 -25
  417. package/src/vite/plugins/refresh-cmd.ts +1 -1
  418. package/src/vite/plugins/use-cache-transform.ts +73 -83
  419. package/src/vite/plugins/vercel-output.ts +384 -0
  420. package/src/vite/plugins/version-injector.ts +40 -29
  421. package/src/vite/plugins/version-plugin.ts +37 -40
  422. package/src/vite/plugins/virtual-entries.ts +138 -27
  423. package/src/vite/rango.ts +236 -138
  424. package/src/vite/router-discovery.ts +927 -136
  425. package/src/vite/utils/ast-handler-extract.ts +26 -35
  426. package/src/vite/utils/banner.ts +1 -1
  427. package/src/vite/utils/bundle-analysis.ts +10 -15
  428. package/src/vite/utils/client-chunks.ts +184 -0
  429. package/src/vite/utils/directive-prologue.ts +40 -0
  430. package/src/vite/utils/forward-user-plugins.ts +171 -0
  431. package/src/vite/utils/manifest-utils.ts +4 -59
  432. package/src/vite/utils/package-resolution.ts +20 -52
  433. package/src/vite/utils/prerender-utils.ts +71 -43
  434. package/src/vite/utils/shared-utils.ts +142 -43
  435. package/src/browser/action-response-classifier.ts +0 -99
  436. package/src/browser/react/use-client-cache.ts +0 -58
  437. package/src/browser/shallow.ts +0 -40
  438. package/src/handles/index.ts +0 -7
  439. package/src/network-error-thrower.tsx +0 -23
  440. package/src/router/middleware-cookies.ts +0 -55
@@ -1,12 +1,22 @@
1
1
  ---
2
2
  name: loader
3
- description: Define data loaders for fetching data in routes with createLoader
3
+ description: Define data loaders for fetching data in routes with createLoader. Use when pages need per-request data that stays fresh, data should stream while the page renders, or client components need reactive server data.
4
4
  argument-hint: [loader]
5
5
  ---
6
6
 
7
7
  # Data Loaders with loader()
8
8
 
9
- Loaders fetch data on the server and stream it to the client.
9
+ Loaders fetch data on the server and stream it to the client. For mutations
10
+ (writes triggered by forms or buttons), use server actions instead — see
11
+ `/server-actions`. Loaders re-resolve after an action runs, so the typical
12
+ flow is _action mutates → loader re-reads → UI updates_.
13
+
14
+ ## Not this skill if…
15
+
16
+ - You want to mutate state — mutations are `"use server"` actions: see
17
+ `/server-actions`. Loaders read per-request live data.
18
+ - You want to cache a function's return value — loaders are fresh every request
19
+ by default; caching one function is `"use cache"`: see `/use-cache`.
10
20
 
11
21
  ## Creating a Loader
12
22
 
@@ -88,6 +98,20 @@ path("/product/:slug", ProductPage, { name: "product" }, () => [
88
98
  ]);
89
99
  ```
90
100
 
101
+ > **Client refresh `key` vs. server `cache({ key })` vs. `revalidate()`.** Three
102
+ > different "what refreshes" knobs that are easy to confuse:
103
+ >
104
+ > - `useLoader(Loader, { key })` / `useFetchLoader(Loader, { key })` — a
105
+ > **client** refresh identity. It groups which mounted reads of one loader
106
+ > refresh together when one calls `load()`. It never touches the server
107
+ > request. For refreshing **different** loaders together, tag them with
108
+ > `{ refreshGroup }` (one name or several) and call `useRefreshLoaders()(name)`
109
+ > (plain GET only). See the hooks skill ("Scoping refetch with a `key`" and
110
+ > "Refreshing multiple loaders together").
111
+ > - `cache({ key })` — a **server** cache identity (storage hit/miss/ttl/swr).
112
+ > - `revalidate()` — which **server** segments/loaders recompute during
113
+ > navigation and action refreshes.
114
+
91
115
  DSL loaders are the **live data layer** — they resolve fresh on every
92
116
  request, even when the route is inside a `cache()` boundary. The router
93
117
  excludes them from the segment cache at storage time and re-resolves them
@@ -123,6 +147,11 @@ same memoized result — loaders never run twice per request.
123
147
  - The handler output depends on the loader data. If the route is inside
124
148
  `cache()`, the handler is cached with the loader result baked in —
125
149
  defeating the live data guarantee.
150
+ - The same holds under a PPR shell capture (`/ppr`): handler consumption is
151
+ the BAKED lane — the loader executes at capture (identity reads permitted)
152
+ and the rendered value is a capture-time copy; `useLoader` client-side is
153
+ the live lane. One rule across `cache()`, `"use cache"`, and PPR: the
154
+ consumption-lane rule (`/rango` → Invariants).
126
155
  - Non-cacheable variable reads (`createVar({ cache: false })`) inside the
127
156
  handler still throw, even if the data came from a loader.
128
157
  - Prefer DSL `loader()` + client `useLoader()` for data that depends on
@@ -139,7 +168,29 @@ same memoized result — loaders never run twice per request.
139
168
 
140
169
  ## Loader Context
141
170
 
142
- Loaders receive the same context as route handlers:
171
+ Loaders receive the same context shape as route handlers.
172
+
173
+ ### Full field surface
174
+
175
+ | Field | Type | Notes |
176
+ | -------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
177
+ | `params` | `TParams` | Merged route + explicit loader params; overridable by fetchable `load({ params })`. |
178
+ | `routeParams` | `Record<string, string>` | Server-trusted route params from URL pattern matching; cannot be overridden. |
179
+ | `request` | `Request` | The incoming `Request` (headers, method, body, `signal` for abort). |
180
+ | `url` | `URL` | Parsed request URL. |
181
+ | `pathname` | `string` | URL pathname (shortcut for `ctx.url.pathname`). |
182
+ | `searchParams` | `URLSearchParams` | Shortcut for `ctx.url.searchParams`. |
183
+ | `search` | `ResolveSearchSchema<TSearch>` | Typed query params when a search schema is declared on the route; `{}` otherwise. |
184
+ | `env` | `TEnv` | Plain bindings from `createRouter<TEnv>()` (DB, KV, secrets, etc.). |
185
+ | `get` | `(key \| ContextVar) => value` | Reads variables/context-vars set by middleware. |
186
+ | `use` | `(loader \| handle) => T` | Access another loader's data (Promise) or a handle's collected data (after `await ctx.rendered()`). |
187
+ | `rendered` | `() => Promise<void>` | **Experimental.** DSL loaders only — waits for all non-loader segments (including `loading()` streaming handlers) to settle before reading handle data. |
188
+ | `method` | `string` | HTTP method. `"GET"` for SSR loader runs; reflects real method for fetchable loaders. |
189
+ | `body` | `TBody \| undefined` | Parsed request body for fetchable POST/PUT/PATCH/DELETE calls. |
190
+ | `formData` | `FormData \| undefined` | Present when a fetchable loader is invoked via form submission. |
191
+ | `reverse` | `ScopedReverseFunction` | Generate type-checked URLs from route names (same scoped semantics as route handlers). |
192
+
193
+ ### Example
143
194
 
144
195
  ```typescript
145
196
  export const ProductLoader = createLoader(async (ctx) => {
@@ -160,13 +211,24 @@ export const ProductLoader = createLoader(async (ctx) => {
160
211
  // Request headers
161
212
  const auth = ctx.request.headers.get("Authorization");
162
213
 
163
- // Variables set by middleware (from RSCRouter.Vars augmentation)
214
+ // Variables set by middleware (from Rango.Vars augmentation)
164
215
  const user = ctx.get("user");
165
216
 
166
- return { product: await fetchProduct(slug) };
217
+ // Type-checked URLs for payloads. `.name` resolves within the current
218
+ // include() scope; a bare `name` resolves globally. See /route and
219
+ // /typesafety for scope rules and route-name autocomplete.
220
+ const detailUrl = ctx.reverse(".detail", { slug });
221
+
222
+ return {
223
+ product: await fetchProduct(slug),
224
+ links: { self: detailUrl },
225
+ };
167
226
  });
168
227
  ```
169
228
 
229
+ See `/route` for the full handler-context contract (shared with loaders) and
230
+ `/typesafety` for route-name typing that powers `ctx.reverse` autocomplete.
231
+
170
232
  ### params vs routeParams
171
233
 
172
234
  - `ctx.params` — merged route params + explicit loader params. For fetchable
@@ -199,6 +261,8 @@ export const OrderLoader = createLoader(async (ctx) => {
199
261
  Add caching or revalidation to specific loaders:
200
262
 
201
263
  ```typescript
264
+ import * as CartActions from "./actions/cart";
265
+
202
266
  path("/product/:slug", ProductPage, { name: "product" }, () => [
203
267
  // Cached loader
204
268
  loader(ProductLoader, () => [cache({ ttl: 300 })]),
@@ -208,13 +272,104 @@ path("/product/:slug", ProductPage, { name: "product" }, () => [
208
272
  revalidate(() => false), // Never revalidate
209
273
  ]),
210
274
 
211
- // Loader that revalidates after cart actions
275
+ // Loader that revalidates after cart actions (defer otherwise — keeps the
276
+ // permissive loader defaults for navigation and other actions intact)
212
277
  loader(CartLoader, () => [
213
- revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
278
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
214
279
  ]),
215
280
  ]);
216
281
  ```
217
282
 
283
+ ### `revalidate()` return shapes
284
+
285
+ > **Scope: `revalidate()` is a partial-render concern, not a cache concern.**
286
+ > It decides whether a segment (here, a loader) re-runs and streams to the
287
+ > client on a navigation or action — never whether a cached value is stale. The
288
+ > cache decides hit/miss/ttl/swr independently and never reads `revalidate()`.
289
+ > Caching a loader is a separate, opt-in step (`loader(Fn, () => [cache({...})])`).
290
+ > See `/cache-guide` → "Two axes" and `/rango` → "The shape of rango".
291
+
292
+ A `revalidate(fn)` callback can return one of four shapes. The chain
293
+ processes revalidators in order; each call's return controls how the
294
+ chain continues:
295
+
296
+ ```typescript
297
+ // 1) Hard decision — short-circuits the chain, used as the final answer.
298
+ revalidate(() => true);
299
+ revalidate(({ actionId }) => actionId?.includes("Cart") ?? false);
300
+
301
+ // 2) Soft decision — updates the running suggestion for downstream
302
+ // revalidators on the same segment, chain continues.
303
+ revalidate(({ defaultShouldRevalidate }) => ({
304
+ defaultShouldRevalidate: !defaultShouldRevalidate,
305
+ }));
306
+
307
+ // 3) Defer (no opinion) — leaves the running suggestion unchanged and
308
+ // continues to the next revalidator. Implicit return / null /
309
+ // undefined are all equivalent and consumer-friendly.
310
+ revalidate(({ actionId }) => {
311
+ if (actionId?.includes("Cart")) return true; // hard for this branch only
312
+ // implicit return — let downstream revalidators or the segment default decide
313
+ });
314
+ revalidate(() => undefined); // explicit defer
315
+ revalidate(() => null); // explicit defer
316
+ ```
317
+
318
+ If every revalidator on a segment defers, the segment-type default
319
+ (e.g. params-changed for routes, `false` for parallels) is used.
320
+
321
+ #### `|| undefined` (defer) vs `?? false` (hard) — pick deliberately
322
+
323
+ A boolean return — including `false` — is a **hard** decision: it short-circuits
324
+ the chain and overrides the segment default. `undefined` **defers** to the
325
+ running suggestion / segment default. They are not interchangeable:
326
+
327
+ ```typescript
328
+ // Defer: "revalidate on match, otherwise let the default/downstream decide."
329
+ revalidate(({ actionId }) => actionId?.includes("Cart") || undefined);
330
+
331
+ // Hard: "revalidate ONLY on match, suppress everything else."
332
+ revalidate(({ actionId }) => actionId?.includes("Cart") ?? false);
333
+ ```
334
+
335
+ This matters most for loaders, whose defaults are permissive: a loader defaults
336
+ to revalidating on **any** action (`POST`) and on **param/search changes**
337
+ during navigation. So `?? false` on a loader silently suppresses both — the
338
+ loader will not refetch when you navigate to a different `:id`. Use
339
+ `|| undefined` when you want to _add_ a revalidation signal on top of the
340
+ sensible defaults, and reserve `?? false` for the rare case where you genuinely
341
+ want the loader to refetch on nothing but your matched action.
342
+
343
+ When **composing multiple revalidators** on one segment (see below), defer is
344
+ mandatory: the first hard `?? false` ends the chain and the later contracts
345
+ never run.
346
+
347
+ #### Matching actions: `ctx.isAction()`
348
+
349
+ To revalidate after specific server actions, match them by **reference** with
350
+ `ctx.isAction()` rather than hand-written `actionId` substrings. A rename or
351
+ moved file then becomes a type error instead of silently failing to match:
352
+
353
+ ```typescript
354
+ import { addToCart, removeFromCart } from "../actions/cart";
355
+ import * as CartActions from "../actions/cart";
356
+
357
+ loader(CartLoader, () => [
358
+ revalidate((ctx) => ctx.isAction(addToCart) || undefined), // one action
359
+ ]);
360
+ revalidate((ctx) => ctx.isAction(addToCart, removeFromCart) || undefined); // several
361
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined); // any action in the module
362
+ ```
363
+
364
+ `isAction()` is a method on the revalidate predicate's **context argument** —
365
+ there is no standalone `isAction` import; you always reach it through the callback
366
+ parameter (`revalidate((ctx) => ctx.isAction(...))`). It returns a raw boolean, so
367
+ pair it with `|| undefined` for the usual "revalidate on match, else defer"
368
+ intent. It returns `false` on plain navigation and on non-matches, and resolves
369
+ the reference the same way the router derives `actionId` (`$id` in production,
370
+ `$$id` in dev), so it matches in both modes. The raw `actionId` string stays
371
+ available on the same context as an escape hatch.
372
+
218
373
  ### Revalidation Contracts for Loader Dependencies
219
374
 
220
375
  If a loader reads `ctx.get()` data produced by an outer handler/layout, share
@@ -222,8 +377,12 @@ the same named revalidation contract across producer and consumer segments.
222
377
 
223
378
  ```typescript
224
379
  // revalidation-contracts.ts
225
- export const revalidateAccountScope = ({ actionId }) =>
226
- actionId?.includes("src/actions/account.ts#") ?? false;
380
+ import * as AccountActions from "./actions/account";
381
+
382
+ // Match by reference with ctx.isAction() (rename-safe), and defer (|| undefined)
383
+ // so these contracts compose — a hard `false` would short-circuit the rest.
384
+ export const revalidateAccountScope = (ctx) =>
385
+ ctx.isAction(AccountActions) || undefined;
227
386
 
228
387
  layout(AccountLayout, () => [
229
388
  revalidate(revalidateAccountScope), // producer reruns
@@ -266,6 +425,64 @@ follows the same rule: at build time, loaders are skipped entirely (there is no
266
425
  real request context), and at runtime the worker resolves them fresh against
267
426
  the live database.
268
427
 
428
+ ### Parallel and streaming — latency overlaps first paint
429
+
430
+ Loaders do not block the page. As the render pass begins — the pass that route
431
+ middleware wraps, so loaders run right after middleware, not in a later
432
+ phase — every matched loader is kicked off **concurrently** (their promises start in the
433
+ same tick), and each result is **streamed** to the client as its own RSC Flight
434
+ chunk rather than awaited up front. Pair a loader with `loading()` (or a
435
+ client `<Suspense>`) and the shell paints immediately while the data streams in.
436
+
437
+ This is why **"cached UI still pays full data latency" is the wrong intuition**:
438
+ on a `cache()` hit the UI segments stream instantly from cache while the live
439
+ loaders resolve fresh **in parallel** — data latency _overlaps_ first paint
440
+ instead of being added on top of it. (Without a `loading()` / `<Suspense>`
441
+ boundary a parallel loader blocks its parent, so add one to keep the overlap.)
442
+
443
+ If you come from a framework where the loader is a blocking step that runs
444
+ before the response is built, this is the shift to internalize: here the
445
+ response starts streaming first and loader data fills in.
446
+
447
+ ### See it: `debugPerformance`
448
+
449
+ Turn on the per-request performance timeline early — it is the fastest way to
450
+ confirm loaders overlap rather than serialize, and to find the real bottleneck
451
+ locally instead of guessing:
452
+
453
+ ```typescript
454
+ const router = createRouter({ document: Document, debugPerformance: true });
455
+ ```
456
+
457
+ Or enable it per-request from middleware (e.g. only when `?debug` is present) by
458
+ calling `ctx.debugPerformance()` **before** `await next()`. Each HTML request
459
+ then prints a shared-axis waterfall (and emits a `Server-Timing` header):
460
+
461
+ ```
462
+ [RSC Perf] GET /product/widget (24.53ms)
463
+ start dur span timeline
464
+ 0.08ms 3.20ms route-matching |#####...................................|
465
+ 3.40ms 8.70ms ssr-render-html |.....##############.....................|
466
+ 3.42ms 11.90ms loader:…#ProductLoader |.....###################................|
467
+ 3.45ms 11.40ms loader:…#ReviewsLoader |.....##################.................|
468
+ 0.00ms 24.53ms handler:total |########################################|
469
+ ```
470
+
471
+ How to read it:
472
+
473
+ - **Humans:** scan the `#` bars on the shared axis. Bars that start at the same
474
+ offset and run side by side are executing **in parallel** — loaders should
475
+ overlap `ssr-render-html` / `render:total`, not sit alone to the right of
476
+ everything. A lone `loader:*` bar past the render bar is serialized latency to
477
+ chase. `handler:total` is the whole request; `render:total` is the render pass.
478
+ - **LLMs / programmatic:** read each row as `{ start, dur, label }`. A loader
479
+ overlaps paint when its `[start, start+dur]` interval intersects
480
+ `render:total` / `ssr-render-html`. Flag a regression when a `loader:*`
481
+ interval is **disjoint from and starts after** `render:total`, or when its
482
+ `dur` approaches `handler:total` — that loader is on the critical path instead
483
+ of overlapping it. Two `loader:*` rows with near-equal `start` confirm
484
+ parallel execution.
485
+
269
486
  ### Opting a Loader into Caching
270
487
 
271
488
  To cache a specific loader's data, attach a `cache()` child:
@@ -356,6 +573,8 @@ entirely (no read, no write).
356
573
  ### Per-Loader Store Override
357
574
 
358
575
  ```typescript
576
+ import { MemorySegmentCacheStore } from "@rangojs/router/cache";
577
+
359
578
  const hotStore = new MemorySegmentCacheStore({ defaults: { ttl: 10 } });
360
579
 
361
580
  loader(PricingLoader, () => [
@@ -464,6 +683,16 @@ export const SearchLoader = createLoader(async (ctx) => {
464
683
  }, true); // true = fetchable
465
684
  ```
466
685
 
686
+ > **No registration needed — and no worker-entry import.** A fetchable loader
687
+ > does not have to be registered with `loader()` in the route DSL, and it does
688
+ > not have to be imported by any server module. Importing it into the client
689
+ > component that calls `useFetchLoader()` / `load()` is enough. Rango discovers
690
+ > every `createLoader(fn, true)` at build time and registers it for the
691
+ > `_rsc_loader` endpoint, so a loader reachable only through a client component
692
+ > still resolves in production — on both the generated entry and a hand-written
693
+ > worker entry (e.g. a Cloudflare `worker.rsc.tsx`). You do **not** need to
694
+ > force-import the loader in your worker entry to make it resolve.
695
+
467
696
  ### Fetchable Loader with Middleware
468
697
 
469
698
  Pass an options object instead of `true` to attach per-loader middleware.
@@ -539,6 +768,13 @@ export const FileUploadLoader = createLoader(async (ctx) => {
539
768
 
540
769
  Client usage — see `/hooks useFetchLoader` for the full client-side pattern.
541
770
 
771
+ > **Refetch sharing**: when the loader is registered on the route via
772
+ > `loader()`, a plain `load()` call (no `params`, no `body`) broadcasts
773
+ > the new value to every component reading the same loader id —
774
+ > `useLoader` reads in layouts, pages, and parallel slots all converge.
775
+ > Calls with `params` or a non-GET method stay local to the call site.
776
+ > See `/hooks` → "Shared refetch behavior" for the full contract.
777
+
542
778
  ## Complete Example
543
779
 
544
780
  ```typescript
@@ -571,10 +807,12 @@ export const CartLoader = createLoader(async (ctx) => {
571
807
  });
572
808
 
573
809
  // urls.tsx — register loaders in the DSL
810
+ import * as CartActions from "./actions/cart";
811
+
574
812
  export const urlpatterns = urls(({ path, layout, loader, loading, cache, revalidate }) => [
575
813
  layout(<ShopLayout />, () => [
576
814
  loader(CartLoader, () => [
577
- revalidate(({ actionId }) => actionId?.includes("Cart") ?? false),
815
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
578
816
  ]),
579
817
 
580
818
  path("/shop/product/:slug", ProductPage, { name: "product" }, () => [
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: middleware
3
- description: Define middleware for authentication, logging, and request processing in @rangojs/router
3
+ description: Define middleware for authentication, logging, and request processing in @rangojs/router. Use when gating routes behind auth checks, logging requests, or running shared logic before a handler runs.
4
4
  argument-hint: [middleware-name]
5
5
  ---
6
6
 
@@ -10,9 +10,6 @@ Middleware runs before/after route handlers using the onion model.
10
10
 
11
11
  ## Execution Model
12
12
 
13
- Canonical semantics reference:
14
- [docs/execution-model.md](../../docs/internal/execution-model.md)
15
-
16
13
  There are two levels of middleware with different execution scopes:
17
14
 
18
15
  ### Global middleware (`router.use()`)
@@ -32,17 +29,26 @@ When the router has a `basename`, pattern-scoped `.use()` patterns are automatic
32
29
 
33
30
  Registered inside `urls()` callback. Wraps **rendering only** -- it does NOT wrap server action execution. Actions run before route middleware, so when route middleware executes during post-action revalidation, it can observe state that the action set (cookies, context variables, headers).
34
31
 
32
+ > **Implication for auth:** route middleware cannot guard server actions. Use `router.use("/admin/*", requireAuth)` (global, scoped) for action protection, or check inside the action body. See `/server-actions` for action-side auth patterns.
33
+
35
34
  ```
36
35
  Request flow (with action):
37
- global mw -> action executes -> route mw -> layout -> handler -> loaders
36
+ global mw -> action executes -> route mw -> render pass
38
37
 
39
38
  Request flow (no action):
40
- global mw -> route mw -> layout -> handler -> loaders
39
+ global mw -> route mw -> render pass
41
40
 
42
41
  Progressive enhancement (no-JS form POST):
43
42
  global mw -> action executes -> route mw -> full page re-render
44
43
  ```
45
44
 
45
+ The **render pass** resolves handler, layouts, parallels, and loaders together —
46
+ it is not a handler-then-loaders sequence. Handler-first ordering is guaranteed
47
+ only between a route handler and its child/orphan layouts and parallels (so
48
+ `ctx.set` is visible); loaders run **concurrently** and stream their results, so
49
+ their latency overlaps rendering rather than blocking it. See `/loader` →
50
+ "Parallel and streaming".
51
+
46
52
  The contract is: **route middleware wraps rendering regardless of transport** (JS-enabled RSC stream or no-JS HTML). During PE re-render, route middleware observes action-set state (cookies, context variables) the same way it does during JS-enabled post-action revalidation.
47
53
 
48
54
  Revalidation is still partial. Route middleware wraps the render pass that
@@ -54,15 +60,21 @@ data itself.
54
60
  ### Revalidation Contracts with Middleware-Backed Trees
55
61
 
56
62
  Middleware can establish request-level context (`ctx.set`) for segments that
57
- execute in the current render pass. It does not change partial revalidation
58
- boundaries between handler/layout/parallel segments.
63
+ execute in the current render pass. Because route middleware wraps **every**
64
+ render pass normal renders, post-action revalidation, PE re-renders — its
65
+ variables are never stale: middleware is the safest `ctx.set` rung on the
66
+ data-passing ladder (`/rango` → "Passing data down the tree"). But it does
67
+ not change partial revalidation boundaries between handler/layout/parallel
68
+ segments.
59
69
 
60
70
  For shared segment data, use named revalidation contracts on both the producer
61
71
  and consumer segments, even when middleware is present in the chain.
62
72
 
63
73
  ```typescript
64
- export const revalidateCartData = ({ actionId }) =>
65
- actionId?.includes("src/actions/cart.ts#") ?? false;
74
+ import * as CartActions from "./actions/cart";
75
+
76
+ export const revalidateCartData = (ctx) =>
77
+ ctx.isAction(CartActions) || undefined;
66
78
 
67
79
  layout(CartLayout, () => [
68
80
  middleware(cartRenderMiddleware),
@@ -190,7 +202,7 @@ export const myMiddleware: Middleware = async (ctx, next) => {
190
202
  ctx.env.DB; // D1Database
191
203
  ctx.env.KV; // KVNamespace
192
204
 
193
- // Set variables for downstream handlers (typed via RSCRouter.Vars)
205
+ // Set variables for downstream handlers (typed via Rango.Vars)
194
206
  ctx.set("user", { id: "123", name: "John" });
195
207
 
196
208
  // Continue to next middleware/handler
@@ -231,8 +243,8 @@ const Dashboard: Handler<"dashboard"> = (ctx) => {
231
243
  ```
232
244
 
233
245
  This works alongside `ctx.get("key")` / `ctx.set("key", value)` (global typing
234
- via RSCRouter.Vars augmentation). Use `createVar` for route-local or feature-scoped
235
- data; use RSCRouter.Vars for app-wide middleware state.
246
+ via Rango.Vars augmentation). Use `createVar` for route-local or feature-scoped
247
+ data; use Rango.Vars for app-wide middleware state.
236
248
 
237
249
  ## Redirect with State in Middleware
238
250