@rangojs/router 0.16.0 → 0.18.0

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 (309) hide show
  1. package/README.md +255 -89
  2. package/dist/testing/vitest.js +252 -0
  3. package/dist/types/browser/cookie-name.d.ts +6 -0
  4. package/dist/types/browser/history-state.d.ts +16 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +6 -0
  6. package/dist/types/browser/partial-update.d.ts +11 -0
  7. package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
  8. package/dist/types/browser/rsc-router.d.ts +1 -1
  9. package/dist/types/browser/scroll-restoration.d.ts +7 -0
  10. package/dist/types/cache/cache-exec-scope.d.ts +18 -1
  11. package/dist/types/cache/cache-key-utils.d.ts +17 -2
  12. package/dist/types/cache/cache-policy.d.ts +17 -0
  13. package/dist/types/cache/cache-scope.d.ts +132 -19
  14. package/dist/types/cache/cache-tag.d.ts +92 -7
  15. package/dist/types/cache/cf/cf-base64.d.ts +6 -0
  16. package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
  17. package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
  18. package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
  19. package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
  20. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
  21. package/dist/types/cache/handle-capture.d.ts +41 -3
  22. package/dist/types/cache/handle-snapshot.d.ts +54 -13
  23. package/dist/types/cache/index.d.ts +1 -0
  24. package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
  25. package/dist/types/cache/segment-codec.d.ts +10 -3
  26. package/dist/types/cache/shell-memo.d.ts +178 -0
  27. package/dist/types/cache/shell-snapshot.d.ts +110 -21
  28. package/dist/types/cache/tag-invalidation.d.ts +30 -3
  29. package/dist/types/cache/taint.d.ts +1 -1
  30. package/dist/types/cache/types.d.ts +220 -44
  31. package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
  32. package/dist/types/client.d.ts +4 -4
  33. package/dist/types/client.rsc.d.ts +4 -5
  34. package/dist/types/components/DefaultDocument.d.ts +5 -2
  35. package/dist/types/context-var.d.ts +6 -5
  36. package/dist/types/escape-script.d.ts +1 -1
  37. package/dist/types/handles/MetaTags.d.ts +5 -4
  38. package/dist/types/handles/Scripts.d.ts +8 -7
  39. package/dist/types/handles/meta.d.ts +2 -2
  40. package/dist/types/handles/script.d.ts +17 -16
  41. package/dist/types/href-client.d.ts +1 -1
  42. package/dist/types/html.d.ts +12 -0
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.rsc.d.ts +3 -2
  45. package/dist/types/loader-store.d.ts +7 -4
  46. package/dist/types/prerender/build-shell-capture.d.ts +11 -4
  47. package/dist/types/reverse.d.ts +36 -4
  48. package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
  49. package/dist/types/route-definition/helpers-types.d.ts +33 -9
  50. package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
  51. package/dist/types/route-types.d.ts +1 -1
  52. package/dist/types/router/debug-manifest.d.ts +3 -2
  53. package/dist/types/router/error-handling.d.ts +20 -0
  54. package/dist/types/router/handler-context.d.ts +6 -0
  55. package/dist/types/router/instrument.d.ts +8 -0
  56. package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
  57. package/dist/types/router/middleware-types.d.ts +9 -3
  58. package/dist/types/router/router-context.d.ts +3 -1
  59. package/dist/types/router/router-interfaces.d.ts +24 -2
  60. package/dist/types/router/router-options.d.ts +8 -5
  61. package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
  62. package/dist/types/router/segment-resolution/loader-cache.d.ts +66 -1
  63. package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
  64. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
  65. package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
  66. package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
  67. package/dist/types/router/segment-wrappers.d.ts +1 -1
  68. package/dist/types/rsc/full-payload.d.ts +14 -0
  69. package/dist/types/rsc/handler.d.ts +1 -1
  70. package/dist/types/rsc/response-route-handler.d.ts +1 -1
  71. package/dist/types/rsc/rsc-rendering.d.ts +1 -2
  72. package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
  73. package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
  74. package/dist/types/rsc/shell-capture.d.ts +151 -19
  75. package/dist/types/rsc/shell-serve.d.ts +140 -17
  76. package/dist/types/rsc/ssr-setup.d.ts +6 -6
  77. package/dist/types/rsc/types.d.ts +17 -0
  78. package/dist/types/server/context.d.ts +139 -15
  79. package/dist/types/server/cookie-store.d.ts +21 -0
  80. package/dist/types/server/handle-store.d.ts +26 -2
  81. package/dist/types/server/request-context.d.ts +182 -53
  82. package/dist/types/ssr/index.d.ts +24 -0
  83. package/dist/types/ssr/ssr-root.d.ts +9 -8
  84. package/dist/types/static-handler.d.ts +4 -1
  85. package/dist/types/testing/flight.entry.d.ts +7 -0
  86. package/dist/types/testing/generated-routes.d.ts +2 -2
  87. package/dist/types/testing/internal/context.d.ts +1 -1
  88. package/dist/types/testing/render-route.d.ts +32 -6
  89. package/dist/types/testing/run-loader.d.ts +18 -3
  90. package/dist/types/testing/serve-shell-request.d.ts +132 -0
  91. package/dist/types/testing/shell-status.d.ts +23 -10
  92. package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
  93. package/dist/types/testing/vitest.d.ts +35 -1
  94. package/dist/types/theme/ThemeScript.d.ts +3 -3
  95. package/dist/types/types/cache-types.d.ts +14 -10
  96. package/dist/types/types/handler-context.d.ts +28 -1
  97. package/dist/types/types/loader-types.d.ts +8 -6
  98. package/dist/types/urls/pattern-types.d.ts +22 -18
  99. package/dist/types/urls/response-types.d.ts +3 -12
  100. package/dist/types/use-loader.d.ts +12 -3
  101. package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
  102. package/dist/types/vite/rango.d.ts +1 -1
  103. package/dist/types/vite/router-discovery.d.ts +29 -2
  104. package/dist/vite/index.js +1420 -1348
  105. package/package.json +2 -2
  106. package/skills/api-client/SKILL.md +22 -10
  107. package/skills/breadcrumbs/SKILL.md +75 -22
  108. package/skills/bundle-analysis/SKILL.md +22 -22
  109. package/skills/cache-guide/SKILL.md +306 -124
  110. package/skills/caching/SKILL.md +530 -98
  111. package/skills/catalog.json +16 -16
  112. package/skills/client-urls/SKILL.md +65 -38
  113. package/skills/cloudflare/SKILL.md +87 -20
  114. package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
  115. package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
  116. package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
  117. package/skills/comparison/SKILL.md +5 -0
  118. package/skills/comparison/references/framework-comparison.md +75 -57
  119. package/skills/composability/SKILL.md +38 -29
  120. package/skills/css/SKILL.md +10 -13
  121. package/skills/debug-manifest/SKILL.md +74 -31
  122. package/skills/defer-hydration/SKILL.md +52 -31
  123. package/skills/deployment-caching/SKILL.md +11 -3
  124. package/skills/document-cache/SKILL.md +98 -28
  125. package/skills/fonts/SKILL.md +16 -8
  126. package/skills/handler-use/SKILL.md +55 -17
  127. package/skills/hooks/SKILL.md +28 -20
  128. package/skills/hooks/data.md +23 -3
  129. package/skills/hooks/handle-and-actions.md +34 -17
  130. package/skills/hooks/navigation.md +39 -10
  131. package/skills/hooks/outlets.md +13 -6
  132. package/skills/hooks/state.md +39 -15
  133. package/skills/hooks/urls.md +7 -5
  134. package/skills/host-router/SKILL.md +64 -12
  135. package/skills/i18n/SKILL.md +60 -34
  136. package/skills/intercept/SKILL.md +161 -26
  137. package/skills/layout/SKILL.md +106 -50
  138. package/skills/links/SKILL.md +51 -19
  139. package/skills/loader/SKILL.md +386 -128
  140. package/skills/middleware/SKILL.md +129 -26
  141. package/skills/migrate-nextjs/SKILL.md +156 -70
  142. package/skills/migrate-nextjs/backend-host-swap.md +5 -2
  143. package/skills/migrate-react-router/SKILL.md +51 -39
  144. package/skills/migrate-react-router/component-migration.md +28 -7
  145. package/skills/migrate-react-router/data-and-actions.md +21 -6
  146. package/skills/migrate-react-router/route-mapping.md +19 -10
  147. package/skills/mime-routes/SKILL.md +12 -7
  148. package/skills/observability/SKILL.md +92 -14
  149. package/skills/parallel/SKILL.md +88 -47
  150. package/skills/ppr/SKILL.md +866 -379
  151. package/skills/prerender/SKILL.md +210 -108
  152. package/skills/rango/SKILL.md +115 -65
  153. package/skills/react-compiler/SKILL.md +6 -5
  154. package/skills/response-routes/SKILL.md +133 -25
  155. package/skills/route/SKILL.md +170 -60
  156. package/skills/router-setup/SKILL.md +420 -240
  157. package/skills/scripts/SKILL.md +39 -21
  158. package/skills/server-actions/SKILL.md +231 -59
  159. package/skills/shell-manifest/SKILL.md +28 -14
  160. package/skills/streams-and-websockets/SKILL.md +32 -14
  161. package/skills/tailwind/SKILL.md +37 -33
  162. package/skills/testing/SKILL.md +73 -33
  163. package/skills/testing/cache-prerender.md +60 -33
  164. package/skills/testing/client-components.md +59 -6
  165. package/skills/testing/e2e-parity.md +12 -2
  166. package/skills/testing/flight.md +19 -11
  167. package/skills/testing/handles.md +8 -5
  168. package/skills/testing/loader.md +26 -6
  169. package/skills/testing/middleware.md +8 -3
  170. package/skills/testing/predicates.md +120 -0
  171. package/skills/testing/render-handler.md +70 -22
  172. package/skills/testing/response-routes.md +11 -4
  173. package/skills/testing/reverse-and-types.md +20 -14
  174. package/skills/testing/serve-shell-request.md +188 -0
  175. package/skills/testing/server-actions.md +12 -3
  176. package/skills/testing/server-tree.md +9 -0
  177. package/skills/testing/setup.md +9 -5
  178. package/skills/theme/SKILL.md +155 -30
  179. package/skills/typesafety/SKILL.md +20 -9
  180. package/skills/typesafety/env-and-bindings.md +137 -50
  181. package/skills/typesafety/generated-files-and-cli.md +26 -14
  182. package/skills/typesafety/params-and-search.md +44 -19
  183. package/skills/typesafety/route-types.md +50 -14
  184. package/skills/use-cache/SKILL.md +224 -83
  185. package/skills/vercel/SKILL.md +35 -13
  186. package/skills/view-transitions/SKILL.md +42 -21
  187. package/src/__augment-tests__/augmented.check.ts +26 -1
  188. package/src/browser/cookie-name.ts +23 -0
  189. package/src/browser/history-state.ts +23 -0
  190. package/src/browser/index.ts +2 -2
  191. package/src/browser/navigation-bridge.ts +3 -4
  192. package/src/browser/navigation-transaction.ts +22 -2
  193. package/src/browser/partial-update.ts +35 -25
  194. package/src/browser/react/ScrollRestoration.tsx +6 -6
  195. package/src/browser/rsc-router.tsx +6 -1
  196. package/src/browser/scroll-restoration.ts +53 -6
  197. package/src/cache/cache-exec-scope.ts +37 -4
  198. package/src/cache/cache-key-utils.ts +23 -8
  199. package/src/cache/cache-policy.ts +22 -0
  200. package/src/cache/cache-runtime.ts +264 -68
  201. package/src/cache/cache-scope.ts +419 -43
  202. package/src/cache/cache-tag.ts +375 -11
  203. package/src/cache/cf/cf-base64.ts +36 -4
  204. package/src/cache/cf/cf-cache-constants.ts +12 -0
  205. package/src/cache/cf/cf-cache-store.ts +990 -348
  206. package/src/cache/cf/cf-cache-types.ts +32 -4
  207. package/src/cache/cf/cf-shell-frame.ts +258 -0
  208. package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
  209. package/src/cache/document-cache.ts +15 -0
  210. package/src/cache/handle-capture.ts +90 -10
  211. package/src/cache/handle-snapshot.ts +133 -28
  212. package/src/cache/index.ts +2 -0
  213. package/src/cache/isolate-tag-memo.ts +308 -0
  214. package/src/cache/segment-codec.ts +26 -7
  215. package/src/cache/shell-memo.ts +341 -0
  216. package/src/cache/shell-snapshot.ts +217 -27
  217. package/src/cache/tag-invalidation.ts +108 -22
  218. package/src/cache/taint.ts +1 -1
  219. package/src/cache/types.ts +225 -44
  220. package/src/cache/vercel/vercel-cache-store.ts +545 -61
  221. package/src/client.rsc.tsx +10 -9
  222. package/src/client.tsx +5 -4
  223. package/src/components/DefaultDocument.tsx +7 -2
  224. package/src/context-var.ts +6 -5
  225. package/src/escape-script.ts +1 -1
  226. package/src/handles/MetaTags.tsx +13 -11
  227. package/src/handles/Scripts.tsx +11 -10
  228. package/src/handles/meta.ts +2 -2
  229. package/src/handles/script.ts +17 -16
  230. package/src/href-client.ts +1 -1
  231. package/src/html.ts +12 -0
  232. package/src/index.rsc.ts +5 -0
  233. package/src/index.ts +1 -0
  234. package/src/loader-store.ts +7 -4
  235. package/src/prerender/build-shell-capture.ts +73 -22
  236. package/src/reverse.ts +44 -4
  237. package/src/route-definition/dsl-helpers.ts +121 -33
  238. package/src/route-definition/helpers-types.ts +33 -9
  239. package/src/route-definition/resolve-handler-use.ts +121 -6
  240. package/src/route-types.ts +0 -3
  241. package/src/router/debug-manifest.ts +10 -2
  242. package/src/router/error-handling.ts +51 -15
  243. package/src/router/handler-context.ts +71 -28
  244. package/src/router/instrument.ts +54 -2
  245. package/src/router/intercept-resolution.ts +141 -43
  246. package/src/router/loader-resolution.ts +115 -39
  247. package/src/router/match-api.ts +40 -26
  248. package/src/router/match-handlers.ts +5 -0
  249. package/src/router/match-middleware/background-revalidation.ts +161 -96
  250. package/src/router/match-middleware/cache-lookup.ts +110 -10
  251. package/src/router/match-middleware/cache-store.ts +48 -101
  252. package/src/router/middleware-types.ts +9 -6
  253. package/src/router/middleware.ts +75 -13
  254. package/src/router/prerender-match.ts +59 -19
  255. package/src/router/route-snapshot.ts +11 -1
  256. package/src/router/router-context.ts +2 -0
  257. package/src/router/router-interfaces.ts +25 -2
  258. package/src/router/router-options.ts +8 -5
  259. package/src/router/segment-resolution/fresh.ts +62 -21
  260. package/src/router/segment-resolution/helpers.ts +4 -2
  261. package/src/router/segment-resolution/loader-cache.ts +407 -76
  262. package/src/router/segment-resolution/loader-mask.ts +12 -22
  263. package/src/router/segment-resolution/loader-snapshot.ts +208 -56
  264. package/src/router/segment-resolution/mask-nested.ts +138 -44
  265. package/src/router/segment-resolution/revalidation.ts +61 -16
  266. package/src/router/segment-wrappers.ts +4 -0
  267. package/src/rsc/full-payload.ts +25 -1
  268. package/src/rsc/handler.ts +14 -2
  269. package/src/rsc/progressive-enhancement.ts +3 -2
  270. package/src/rsc/render-pipeline.ts +3 -0
  271. package/src/rsc/response-cache-serve.ts +9 -6
  272. package/src/rsc/response-route-handler.ts +11 -3
  273. package/src/rsc/rsc-rendering.ts +608 -225
  274. package/src/rsc/shell-build-manifest.ts +27 -9
  275. package/src/rsc/shell-capture-constants.ts +73 -6
  276. package/src/rsc/shell-capture.ts +1068 -296
  277. package/src/rsc/shell-serve.ts +316 -34
  278. package/src/rsc/ssr-setup.ts +14 -8
  279. package/src/rsc/types.ts +18 -0
  280. package/src/server/context.ts +300 -32
  281. package/src/server/cookie-store.ts +87 -61
  282. package/src/server/handle-store.ts +232 -7
  283. package/src/server/request-context.ts +297 -67
  284. package/src/ssr/index.tsx +136 -44
  285. package/src/ssr/ssr-root.tsx +9 -8
  286. package/src/static-handler.ts +4 -1
  287. package/src/testing/flight-runtime.d.ts +21 -0
  288. package/src/testing/flight.entry.ts +14 -0
  289. package/src/testing/generated-routes.ts +2 -2
  290. package/src/testing/internal/context.ts +1 -1
  291. package/src/testing/internal/flight-client-globals.ts +7 -5
  292. package/src/testing/render-route.tsx +85 -24
  293. package/src/testing/run-loader.ts +68 -6
  294. package/src/testing/serve-shell-request.ts +378 -0
  295. package/src/testing/shell-status.ts +34 -12
  296. package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
  297. package/src/testing/vitest.ts +62 -1
  298. package/src/theme/ThemeProvider.tsx +7 -6
  299. package/src/theme/ThemeScript.tsx +3 -3
  300. package/src/types/cache-types.ts +14 -10
  301. package/src/types/handler-context.ts +28 -1
  302. package/src/types/loader-types.ts +8 -6
  303. package/src/urls/pattern-types.ts +22 -18
  304. package/src/urls/response-types.ts +3 -23
  305. package/src/use-loader.tsx +12 -3
  306. package/src/vite/discovery/shell-prerender-phase.ts +9 -0
  307. package/src/vite/plugins/use-cache-transform.ts +118 -74
  308. package/src/vite/rango.ts +7 -3
  309. package/src/vite/router-discovery.ts +14 -4
@@ -1,12 +1,17 @@
1
1
  ---
2
2
  name: middleware
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.
3
+ description: Define global (router.use) and route (middleware()) middleware in @rangojs/router — auth gates, logging, response headers, context variables, redirects. Use when gating routes behind auth checks, logging requests, setting headers or ctx variables before a handler runs, or deciding whether middleware wraps server actions.
4
4
  argument-hint: [middleware-name]
5
5
  ---
6
6
 
7
7
  # Middleware
8
8
 
9
- Middleware runs before/after route handlers using the onion model.
9
+ Middleware runs before and after route handlers using the onion model: code
10
+ before `await next()` runs on the way in, code after it runs on the way out
11
+ with the downstream `Response` available. This skill covers the two
12
+ registration levels (global `router.use()` and route `middleware()`), what each
13
+ wraps (actions, renders, fetchable loaders), the middleware context, and
14
+ common patterns.
10
15
 
11
16
  ## Execution Model
12
17
 
@@ -23,13 +28,15 @@ const router = createRouter<AppEnv>({})
23
28
  .routes(urlpatterns);
24
29
  ```
25
30
 
26
- When the router has a `basename`, pattern-scoped `.use()` patterns are automatically prefixed. For example, with `basename: "/app"`, `.use("/admin/*", mw)` matches `/app/admin/*`.
31
+ Scope patterns use the route pattern syntax: `:param` (typed on `ctx.params`), optional `:param?`, constrained `:locale(en|gb)`, and a trailing `*` wildcard. When the router has a `basename`, pattern-scoped `.use()` patterns are automatically prefixed. For example, with `basename: "/app"`, `.use("/admin/*", mw)` matches `/app/admin/*`.
32
+
33
+ A pattern matches the request URL. Server actions are posted to the current page's URL, but an action can be invoked through any URL that matches a route, so a pattern-scoped guard is not an authorization boundary for actions. Authorize sensitive actions inside the action body (see `/server-actions` → "Authorization in actions").
27
34
 
28
35
  ### Route middleware (`middleware()` in `urls()`)
29
36
 
30
37
  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).
31
38
 
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.
39
+ > **Implication for auth:** route middleware cannot guard server actions. Load identity in global `router.use()` middleware (it wraps actions) and check authorization inside the action body. See `/server-actions` for action-side auth patterns.
33
40
 
34
41
  ```
35
42
  Request flow (with action):
@@ -68,15 +75,19 @@ render pass — normal renders, post-action revalidation, PE re-renders — its
68
75
  variables are never stale: middleware is the safest `ctx.set` rung on the
69
76
  data-passing ladder (`/rango` → "Passing data down the tree"). But it does
70
77
  not change partial revalidation boundaries between handler/layout/parallel
71
- segments.
78
+ segments. On a PPR shell HIT no handler or layout runs; on a route `cache()`
79
+ HIT the segments inside the `cache()` boundary don't run, and those above it
80
+ do. Output that didn't run shows the values read when the shell was captured
81
+ or the entry written.
72
82
 
73
83
  For shared segment data, use named revalidation contracts on both the producer
74
84
  and consumer segments, even when middleware is present in the chain.
75
85
 
76
86
  ```typescript
87
+ import type { Revalidate } from "@rangojs/router";
77
88
  import * as CartActions from "./actions/cart";
78
89
 
79
- export const revalidateCartData = (ctx) =>
90
+ export const revalidateCartData: Revalidate = (ctx) =>
80
91
  ctx.isAction(CartActions) || undefined;
81
92
 
82
93
  layout(CartLayout, () => [
@@ -104,7 +115,7 @@ layout(CartLayout, () => [
104
115
  ]);
105
116
  ```
106
117
 
107
- Route middleware is the right place for per-route concerns that affect rendering (setting context variables for handlers, adding response headers, reading cookies set by actions). It is NOT the right place for action guards -- use global middleware for that.
118
+ Route middleware is the right place for per-route concerns that affect rendering (setting context variables for handlers, adding response headers, reading cookies set by actions). It is NOT the right place for action guards -- use global middleware to load identity and check authorization in the action body.
108
119
 
109
120
  ## Basic Middleware
110
121
 
@@ -125,6 +136,13 @@ export const authMiddleware: Middleware = async (ctx, next) => {
125
136
  };
126
137
  ```
127
138
 
139
+ Every middleware must either call `next()` or return (or throw) a `Response`.
140
+ Returning or throwing a `Response` short-circuits the chain; downstream
141
+ middleware and the handler do not run, and headers/cookies already set on the
142
+ context are merged into it. A middleware that does neither throws an error; any
143
+ other return value is ignored with a warning. `await next()` resolves to the
144
+ downstream `Response`, so `return next()` and `await next()` are both fine.
145
+
128
146
  ## Using Middleware in Routes
129
147
 
130
148
  ```typescript
@@ -132,7 +150,7 @@ import { urls } from "@rangojs/router";
132
150
  import { authMiddleware, loggerMiddleware } from "./middleware";
133
151
 
134
152
  export const urlpatterns = urls(({ path, layout, middleware }) => [
135
- // Global middleware for all routes in this file
153
+ // Route middleware for every route in this urls() tree (wraps renders, not actions)
136
154
  middleware(loggerMiddleware),
137
155
 
138
156
  // Layout with scoped middleware
@@ -192,31 +210,90 @@ middleware([authMw, loggingMw], () => [
192
210
  This creates a transparent layout (`<Outlet />`) that carries the middleware.
193
211
  The middleware does not affect sibling routes outside the callback.
194
212
 
213
+ That scope comes from the routes inside the callback. With no routes inside,
214
+ the wrapper scopes nothing: its middleware runs for every route of the
215
+ enclosing path or layout. Such a wrapper cannot contain `layout()`;
216
+ `router.routes()` throws and points to the flat form:
217
+
218
+ ```typescript
219
+ // throws at definition time
220
+ path("/account", AccountPage, { name: "account" }, () => [
221
+ middleware(requireAuth, () => [layout(<AccountNav />)]),
222
+ ]);
223
+ // same behavior, written flat
224
+ path("/account", AccountPage, { name: "account" }, () => [
225
+ middleware(requireAuth),
226
+ layout(<AccountNav />),
227
+ ]);
228
+ ```
229
+
195
230
  ## Middleware Context
196
231
 
197
232
  ```typescript
198
- export const myMiddleware: Middleware = async (ctx, next) => {
199
- // Access request
200
- ctx.request; // Request object
201
- ctx.url; // Parsed URL
202
- ctx.params; // Route parameters
203
- ctx.build; // in middleware: true only during Prerender + ppr build-shell capture (plain Prerender does not run middleware)
233
+ import { cookies, headers } from "@rangojs/router";
234
+ import type { Middleware } from "@rangojs/router";
235
+ import { FlashMessage } from "./location-states";
204
236
 
205
- // Access platform bindings (plain bindings from createRouter<TEnv>())
237
+ export const myMiddleware: Middleware = async (ctx, next) => {
238
+ // Request
239
+ ctx.request; // incoming Request (raw URL, method, body)
240
+ ctx.url; // URL with internal _rsc* params stripped (also ctx.pathname, ctx.searchParams)
241
+ ctx.params; // params from the router.use() pattern or the matched route
242
+ ctx.routeName; // matched route name (reliable after await next() in global middleware)
243
+ ctx.build; // true only during Prerender + ppr build-shell capture (plain Prerender does not run middleware)
244
+ headers().get("accept-language"); // read-only request headers (free function)
245
+ cookies().get("session")?.value; // request cookies (free function; also .set/.delete)
246
+
247
+ // Platform bindings (plain bindings from createRouter<TEnv>())
206
248
  ctx.env.DB; // D1Database
207
- ctx.env.KV; // KVNamespace
249
+ ctx.waitUntil(async () => {}); // work after the response is sent
208
250
 
209
- // Set variables for downstream handlers (typed via Rango.Vars)
251
+ // Variables for downstream middleware, handlers, and loaders (typed via Rango.Vars)
210
252
  ctx.set("user", { id: "123", name: "John" });
253
+ ctx.get("user");
254
+
255
+ // Response shaping
256
+ ctx.header("X-Frame-Options", "DENY"); // set one response header
257
+ ctx.headers; // response Headers (stub before next(), the real response after)
258
+ ctx.setLocationState(FlashMessage({ text: "Saved" })); // history state for the client
259
+ ctx.reverse("home"); // URL for a global route name (no ".name", no param auto-fill)
211
260
 
212
261
  // Opt the current request out of PPR shell lookup/capture.
213
262
  ctx.dynamic();
263
+ // Print the per-request performance timeline (see /loader → "debugPerformance").
264
+ ctx.debugPerformance();
265
+
266
+ // Continue to the next middleware / the handler
267
+ const response = await next();
268
+
269
+ // After the handler: the real Response is available
270
+ console.log(response.status);
271
+ };
272
+ ```
273
+
274
+ Cookies and request headers are not `ctx` members; use the free functions
275
+ `cookies()` and `headers()` from `@rangojs/router`.
276
+
277
+ ### Changing the response after `next()`
214
278
 
215
- // Continue to next middleware/handler
279
+ After `await next()`, `ctx.header()` and `ctx.headers` write to the real
280
+ downstream response. Returning a different `Response` replaces it.
281
+
282
+ ```typescript
283
+ export const securityHeaders: Middleware = async (ctx, next) => {
216
284
  await next();
285
+ ctx.header("Strict-Transport-Security", "max-age=63072000");
286
+ ctx.headers.set("X-Content-Type-Options", "nosniff");
287
+ };
217
288
 
218
- // After handler (response intercepting)
219
- console.log("Handler completed");
289
+ export const timing: Middleware = async (ctx, next) => {
290
+ const start = performance.now();
291
+ try {
292
+ await next();
293
+ } finally {
294
+ // try/catch around next() also sees downstream errors
295
+ console.log(`${ctx.pathname} ${(performance.now() - start).toFixed(1)}ms`);
296
+ }
220
297
  };
221
298
  ```
222
299
 
@@ -229,7 +306,8 @@ import { createVar } from "@rangojs/router";
229
306
  import type { Middleware } from "@rangojs/router";
230
307
 
231
308
  interface AuthUser { id: string; email: string; role: string }
232
- export const CurrentUser = createVar<AuthUser>();
309
+ // cache: false — per-user data must never bake into a cache() segment
310
+ export const CurrentUser = createVar<AuthUser>({ cache: false });
233
311
 
234
312
  export const authMiddleware: Middleware = async (ctx, next) => {
235
313
  const token = ctx.request.headers.get("Authorization");
@@ -241,6 +319,7 @@ export const authMiddleware: Middleware = async (ctx, next) => {
241
319
  };
242
320
 
243
321
  // In a handler -- typed read
322
+ import type { Handler } from "@rangojs/router";
244
323
  import { CurrentUser } from "./middleware";
245
324
 
246
325
  const Dashboard: Handler<"dashboard"> = (ctx) => {
@@ -253,12 +332,28 @@ This works alongside `ctx.get("key")` / `ctx.set("key", value)` (global typing
253
332
  via Rango.Vars augmentation). Use `createVar` for route-local or feature-scoped
254
333
  data; use Rango.Vars for app-wide middleware state.
255
334
 
335
+ Mark request-specific data (sessions, users, tokens) non-cacheable: either on
336
+ the token (`createVar<T>({ cache: false })`) or per write
337
+ (`ctx.set("user", user, { cache: false })`). Reading it with `ctx.get()` inside
338
+ a `cache()` boundary or a `"use cache"` function then throws instead of baking
339
+ one user's data into a shared entry (inside `"use cache"`, also through a
340
+ middleware `ctx` passed in); under `cache()` loaders can still read it because a
341
+ DSL loader re-runs on every hit (a `"use cache"` function a loader calls cannot,
342
+ and a loader bound with its own `cache()` only with a `key()`, which switches
343
+ the check off, so the key must include the value). On a `ppr` route only a
344
+ loader without `ssr: false` that no handler awaits may read it: a read the shell
345
+ capture waits for refuses the capture. A middleware `ctx` passed to a
346
+ `"use cache"` function keys the call by host, pathname, params and search, plus
347
+ the route name once the route is matched (a global middleware before `next()`
348
+ has none yet), and its `set()`, `header()` and `headers` writes throw inside the
349
+ function (`/use-cache`).
350
+
256
351
  ## Build-Time PPR Middleware
257
352
 
258
353
  Normal `Prerender` Flight payload collection does not run middleware: there is
259
354
  no request to wrap. The exception is `Prerender` + `ppr` build-shell capture.
260
- After the Flight payload exists, the shell producer replays global and route
261
- middleware for each generated URL before it captures HTML.
355
+ After the Flight payload exists, the build replays global and route middleware
356
+ for each generated URL before capturing the shell.
262
357
 
263
358
  In that build-shell pass:
264
359
 
@@ -285,12 +380,20 @@ export const commerceMiddleware: Middleware = async (ctx, next) => {
285
380
  ## Redirect with State in Middleware
286
381
 
287
382
  ```typescript
288
- import { redirect, createLocationState } from "@rangojs/router";
289
- import type { Middleware } from "@rangojs/router";
383
+ // location-states.ts — shared module; the client component that reads the
384
+ // state must import the same definition
385
+ import { createLocationState } from "@rangojs/router";
290
386
 
291
387
  export const FlashMessage = createLocationState<{ text: string }>({
292
388
  flash: true,
293
389
  });
390
+ ```
391
+
392
+ ```typescript
393
+ // middleware/auth.ts
394
+ import { redirect } from "@rangojs/router";
395
+ import type { Middleware } from "@rangojs/router";
396
+ import { FlashMessage } from "../location-states";
294
397
 
295
398
  export const requireAuthMiddleware: Middleware = async (ctx, next) => {
296
399
  const token = ctx.request.headers.get("Authorization");
@@ -400,7 +503,7 @@ import {
400
503
  } from "./middleware";
401
504
 
402
505
  export const urlpatterns = urls(({ path, layout, middleware }) => [
403
- // Global middleware
506
+ // Route middleware for every route in this tree (use router.use() to also wrap actions)
404
507
  middleware(loggerMiddleware),
405
508
  middleware(mockAuthMiddleware),
406
509