@rangojs/router 0.17.0 → 0.19.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 (293) hide show
  1. package/README.md +3 -2
  2. package/dist/types/browser/cookie-name.d.ts +6 -0
  3. package/dist/types/browser/event-controller.d.ts +3 -3
  4. package/dist/types/browser/history-state.d.ts +18 -0
  5. package/dist/types/browser/navigation-transaction.d.ts +20 -2
  6. package/dist/types/browser/partial-update.d.ts +16 -1
  7. package/dist/types/browser/prefetch/cache.d.ts +6 -6
  8. package/dist/types/browser/react/Link.d.ts +19 -9
  9. package/dist/types/browser/react/context.d.ts +2 -2
  10. package/dist/types/browser/react/location-state-shared.d.ts +95 -56
  11. package/dist/types/browser/react/location-state.d.ts +1 -1
  12. package/dist/types/browser/transition-when.d.ts +80 -0
  13. package/dist/types/browser/types.d.ts +104 -9
  14. package/dist/types/build/generate-manifest.d.ts +8 -0
  15. package/dist/types/cache/background-task.d.ts +24 -2
  16. package/dist/types/cache/cache-exec-scope.d.ts +31 -0
  17. package/dist/types/cache/cache-key-utils.d.ts +48 -2
  18. package/dist/types/cache/cache-policy.d.ts +18 -1
  19. package/dist/types/cache/cache-runtime.d.ts +7 -0
  20. package/dist/types/cache/cache-scope.d.ts +192 -26
  21. package/dist/types/cache/cache-tag.d.ts +116 -11
  22. package/dist/types/cache/cf/cf-base64.d.ts +6 -0
  23. package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
  24. package/dist/types/cache/cf/cf-cache-store.d.ts +224 -72
  25. package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
  26. package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
  27. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +19 -0
  28. package/dist/types/cache/document-cache.d.ts +10 -0
  29. package/dist/types/cache/handle-snapshot.d.ts +41 -8
  30. package/dist/types/cache/index.d.ts +1 -0
  31. package/dist/types/cache/invalidation-order.d.ts +23 -0
  32. package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
  33. package/dist/types/cache/request-tag-mask.d.ts +54 -0
  34. package/dist/types/cache/shell-memo.d.ts +178 -0
  35. package/dist/types/cache/shell-snapshot.d.ts +141 -105
  36. package/dist/types/cache/tag-invalidation.d.ts +54 -3
  37. package/dist/types/cache/types.d.ts +267 -96
  38. package/dist/types/cache/vercel/vercel-cache-store.d.ts +123 -18
  39. package/dist/types/client-urls/navigation.d.ts +28 -2
  40. package/dist/types/client-urls/server-projection.d.ts +5 -2
  41. package/dist/types/client-urls/types.d.ts +5 -5
  42. package/dist/types/client.d.ts +1 -1
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.rsc.d.ts +1 -1
  45. package/dist/types/prerender/build-shell-capture.d.ts +11 -4
  46. package/dist/types/route-definition/helpers-types.d.ts +11 -11
  47. package/dist/types/route-name.d.ts +7 -0
  48. package/dist/types/router/error-handling.d.ts +1 -1
  49. package/dist/types/router/instrument.d.ts +8 -0
  50. package/dist/types/router/intercept-resolution.d.ts +2 -0
  51. package/dist/types/router/match-context.d.ts +5 -0
  52. package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
  53. package/dist/types/router/middleware-types.d.ts +6 -1
  54. package/dist/types/router/router-options.d.ts +4 -1
  55. package/dist/types/router/segment-resolution/loader-cache.d.ts +58 -12
  56. package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
  57. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +33 -48
  58. package/dist/types/router/segment-resolution/mask-nested.d.ts +73 -24
  59. package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
  60. package/dist/types/router/transition-when.d.ts +24 -10
  61. package/dist/types/rsc/attach-transition-when.d.ts +18 -0
  62. package/dist/types/rsc/full-payload.d.ts +21 -0
  63. package/dist/types/rsc/handler.d.ts +1 -1
  64. package/dist/types/rsc/response-cache-serve.d.ts +15 -12
  65. package/dist/types/rsc/shell-build-manifest.d.ts +12 -3
  66. package/dist/types/rsc/shell-capture-constants.d.ts +116 -12
  67. package/dist/types/rsc/shell-capture.d.ts +202 -74
  68. package/dist/types/rsc/shell-serve.d.ts +144 -50
  69. package/dist/types/rsc/types.d.ts +9 -0
  70. package/dist/types/segment-system.d.ts +7 -0
  71. package/dist/types/server/context.d.ts +155 -33
  72. package/dist/types/server/cookie-store.d.ts +33 -0
  73. package/dist/types/server/handle-store.d.ts +52 -1
  74. package/dist/types/server/request-context.d.ts +210 -63
  75. package/dist/types/server/request-headers.d.ts +44 -0
  76. package/dist/types/server.d.ts +1 -0
  77. package/dist/types/ssr/index.d.ts +9 -0
  78. package/dist/types/ssr/ssr-root.d.ts +9 -8
  79. package/dist/types/testing/e2e/index.d.ts +1 -1
  80. package/dist/types/testing/flight.entry.d.ts +7 -0
  81. package/dist/types/testing/index.d.ts +3 -2
  82. package/dist/types/testing/internal/action-id.d.ts +7 -0
  83. package/dist/types/testing/location-state-key.d.ts +24 -0
  84. package/dist/types/testing/render-route.d.ts +17 -1
  85. package/dist/types/testing/run-loader.d.ts +18 -3
  86. package/dist/types/testing/run-transition-when.d.ts +44 -69
  87. package/dist/types/testing/serve-shell-request.d.ts +133 -0
  88. package/dist/types/testing/shell-status.d.ts +44 -19
  89. package/dist/types/transition-when-ref.d.ts +79 -0
  90. package/dist/types/types/cache-types.d.ts +15 -3
  91. package/dist/types/types/handler-context.d.ts +14 -1
  92. package/dist/types/types/index.d.ts +1 -1
  93. package/dist/types/types/segments.d.ts +86 -71
  94. package/dist/types/urls/path-helper-types.d.ts +3 -4
  95. package/dist/types/urls/pattern-types.d.ts +21 -18
  96. package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
  97. package/dist/types/vite/router-discovery.d.ts +29 -2
  98. package/dist/vite/index.js +1005 -105
  99. package/package.json +1 -1
  100. package/skills/breadcrumbs/SKILL.md +17 -7
  101. package/skills/cache-guide/SKILL.md +175 -76
  102. package/skills/caching/SKILL.md +361 -33
  103. package/skills/catalog.json +1 -1
  104. package/skills/client-urls/SKILL.md +12 -7
  105. package/skills/cloudflare/SKILL.md +15 -0
  106. package/skills/comparison/references/framework-comparison.md +52 -37
  107. package/skills/defer-hydration/SKILL.md +50 -30
  108. package/skills/deployment-caching/SKILL.md +5 -2
  109. package/skills/document-cache/SKILL.md +32 -2
  110. package/skills/handler-use/SKILL.md +2 -0
  111. package/skills/hooks/SKILL.md +3 -1
  112. package/skills/hooks/handle-and-actions.md +3 -1
  113. package/skills/hooks/navigation.md +23 -2
  114. package/skills/hooks/state.md +101 -7
  115. package/skills/intercept/SKILL.md +29 -12
  116. package/skills/loader/SKILL.md +197 -44
  117. package/skills/middleware/SKILL.md +34 -9
  118. package/skills/migrate-nextjs/SKILL.md +68 -37
  119. package/skills/migrate-react-router/SKILL.md +2 -1
  120. package/skills/migrate-react-router/component-migration.md +3 -1
  121. package/skills/migrate-react-router/data-and-actions.md +3 -1
  122. package/skills/migrate-react-router/route-mapping.md +7 -4
  123. package/skills/observability/SKILL.md +65 -0
  124. package/skills/parallel/SKILL.md +13 -8
  125. package/skills/ppr/SKILL.md +715 -371
  126. package/skills/prerender/SKILL.md +30 -17
  127. package/skills/rango/SKILL.md +72 -34
  128. package/skills/route/SKILL.md +14 -7
  129. package/skills/router-setup/SKILL.md +4 -2
  130. package/skills/scripts/SKILL.md +8 -1
  131. package/skills/server-actions/SKILL.md +11 -0
  132. package/skills/shell-manifest/SKILL.md +21 -12
  133. package/skills/testing/SKILL.md +49 -43
  134. package/skills/testing/cache-prerender.md +15 -14
  135. package/skills/testing/client-components.md +45 -3
  136. package/skills/testing/loader.md +19 -1
  137. package/skills/testing/middleware.md +1 -0
  138. package/skills/testing/predicates.md +49 -49
  139. package/skills/testing/render-handler.md +1 -0
  140. package/skills/testing/serve-shell-request.md +202 -0
  141. package/skills/testing/server-actions.md +9 -3
  142. package/skills/theme/SKILL.md +56 -4
  143. package/skills/typesafety/env-and-bindings.md +18 -2
  144. package/skills/use-cache/SKILL.md +91 -23
  145. package/skills/vercel/SKILL.md +14 -2
  146. package/skills/view-transitions/SKILL.md +150 -29
  147. package/src/__augment-tests__/augmented.check.ts +23 -0
  148. package/src/browser/cookie-name.ts +23 -0
  149. package/src/browser/event-controller.ts +4 -4
  150. package/src/browser/history-state.ts +75 -1
  151. package/src/browser/link-interceptor.ts +4 -0
  152. package/src/browser/navigation-bridge.ts +77 -18
  153. package/src/browser/navigation-client.ts +4 -3
  154. package/src/browser/navigation-store.ts +43 -1
  155. package/src/browser/navigation-transaction.ts +31 -11
  156. package/src/browser/partial-update.ts +146 -35
  157. package/src/browser/prefetch/cache.ts +6 -6
  158. package/src/browser/prefetch/fetch.ts +2 -2
  159. package/src/browser/react/Link.tsx +38 -33
  160. package/src/browser/react/NavigationProvider.tsx +2 -2
  161. package/src/browser/react/context.ts +2 -2
  162. package/src/browser/react/location-state-shared.ts +241 -49
  163. package/src/browser/react/location-state.ts +5 -2
  164. package/src/browser/rsc-router.tsx +9 -0
  165. package/src/browser/server-action-bridge.ts +84 -15
  166. package/src/browser/transition-when.ts +205 -0
  167. package/src/browser/types.ts +124 -10
  168. package/src/build/generate-manifest.ts +77 -1
  169. package/src/cache/background-task.ts +55 -2
  170. package/src/cache/cache-exec-scope.ts +48 -1
  171. package/src/cache/cache-key-utils.ts +62 -2
  172. package/src/cache/cache-policy.ts +31 -4
  173. package/src/cache/cache-runtime.ts +209 -129
  174. package/src/cache/cache-scope.ts +573 -69
  175. package/src/cache/cache-tag.ts +475 -19
  176. package/src/cache/cf/cf-base64.ts +36 -4
  177. package/src/cache/cf/cf-cache-constants.ts +12 -0
  178. package/src/cache/cf/cf-cache-store.ts +1094 -376
  179. package/src/cache/cf/cf-cache-types.ts +32 -4
  180. package/src/cache/cf/cf-shell-frame.ts +258 -0
  181. package/src/cache/cf/cf-tag-marker-memo.ts +55 -40
  182. package/src/cache/document-cache.ts +53 -7
  183. package/src/cache/handle-snapshot.ts +53 -9
  184. package/src/cache/index.ts +2 -0
  185. package/src/cache/invalidation-order.ts +84 -0
  186. package/src/cache/isolate-tag-memo.ts +308 -0
  187. package/src/cache/request-tag-mask.ts +147 -0
  188. package/src/cache/shell-memo.ts +341 -0
  189. package/src/cache/shell-snapshot.ts +249 -277
  190. package/src/cache/tag-invalidation.ts +109 -18
  191. package/src/cache/types.ts +274 -102
  192. package/src/cache/vercel/vercel-cache-store.ts +561 -74
  193. package/src/client-urls/client-root.tsx +8 -4
  194. package/src/client-urls/client-urls.ts +8 -6
  195. package/src/client-urls/navigation.ts +55 -4
  196. package/src/client-urls/server-projection.ts +31 -10
  197. package/src/client-urls/types.ts +12 -5
  198. package/src/client.tsx +2 -0
  199. package/src/host/cookie-handler.ts +2 -1
  200. package/src/index.rsc.ts +3 -0
  201. package/src/index.ts +3 -0
  202. package/src/loader-redirect.tsx +7 -3
  203. package/src/prerender/build-shell-capture.ts +173 -110
  204. package/src/route-definition/dsl-helpers.ts +6 -3
  205. package/src/route-definition/helpers-types.ts +11 -11
  206. package/src/route-name.ts +12 -0
  207. package/src/router/content-negotiation.ts +4 -1
  208. package/src/router/error-handling.ts +5 -2
  209. package/src/router/handler-context.ts +42 -5
  210. package/src/router/instrument.ts +54 -2
  211. package/src/router/intercept-resolution.ts +30 -8
  212. package/src/router/loader-resolution.ts +89 -33
  213. package/src/router/logging.ts +5 -3
  214. package/src/router/match-api.ts +89 -42
  215. package/src/router/match-context.ts +5 -0
  216. package/src/router/match-handlers.ts +14 -29
  217. package/src/router/match-middleware/background-revalidation.ts +3 -5
  218. package/src/router/match-middleware/cache-lookup.ts +52 -19
  219. package/src/router/match-middleware/cache-store.ts +36 -10
  220. package/src/router/match-result.ts +1 -0
  221. package/src/router/middleware-types.ts +6 -1
  222. package/src/router/middleware.ts +20 -4
  223. package/src/router/navigation-snapshot.ts +6 -5
  224. package/src/router/prerender-match.ts +10 -0
  225. package/src/router/request-classification.ts +7 -4
  226. package/src/router/router-options.ts +4 -1
  227. package/src/router/segment-resolution/fresh.ts +18 -13
  228. package/src/router/segment-resolution/helpers.ts +4 -2
  229. package/src/router/segment-resolution/loader-cache.ts +366 -70
  230. package/src/router/segment-resolution/loader-mask.ts +3 -4
  231. package/src/router/segment-resolution/loader-snapshot.ts +215 -126
  232. package/src/router/segment-resolution/mask-nested.ts +161 -42
  233. package/src/router/segment-resolution/revalidation.ts +27 -13
  234. package/src/router/segment-resolution/view-transition-default.ts +6 -21
  235. package/src/router/telemetry.ts +6 -3
  236. package/src/router/transition-when.ts +34 -52
  237. package/src/router.ts +2 -1
  238. package/src/rsc/attach-transition-when.ts +47 -0
  239. package/src/rsc/full-payload.ts +47 -3
  240. package/src/rsc/handler.ts +24 -10
  241. package/src/rsc/loader-fetch.ts +2 -1
  242. package/src/rsc/manifest-init.ts +4 -0
  243. package/src/rsc/origin-guard.ts +8 -5
  244. package/src/rsc/progressive-enhancement.ts +10 -32
  245. package/src/rsc/response-cache-serve.ts +69 -78
  246. package/src/rsc/response-route-handler.ts +2 -2
  247. package/src/rsc/rsc-rendering.ts +712 -338
  248. package/src/rsc/server-action.ts +8 -20
  249. package/src/rsc/shell-build-manifest.ts +49 -29
  250. package/src/rsc/shell-capture-constants.ts +182 -12
  251. package/src/rsc/shell-capture.ts +1126 -612
  252. package/src/rsc/shell-serve.ts +331 -85
  253. package/src/rsc/ssr-setup.ts +3 -2
  254. package/src/rsc/types.ts +9 -0
  255. package/src/segment-system.tsx +40 -7
  256. package/src/server/context.ts +328 -72
  257. package/src/server/cookie-store.ts +184 -133
  258. package/src/server/handle-store.ts +245 -27
  259. package/src/server/request-context.ts +364 -100
  260. package/src/server/request-headers.ts +134 -0
  261. package/src/server.ts +4 -0
  262. package/src/ssr/index.tsx +96 -37
  263. package/src/ssr/ssr-root.tsx +9 -8
  264. package/src/testing/dispatch.ts +4 -7
  265. package/src/testing/e2e/index.ts +1 -0
  266. package/src/testing/flight.entry.ts +14 -0
  267. package/src/testing/index.ts +5 -0
  268. package/src/testing/internal/action-id.ts +25 -0
  269. package/src/testing/internal/context.ts +1 -1
  270. package/src/testing/location-state-key.ts +45 -0
  271. package/src/testing/render-handler.ts +1 -1
  272. package/src/testing/render-route.tsx +109 -16
  273. package/src/testing/run-client-revalidate.ts +3 -19
  274. package/src/testing/run-loader.ts +67 -5
  275. package/src/testing/run-transition-when.ts +109 -172
  276. package/src/testing/serve-shell-request.ts +381 -0
  277. package/src/testing/shell-status.ts +73 -47
  278. package/src/theme/ThemeProvider.tsx +7 -6
  279. package/src/transition-when-ref.ts +220 -0
  280. package/src/types/cache-types.ts +15 -3
  281. package/src/types/handler-context.ts +14 -1
  282. package/src/types/index.ts +3 -0
  283. package/src/types/segments.ts +94 -91
  284. package/src/urls/path-helper-types.ts +3 -4
  285. package/src/urls/pattern-types.ts +21 -18
  286. package/src/vite/discovery/discover-routers.ts +3 -0
  287. package/src/vite/discovery/shell-prerender-phase.ts +9 -2
  288. package/src/vite/discovery/virtual-module-codegen.ts +16 -6
  289. package/src/vite/plugins/transition-when-hoist.ts +1064 -0
  290. package/src/vite/rango.ts +2 -0
  291. package/src/vite/router-discovery.ts +89 -9
  292. package/dist/types/rsc/transition-gate.d.ts +0 -23
  293. package/src/rsc/transition-gate.ts +0 -86
@@ -13,7 +13,10 @@ import type { RscPayload } from "./types.js";
13
13
  import type { HandlerContext } from "./handler-context.js";
14
14
  import type { RequestContext } from "../server/request-context.js";
15
15
  import type { HandleStore } from "../server/handle-store.js";
16
- import { gateTransitions } from "./transition-gate.js";
16
+ import type { Theme } from "../theme/types.js";
17
+ import { documentCacheStoresRender } from "../cache/document-cache.js";
18
+ import { attachTransitionWhen } from "./attach-transition-when.js";
19
+ import { publicRouteName } from "../route-name.js";
17
20
  import { resolvedHandleStream } from "../handles/deferred-resolution.js";
18
21
 
19
22
  /**
@@ -38,11 +41,12 @@ export function buildFullPayload(
38
41
  pathname: url.pathname,
39
42
  routerId: ctx.router.id,
40
43
  basename: ctx.router.basename,
41
- segments: gateTransitions(m.segments, reqCtx, ctx.router.onError),
44
+ segments: attachTransitionWhen(m.segments, reqCtx),
42
45
  matched: m.matched,
43
46
  diff: m.diff,
44
47
  resolvedIds: m.resolvedIds,
45
48
  params: m.params,
49
+ routeName: publicRouteName(m.routeName),
46
50
  isPartial: false,
47
51
  interceptTargets: m.interceptTargets,
48
52
  rootLayout: ctx.router.rootLayout,
@@ -71,7 +75,47 @@ export function buildFullPayload(
71
75
  // entry knows whether to wrap hydration in React.StrictMode. Partial
72
76
  // (navigation) payloads omit it by design; StrictMode is decided once.
73
77
  strictMode: ctx.router.strictMode,
74
- initialTheme: reqCtx.theme,
78
+ initialTheme: payloadInitialTheme(reqCtx),
75
79
  },
76
80
  };
77
81
  }
82
+
83
+ /**
84
+ * The theme a document payload carries as `metadata.initialTheme` (the
85
+ * ThemeProvider's first state), read with no identity guard: it is the
86
+ * router's own read, not handler code (#971).
87
+ *
88
+ * A render other visitors may be served carries the no-cookie default, not
89
+ * the rendering visitor's theme: a shell capture, and a render the document
90
+ * cache runs whose response opted in before next() (documentCacheStoresRender,
91
+ * #978). The shell, its ShellCacheEntry.initialTheme and the stored document
92
+ * serve every visitor, and ThemeProvider re-syncs only from an explicitly
93
+ * stored theme, so a visitor with none kept the first visitor's
94
+ * `useTheme().theme` for the page's lifetime. A visitor with a stored theme
95
+ * gets it pre-paint (theme script) and in the provider after mount.
96
+ *
97
+ * Any other render carries the visitor's theme (the unmatched-route 404 reads
98
+ * it without this function, rsc/handler.ts); when that differs from the
99
+ * default it marks `_payloadVisitorTheme`, and the document cache does not
100
+ * store the response.
101
+ */
102
+ export function payloadInitialTheme(
103
+ reqCtx: Pick<
104
+ RequestContext<any>,
105
+ | "_themeConfig"
106
+ | "_shellCaptureRun"
107
+ | "_readTheme"
108
+ | "_documentCacheRender"
109
+ | "_payloadVisitorTheme"
110
+ | "res"
111
+ >,
112
+ ): Theme | undefined {
113
+ const config = reqCtx._themeConfig;
114
+ if (!config) return undefined;
115
+ if (reqCtx._shellCaptureRun || documentCacheStoresRender(reqCtx)) {
116
+ return config.defaultTheme;
117
+ }
118
+ const theme = reqCtx._readTheme();
119
+ if (theme !== config.defaultTheme) reqCtx._payloadVisitorTheme = true;
120
+ return theme;
121
+ }
@@ -7,6 +7,7 @@
7
7
  * and progressive enhancement (no-JS form submissions).
8
8
  */
9
9
 
10
+ import { requestHeaders } from "../server/request-headers.js";
10
11
  import { isRouteNotFoundError } from "../errors.js";
11
12
  import { matchMiddleware, executeMiddleware } from "../router/middleware.js";
12
13
  import {
@@ -85,6 +86,7 @@ import {
85
86
  ORIGIN_CHECK_PHASE_BY_MODE,
86
87
  } from "./origin-guard.js";
87
88
  import { handleRscRendering } from "./rsc-rendering.js";
89
+ import { withoutShellMissMarker } from "./shell-serve.js";
88
90
  import {
89
91
  withTimeout,
90
92
  isTimeoutEnabled,
@@ -436,10 +438,16 @@ export function createRSCHandler<
436
438
  };
437
439
 
438
440
  return async function handler(
439
- request: Request,
441
+ incomingRequest: Request,
440
442
  input: RouterRequestInput<TEnv> = {},
441
443
  ): Promise<Response> {
442
444
  const handlerStart = performance.now();
445
+ // A degraded PPR HIT's reload carries the forced-MISS marker: keep only
446
+ // the flag (set on the request context below) and drop the marker before
447
+ // anything reads the request, so middleware, handlers, loaders, cache
448
+ // keys and the SSR search seed see the URL the visitor asked for.
449
+ const unmarkedRequest = withoutShellMissMarker(incomingRequest);
450
+ const request = unmarkedRequest ?? incomingRequest;
443
451
  // Create the metrics store at handler start so handler:total has startTime=0
444
452
  // and all metrics are relative to the request entry point.
445
453
  const earlyMetricsStore = router.debugPerformance
@@ -566,6 +574,7 @@ export function createRSCHandler<
566
574
  stateCookieName: router.resolvedStateCookieName,
567
575
  version,
568
576
  });
577
+ if (unmarkedRequest) requestContext._shellForcedMiss = true;
569
578
  // Gate on the SAME enabled-semantics withTimeout uses (isTimeoutEnabled):
570
579
  // a `renderStartMs: 0` / negative opt-out disables the timeout, so the
571
580
  // driver's cursor bookkeeping (which only the timeout reads) must be off too.
@@ -662,6 +671,9 @@ export function createRSCHandler<
662
671
  // the host; it never reads or wraps response.body. A downstream throw
663
672
  // skips it entirely (no response exists to hand off).
664
673
  return observePhase(PHASES.response, (responseSpan) => {
674
+ // Header and cookie writes from here on (a streaming loader or
675
+ // render) no longer reach the response.
676
+ requestContext._responseSent = true;
665
677
  let response: Response;
666
678
  if (hasMiddleware) {
667
679
  if (
@@ -913,8 +925,10 @@ export function createRSCHandler<
913
925
  originPhase,
914
926
  );
915
927
  if (originResult) {
928
+ const origin = requestHeaders(request).get("origin");
929
+ const host = requestHeaders(request).get("host");
916
930
  const originError = new Error(
917
- `Origin check rejected: ${request.headers.get("origin") ?? "none"} vs ${request.headers.get("host") ?? "none"}`,
931
+ `Origin check rejected: ${origin ?? "none"} vs ${host ?? "none"}`,
918
932
  );
919
933
  originError.name = "OriginCheckError";
920
934
 
@@ -923,11 +937,7 @@ export function createRSCHandler<
923
937
  url,
924
938
  env,
925
939
  handledByBoundary: false,
926
- metadata: {
927
- phase: originPhase,
928
- origin: request.headers.get("origin"),
929
- host: request.headers.get("host"),
930
- },
940
+ metadata: { phase: originPhase, origin, host },
931
941
  });
932
942
 
933
943
  if (router.telemetry) {
@@ -938,8 +948,8 @@ export function createRSCHandler<
938
948
  method: request.method,
939
949
  pathname: url.pathname,
940
950
  phase: originPhase,
941
- origin: request.headers.get("origin"),
942
- host: request.headers.get("host"),
951
+ origin,
952
+ host,
943
953
  });
944
954
  }
945
955
 
@@ -1355,7 +1365,11 @@ export function createRSCHandler<
1355
1365
  themeConfig: router.themeConfig,
1356
1366
  warmupEnabled: router.warmupEnabled,
1357
1367
  strictMode: router.strictMode,
1358
- initialTheme: getRequestContext().theme,
1368
+ // The visitor's theme, not payloadInitialTheme (full-payload.ts):
1369
+ // that picks the default when middleware opted the URL into the
1370
+ // document cache before next(), but a 404 is never stored or
1371
+ // captured (#978).
1372
+ initialTheme: getRequestContext()._readTheme(),
1359
1373
  },
1360
1374
  };
1361
1375
 
@@ -11,6 +11,7 @@
11
11
  * has already extracted params from it.
12
12
  */
13
13
 
14
+ import { requestHeaders } from "../server/request-headers.js";
14
15
  import { getLoaderLazy } from "../server/loader-registry.js";
15
16
  import { isDataNotFoundError } from "../errors.js";
16
17
  import { executeLoaderMiddleware } from "../router/middleware.js";
@@ -144,7 +145,7 @@ export async function handleLoaderFetch<TEnv>(
144
145
 
145
146
  if (isBodyMethod) {
146
147
  try {
147
- const contentType = request.headers.get("content-type") || "";
148
+ const contentType = requestHeaders(request).get("content-type") || "";
148
149
  if (contentType.includes("multipart/form-data")) {
149
150
  // FormData body — sent by load() when body is a FormData instance.
150
151
  // Preserves File objects and binary data.
@@ -14,6 +14,7 @@ import {
14
14
  setRouterPrecomputedEntries,
15
15
  } from "../route-map-builder.js";
16
16
  import { mergeFullManifests } from "../build/merge-full-manifests.js";
17
+ import { isTransitionWhenValidationEnabled } from "../transition-when-ref.js";
17
18
 
18
19
  /**
19
20
  * Build a fresh route trie from the router's URL-pattern mounts and store it in
@@ -49,6 +50,9 @@ export async function buildRouterTrieFromUrlpatterns(
49
50
  await generateManifestFull(mount.patterns, mount.mountIndex, {
50
51
  routerId: router.id,
51
52
  ...(router.basename ? { urlPrefix: router.basename } : {}),
53
+ // Under the Vite plugin the realm validates like discovery does, so
54
+ // a Cloudflare dev rebuild fails on an invalid when too.
55
+ validateTransitionWhen: isTransitionWhenValidationEnabled(),
52
56
  }),
53
57
  );
54
58
  }
@@ -9,6 +9,7 @@
9
9
  * navigations, bookmarks, and non-browser clients don't send Origin.
10
10
  */
11
11
 
12
+ import { requestHeaders } from "../server/request-headers.js";
12
13
  import type { RequestPlan } from "../router/request-classification.js";
13
14
 
14
15
  /**
@@ -69,10 +70,11 @@ export type OriginCheckConfig<TEnv = any> =
69
70
  * Returns true to allow, false to reject.
70
71
  */
71
72
  export function defaultOriginCheck(request: Request, url: URL): boolean {
72
- let requestOrigin = request.headers.get("origin");
73
+ const headers = requestHeaders(request);
74
+ let requestOrigin = headers.get("origin");
73
75
 
74
76
  if (!requestOrigin) {
75
- const referer = request.headers.get("referer");
77
+ const referer = headers.get("referer");
76
78
  if (referer) {
77
79
  try {
78
80
  requestOrigin = new URL(referer).origin;
@@ -92,7 +94,7 @@ export function defaultOriginCheck(request: Request, url: URL): boolean {
92
94
  // :authority), so a missing Host here is anomalous. Fail closed rather than
93
95
  // fall back to url.host (derived from the request line) when the trusted Host
94
96
  // cannot be established.
95
- const expectedHost = request.headers.get("host");
97
+ const expectedHost = headers.get("host");
96
98
  if (!expectedHost) return false;
97
99
 
98
100
  const expectedOrigin = `${url.protocol}//${expectedHost}`;
@@ -102,11 +104,12 @@ export function defaultOriginCheck(request: Request, url: URL): boolean {
102
104
 
103
105
  function createForbiddenResponse(request: Request): Response {
104
106
  const isDev = process.env.NODE_ENV !== "production";
107
+ const headers = requestHeaders(request);
105
108
  const body = isDev
106
109
  ? "Forbidden: Origin mismatch. The request origin does not match the server host. " +
107
110
  `Set originCheck: false in createRouter() to disable this check. ` +
108
- `(Origin: ${request.headers.get("origin") ?? "none"}, ` +
109
- `Host: ${request.headers.get("host") ?? "none"})`
111
+ `(Origin: ${headers.get("origin") ?? "none"}, ` +
112
+ `Host: ${headers.get("host") ?? "none"})`
110
113
  : "Forbidden";
111
114
 
112
115
  return new Response(body, {
@@ -6,6 +6,7 @@
6
6
  * reference. We detect these and return HTML instead of RSC stream.
7
7
  */
8
8
 
9
+ import { requestHeaders } from "../server/request-headers.js";
9
10
  import {
10
11
  getRequestContext,
11
12
  setRequestContextParams,
@@ -14,7 +15,8 @@ import { createSsrHtmlStage } from "./ssr-setup.js";
14
15
  import type { MiddlewareFn } from "../router/middleware.js";
15
16
  import { executeMiddleware } from "../router/middleware.js";
16
17
  import { observePhase, PHASES } from "../router/instrument.js";
17
- import { gateTransitions } from "./transition-gate.js";
18
+ import { attachTransitionWhen } from "./attach-transition-when.js";
19
+ import { payloadInitialTheme } from "./full-payload.js";
18
20
  import { resolvedHandleStream } from "../handles/deferred-resolution.js";
19
21
  import type { RscPayload, ReactFormState } from "./types.js";
20
22
  import {
@@ -63,7 +65,7 @@ export async function handleProgressiveEnhancement<TEnv>(
63
65
  nonce: string | undefined,
64
66
  routeMwInfo?: PeRouteMiddlewareInfo,
65
67
  ): Promise<Response | null> {
66
- const contentType = request.headers.get("content-type") || "";
68
+ const contentType = requestHeaders(request).get("content-type") || "";
67
69
  const isFormSubmission =
68
70
  contentType.includes("multipart/form-data") ||
69
71
  contentType.includes("application/x-www-form-urlencoded");
@@ -311,7 +313,7 @@ async function handleProgressiveEnhancementInner<TEnv>(
311
313
  // custom headers) so loaders that read request headers/cookies behave
312
314
  // identically under PE and the JS action path. Drop body-framing headers
313
315
  // from the bodyless GET and force the HTML accept.
314
- const headers = new Headers(request.headers);
316
+ const headers = new Headers(requestHeaders(request));
315
317
  headers.delete("content-type");
316
318
  headers.delete("content-length");
317
319
  headers.delete("content-encoding");
@@ -325,15 +327,9 @@ async function handleProgressiveEnhancementInner<TEnv>(
325
327
  // JS/PE parity: this is an action's revalidation render, so mark it BEFORE
326
328
  // matching — a stale `foregroundOnAction` cache entry must re-execute in the
327
329
  // foreground during the re-render, exactly as the JS path's
328
- // revalidateAfterAction does. PPR transition({ when }) runs during match,
329
- // while foregroundOnAction reads _inActionRevalidation there too, so all
330
- // action metadata must be available before matching.
330
+ // revalidateAfterAction does.
331
331
  const peReqCtx = getRequestContext();
332
332
  peReqCtx._inActionRevalidation = true;
333
- peReqCtx._gateActionId = directActionId ?? undefined;
334
- peReqCtx._gateActionUrl = new URL(url);
335
- peReqCtx._gateActionResult = actionResult;
336
- peReqCtx._gateFormData = formData;
337
333
 
338
334
  return runRoutine(
339
335
  peRenderPlan({
@@ -426,11 +422,7 @@ function renderPeResponse<TEnv>(
426
422
  pathname: url.pathname,
427
423
  routerId: ctx.router.id,
428
424
  basename: ctx.router.basename,
429
- segments: gateTransitions(
430
- match.segments,
431
- getRequestContext(),
432
- ctx.router.onError,
433
- ),
425
+ segments: attachTransitionWhen(match.segments, getRequestContext()),
434
426
  matched: match.matched,
435
427
  diff: match.diff,
436
428
  resolvedIds: match.resolvedIds,
@@ -444,7 +436,7 @@ function renderPeResponse<TEnv>(
444
436
  themeConfig: ctx.router.themeConfig,
445
437
  warmupEnabled: ctx.router.warmupEnabled,
446
438
  strictMode: ctx.router.strictMode,
447
- initialTheme: getRequestContext().theme,
439
+ initialTheme: payloadInitialTheme(getRequestContext()),
448
440
  },
449
441
  };
450
442
 
@@ -602,16 +594,6 @@ async function matchPeErrorBoundary<TEnv>(
602
594
 
603
595
  setRequestContextParams(errorResult.params, errorResult.routeName);
604
596
 
605
- // Only the failing action id + URL are in scope here (no formData/actionResult
606
- // thread into this helper). Expose the URL only when the action id is known:
607
- // this helper also handles malformed form bodies before action detection, and
608
- // those should not look like action-triggered renders to transition({ when }).
609
- if (actionId != null) {
610
- const peErrCtx = getRequestContext();
611
- peErrCtx._gateActionId = actionId;
612
- peErrCtx._gateActionUrl = new URL(url);
613
- }
614
-
615
597
  return errorResult;
616
598
  }
617
599
 
@@ -627,11 +609,7 @@ function renderPeErrorResponse<TEnv>(
627
609
  pathname: url.pathname,
628
610
  routerId: ctx.router.id,
629
611
  basename: ctx.router.basename,
630
- segments: gateTransitions(
631
- errorResult.segments,
632
- getRequestContext(),
633
- ctx.router.onError,
634
- ),
612
+ segments: attachTransitionWhen(errorResult.segments, getRequestContext()),
635
613
  matched: errorResult.matched,
636
614
  diff: errorResult.diff,
637
615
  resolvedIds: errorResult.resolvedIds,
@@ -646,7 +624,7 @@ function renderPeErrorResponse<TEnv>(
646
624
  themeConfig: ctx.router.themeConfig,
647
625
  warmupEnabled: ctx.router.warmupEnabled,
648
626
  strictMode: ctx.router.strictMode,
649
- initialTheme: getRequestContext().theme,
627
+ initialTheme: payloadInitialTheme(getRequestContext()),
650
628
  },
651
629
  };
652
630
 
@@ -3,24 +3,27 @@
3
3
  *
4
4
  * Owns the single response-cache contract — cache-scope resolution from the
5
5
  * matched entry tree, condition eval, key resolution (route key() > store
6
- * keyGenerator > default), tag resolution, pre-handler-callback timing, and the
7
- * fresh-hit / SWR-revalidate / miss-write branches — for BOTH the production
6
+ * keyGenerator > default, CacheScope.resolveKeyFrom), tag resolution,
7
+ * pre-handler-callback timing, and the fresh-hit / SWR-revalidate /
8
+ * miss-write branches — for BOTH the production
8
9
  * response-route handler (rsc/response-route-handler.ts) and the dispatch testing
9
10
  * primitive (testing/dispatch.ts), so the two can never drift.
10
11
  *
11
12
  * Plugin-rsc hazard: cache-scope.ts pulls @vitejs/plugin-rsc (via segment-codec),
12
13
  * which the non-Vite unit-test runner cannot resolve, and this module is on the
13
- * testing barrel's EAGER graph (dispatch imports it). So `createCacheScope` and
14
- * `resolveCacheTags` are NOT imported here at runtime — they are INJECTED by the
15
- * caller (production imports them statically; dispatch lazy-imports them only once
16
- * a response route matches). The only runtime imports here are plugin-rsc-free
14
+ * testing barrel's EAGER graph (dispatch imports it). So `createCacheScope` is
15
+ * NOT imported here at runtime — it is INJECTED by the caller (production
16
+ * imports it statically; dispatch lazy-imports it only once a response route
17
+ * matches). The only runtime imports here are plugin-rsc-free
17
18
  * (helpers' isCacheableStatus/finalizeResponse, traverseBack); cache-scope is a
18
19
  * type-only import (erased at build).
19
20
  */
20
21
 
21
22
  import type { CacheScope } from "../cache/cache-scope.js";
22
- import type { PartialCacheOptions } from "../types.js";
23
- import type { RequestContext } from "../server/request-context.js";
23
+ import {
24
+ _getRequestContext,
25
+ type RequestContext,
26
+ } from "../server/request-context.js";
24
27
  import type { SegmentCacheStore } from "../cache/types.js";
25
28
  import type { EntryCacheConfig, EntryData } from "../server/context.js";
26
29
  import { traverseBack } from "../router/pattern-matching.js";
@@ -31,18 +34,19 @@ import {
31
34
  } from "./helpers.js";
32
35
  import { reportCacheError } from "../cache/cache-error.js";
33
36
  import { cacheKeyBase } from "../cache/cache-key-utils.js";
37
+ import {
38
+ executionStart,
39
+ predatesInvalidation,
40
+ type ExecutionStart,
41
+ } from "../cache/tag-invalidation.js";
34
42
  import { hasPerClientSignal } from "../browser/cookie-name.js";
35
43
 
36
- /** Injected cache-scope builders (kept off this module's runtime import graph). */
44
+ /** Injected cache-scope builder (kept off this module's runtime import graph). */
37
45
  export interface CacheScopeDeps {
38
46
  createCacheScope: (
39
47
  config: EntryCacheConfig | undefined,
40
48
  parent?: CacheScope | null,
41
49
  ) => CacheScope | null;
42
- resolveCacheTags: (
43
- config: PartialCacheOptions | false,
44
- ctx: RequestContext | undefined,
45
- ) => string[] | undefined;
46
50
  }
47
51
 
48
52
  export interface ServeResponseRouteWithCacheArgs {
@@ -60,8 +64,12 @@ export interface ServeResponseRouteWithCacheArgs {
60
64
  * applies (no scope, disabled, condition false, or store lacks get/putResponse)
61
65
  * so the caller falls through to a plain `executeHandler()` run.
62
66
  *
63
- * Must run inside runWithRequestContext (reads the ambient request context via
64
- * the helpers and reqCtx.waitUntil for background writes).
67
+ * Must run inside runWithRequestContext for `reqCtx` (reads the ambient
68
+ * request context via the helpers and reqCtx.waitUntil for background writes).
69
+ * Outside it, the route runs uncached: the scope resolves `key()`, a store
70
+ * keyGenerator and `condition()` against the ambient context, and without
71
+ * it a keyGenerator was skipped and the entry landed on the broad default
72
+ * key.
65
73
  */
66
74
  export async function serveResponseRouteWithCache(
67
75
  args: ServeResponseRouteWithCacheArgs,
@@ -75,6 +83,7 @@ export async function serveResponseRouteWithCache(
75
83
  if (method !== "GET" && method !== "HEAD") {
76
84
  return undefined;
77
85
  }
86
+ if (_getRequestContext() !== reqCtx) return undefined;
78
87
 
79
88
  let cacheScope: CacheScope | null = null;
80
89
  for (const entry of traverseBack(manifestEntry)) {
@@ -83,20 +92,12 @@ export async function serveResponseRouteWithCache(
83
92
  }
84
93
  }
85
94
 
86
- if (!cacheScope?.enabled) return undefined;
87
-
88
- // Evaluate condition — skip the response cache when condition returns false.
89
- let conditionPassed = true;
90
- if (cacheScope.config !== false && cacheScope.config.condition) {
91
- try {
92
- conditionPassed = !!cacheScope.config.condition(reqCtx);
93
- } catch {
94
- conditionPassed = false;
95
- }
96
- }
95
+ // Skip the response cache when a condition() of the scope, or of any
96
+ // cache() enclosing it (#974), refuses this request.
97
+ if (!cacheScope?.allowsCache("read")) return undefined;
97
98
 
98
99
  const store = cacheScope.getStore() ?? reqCtx._cacheStore;
99
- if (!conditionPassed || !store?.getResponse || !store?.putResponse) {
100
+ if (!store?.getResponse || !store?.putResponse) {
100
101
  return undefined;
101
102
  }
102
103
 
@@ -105,8 +106,12 @@ export async function serveResponseRouteWithCache(
105
106
  // the host-namespacing and search-normalization rules cannot drift.
106
107
  let cacheKey = `response:${responseType}:${cacheKeyBase(url.host, url.pathname, url.searchParams, undefined, reqCtx._searchParamsFilter)}`;
107
108
 
108
- // Priority 1: route-level key() (full override). Priority 2: store-level
109
- // keyGenerator (modifies the default key).
109
+ // Keyed like the segment record (CacheScope.resolveKeyFrom): with key()
110
+ // results on the cache() chain (a full override, namespaced, #975) or an
111
+ // enclosing scope on another store whose keyGenerator partitions (#974),
112
+ // `response:` plus the composed key, so a nested cache() never shares an
113
+ // entry across the enclosing partitions (#970); otherwise the store's
114
+ // keyGenerator result (it modifies the default key), else the default key.
110
115
  //
111
116
  // A CONFIGURED key()/keyGenerator that THROWS must DEGRADE TO A MISS, not fall
112
117
  // back to the broad default key. The default key is intentionally broad; if the
@@ -114,46 +119,27 @@ export async function serveResponseRouteWithCache(
114
119
  // would cache PERSONALIZED output under it and serve it cross-user (cache
115
120
  // poisoning). Mirrors the segment-cache behavior (cache-scope.ts lookupRoute):
116
121
  // a throwing key degrades to a cache miss, never a collision onto the default
117
- // slot. The no-key default path is left untouched (the broad key is correct
118
- // when no key is configured).
119
- let keyResolutionFailed = false;
120
- if (cacheScope.config !== false && cacheScope.config.key) {
121
- try {
122
- const customKey = await cacheScope.config.key(reqCtx);
123
- cacheKey = `response:${customKey}`;
124
- } catch (error) {
125
- keyResolutionFailed = true;
126
- reportCacheError(
127
- error,
128
- "cache-read",
129
- "[ResponseCache] Key resolution failed",
130
- reqCtx,
131
- );
132
- }
133
- } else if (store.keyGenerator) {
134
- try {
135
- cacheKey = await store.keyGenerator(reqCtx, cacheKey);
136
- } catch (error) {
137
- keyResolutionFailed = true;
138
- reportCacheError(
139
- error,
140
- "cache-read",
141
- "[ResponseCache] keyGenerator failed",
142
- reqCtx,
143
- );
144
- }
145
- }
146
-
147
- // Degrade to a MISS: return undefined so the caller runs the route UNCACHED.
148
- // This early-returns BEFORE _onResponseCallbacks is saved/cleared below, so the
149
- // pre-handler onResponse callbacks are still intact for the uncached run.
150
- if (keyResolutionFailed) {
122
+ // slot, and so does a key() with no ambient request context to run in
123
+ // (resolveKeyFrom rejects).
124
+ try {
125
+ cacheKey = await cacheScope.resolveKeyFrom(cacheKey, "response:");
126
+ } catch (error) {
127
+ reportCacheError(
128
+ error,
129
+ "cache-read",
130
+ "[ResponseCache] Key resolution failed",
131
+ reqCtx,
132
+ );
133
+ // Degrade to a MISS: the caller runs the route UNCACHED. This returns
134
+ // BEFORE _onResponseCallbacks is saved/cleared below, so the pre-handler
135
+ // onResponse callbacks are still intact for the uncached run.
151
136
  return undefined;
152
137
  }
153
138
 
154
- // Resolve cache tags for this document entry (static or dynamic) while the
155
- // request context is available, so the stored entry is tag-invalidatable.
156
- const responseTags = deps.resolveCacheTags(cacheScope.config, reqCtx);
139
+ // Resolve cache tags for this entry (static or dynamic, the enclosing
140
+ // scopes' included, #974) while the request context is available, so the
141
+ // stored entry is tag-invalidatable.
142
+ const responseTags = cacheScope.resolveTags(reqCtx);
157
143
 
158
144
  // Pre-handler callbacks (registered by app-level middleware before the cache
159
145
  // block) are saved and the live array is cleared:
@@ -180,17 +166,26 @@ export async function serveResponseRouteWithCache(
180
166
  const canServeCached = (response: Response): boolean =>
181
167
  isCacheableStatus(response.status) && !hasPerClientSignal(response.headers);
182
168
 
183
- const putFresh = (
169
+ // A handler run that started before one of the entry's tags was
170
+ // invalidated is not written (#977, predatesInvalidation).
171
+ const putFresh = async (
184
172
  store2: SegmentCacheStore,
185
173
  fresh: Response,
186
- ): Promise<void> =>
187
- store2.putResponse!(
174
+ start: ExecutionStart,
175
+ ): Promise<void> => {
176
+ if (await predatesInvalidation(store2, responseTags, start)) {
177
+ // Nothing reads the copy now: release it (a tee branch buffers).
178
+ await fresh.body?.cancel();
179
+ return;
180
+ }
181
+ await store2.putResponse!(
188
182
  cacheKey,
189
- fresh.clone(),
183
+ fresh,
190
184
  cacheScope!.ttl,
191
185
  cacheScope!.swr,
192
186
  responseTags,
193
187
  );
188
+ };
194
189
 
195
190
  try {
196
191
  const cached = await store.getResponse(cacheKey);
@@ -201,8 +196,9 @@ export async function serveResponseRouteWithCache(
201
196
  // Stale hit (SWR): return cached, revalidate in background.
202
197
  reqCtx.waitUntil(async () => {
203
198
  try {
199
+ const start = executionStart();
204
200
  const fresh = finalizeResponse(await executeHandler());
205
- if (canStore(fresh)) await putFresh(store, fresh);
201
+ if (canStore(fresh)) await putFresh(store, fresh, start);
206
202
  } catch (error) {
207
203
  reportCacheError(
208
204
  error,
@@ -224,6 +220,7 @@ export async function serveResponseRouteWithCache(
224
220
  }
225
221
 
226
222
  // Cache miss: execute the handler and cache the result when storeable.
223
+ const start = executionStart();
227
224
  const response = finalizeResponse(await executeHandler());
228
225
  if (canStore(response)) {
229
226
  // Clone SYNCHRONOUSLY here, before returning. The original `response` is
@@ -238,13 +235,7 @@ export async function serveResponseRouteWithCache(
238
235
  const toCache = response.clone();
239
236
  reqCtx.waitUntil(async () => {
240
237
  try {
241
- await store.putResponse!(
242
- cacheKey,
243
- toCache,
244
- cacheScope!.ttl,
245
- cacheScope!.swr,
246
- responseTags,
247
- );
238
+ await putFresh(store, toCache, start);
248
239
  } catch (error) {
249
240
  reportCacheError(
250
241
  error,
@@ -11,7 +11,7 @@ import { getRequestContext } from "../server/request-context.js";
11
11
  import { contextGet, isNonCacheable } from "../context-var.js";
12
12
  import { NOCACHE_SYMBOL } from "../cache/taint.js";
13
13
  import { RESPONSE_TYPE_MIME } from "../router/content-negotiation.js";
14
- import { createCacheScope, resolveCacheTags } from "../cache/cache-scope.js";
14
+ import { createCacheScope } from "../cache/cache-scope.js";
15
15
  import { serveResponseRouteWithCache } from "./response-cache-serve.js";
16
16
  import { executeMiddleware } from "../router/middleware.js";
17
17
  import {
@@ -220,7 +220,7 @@ export async function handleResponseRoute<TEnv>(
220
220
  responseType: preview.responseType,
221
221
  url,
222
222
  executeHandler,
223
- deps: { createCacheScope, resolveCacheTags },
223
+ deps: { createCacheScope },
224
224
  });
225
225
  if (cached !== undefined) return cached;
226
226
  }