vinext 1.0.0 → 1.1.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 (263) hide show
  1. package/README.md +72 -1
  2. package/THIRD_PARTY_LICENSES.md +26 -0
  3. package/dist/build/app-page-static-eligibility.d.ts +15 -0
  4. package/dist/build/app-page-static-eligibility.js +82 -0
  5. package/dist/build/lifecycle.js +10 -10
  6. package/dist/build/pages-client-assets-module.js +6 -1
  7. package/dist/build/precompress.js +1 -1
  8. package/dist/build/prerender-paths.js +6 -85
  9. package/dist/build/prerender.d.ts +8 -1
  10. package/dist/build/prerender.js +167 -46
  11. package/dist/build/run-prerender.js +4 -3
  12. package/dist/build/server-entry.d.ts +2 -0
  13. package/dist/build/server-entry.js +7 -1
  14. package/dist/build/server-manifest.d.ts +7 -0
  15. package/dist/build/server-manifest.js +11 -1
  16. package/dist/cache/cache-adapters-virtual.d.ts +7 -1
  17. package/dist/cache/cache-adapters-virtual.js +3 -3
  18. package/dist/client/browser-globals.d.ts +4 -0
  19. package/dist/client/browser-globals.js +5 -0
  20. package/dist/client/navigation-runtime.d.ts +11 -1
  21. package/dist/client/navigation-runtime.js +3 -3
  22. package/dist/config/config-matchers.js +3 -1
  23. package/dist/config/dotenv.js +14 -3
  24. package/dist/config/next-config.d.ts +7 -0
  25. package/dist/config/next-config.js +18 -3
  26. package/dist/entries/app-rsc-entry.d.ts +2 -0
  27. package/dist/entries/app-rsc-entry.js +67 -45
  28. package/dist/index.d.ts +4 -1
  29. package/dist/index.js +200 -100
  30. package/dist/init-cloudflare.d.ts +1 -1
  31. package/dist/init-cloudflare.js +6 -6
  32. package/dist/init-platform.js +1 -1
  33. package/dist/init.js +4 -2
  34. package/dist/plugins/cache-flight-codec.d.ts +19 -0
  35. package/dist/plugins/cache-flight-codec.js +68 -0
  36. package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
  37. package/dist/plugins/commonjs-esm-facade.js +80 -0
  38. package/dist/plugins/commonjs-syntax.d.ts +16 -0
  39. package/dist/plugins/commonjs-syntax.js +22 -0
  40. package/dist/plugins/fonts.d.ts +8 -11
  41. package/dist/plugins/fonts.js +71 -34
  42. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  43. package/dist/plugins/ignore-dynamic-requests.js +54 -3
  44. package/dist/plugins/import-meta-url.js +6 -6
  45. package/dist/plugins/og-asset-ownership.d.ts +2 -0
  46. package/dist/plugins/og-asset-ownership.js +24 -13
  47. package/dist/plugins/og-assets.d.ts +18 -0
  48. package/dist/plugins/og-assets.js +50 -8
  49. package/dist/plugins/og-harfbuzz.js +38 -27
  50. package/dist/plugins/optimize-imports.js +2 -1
  51. package/dist/plugins/require-context.d.ts +1 -0
  52. package/dist/plugins/require-context.js +28 -1
  53. package/dist/plugins/scan-build-css.d.ts +12 -0
  54. package/dist/plugins/scan-build-css.js +39 -0
  55. package/dist/plugins/strip-server-exports.d.ts +2 -0
  56. package/dist/plugins/strip-server-exports.js +3 -1
  57. package/dist/plugins/transform-result.d.ts +18 -0
  58. package/dist/plugins/transform-result.js +23 -2
  59. package/dist/plugins/typeof-window.d.ts +10 -0
  60. package/dist/plugins/typeof-window.js +33 -9
  61. package/dist/routing/app-route-graph.d.ts +0 -1
  62. package/dist/routing/app-route-graph.js +2 -4
  63. package/dist/routing/app-route-ids.d.ts +3 -0
  64. package/dist/routing/app-route-ids.js +6 -0
  65. package/dist/routing/file-matcher.d.ts +1 -0
  66. package/dist/routing/file-matcher.js +1 -1
  67. package/dist/server/api-handler.js +17 -7
  68. package/dist/server/app-bfcache-id.d.ts +1 -0
  69. package/dist/server/app-bfcache-id.js +7 -1
  70. package/dist/server/app-bfcache-identity.js +1 -2
  71. package/dist/server/app-browser-entry.js +15 -9
  72. package/dist/server/app-browser-history-controller.d.ts +2 -0
  73. package/dist/server/app-browser-history-controller.js +8 -0
  74. package/dist/server/app-browser-hydration.d.ts +1 -1
  75. package/dist/server/app-browser-hydration.js +2 -2
  76. package/dist/server/app-browser-interception-context.js +26 -2
  77. package/dist/server/app-browser-navigation-controller.d.ts +7 -1
  78. package/dist/server/app-browser-navigation-controller.js +94 -11
  79. package/dist/server/app-browser-state.js +1 -1
  80. package/dist/server/app-browser-stream.d.ts +1 -1
  81. package/dist/server/app-fallback-renderer.d.ts +2 -0
  82. package/dist/server/app-fallback-renderer.js +1 -0
  83. package/dist/server/app-history-state.d.ts +3 -1
  84. package/dist/server/app-history-state.js +9 -5
  85. package/dist/server/app-middleware.js +2 -1
  86. package/dist/server/app-optimistic-routing.js +1 -1
  87. package/dist/server/app-page-boundary-render.d.ts +5 -0
  88. package/dist/server/app-page-boundary-render.js +6 -4
  89. package/dist/server/app-page-cache-finalizer.d.ts +11 -0
  90. package/dist/server/app-page-cache-finalizer.js +41 -7
  91. package/dist/server/app-page-cache-render.d.ts +18 -0
  92. package/dist/server/app-page-cache-render.js +65 -44
  93. package/dist/server/app-page-cache.d.ts +5 -0
  94. package/dist/server/app-page-cache.js +27 -7
  95. package/dist/server/app-page-dispatch.d.ts +9 -1
  96. package/dist/server/app-page-dispatch.js +47 -30
  97. package/dist/server/app-page-element-builder.d.ts +7 -0
  98. package/dist/server/app-page-element-builder.js +27 -42
  99. package/dist/server/app-page-execution.d.ts +15 -12
  100. package/dist/server/app-page-execution.js +30 -40
  101. package/dist/server/app-page-head.d.ts +5 -0
  102. package/dist/server/app-page-head.js +9 -3
  103. package/dist/server/app-page-probe.d.ts +0 -109
  104. package/dist/server/app-page-probe.js +3 -136
  105. package/dist/server/app-page-render-identity.d.ts +0 -1
  106. package/dist/server/app-page-render-identity.js +1 -1
  107. package/dist/server/app-page-render-observation.js +2 -2
  108. package/dist/server/app-page-render.d.ts +13 -5
  109. package/dist/server/app-page-render.js +219 -118
  110. package/dist/server/app-page-request.d.ts +0 -1
  111. package/dist/server/app-page-request.js +1 -2
  112. package/dist/server/app-page-response.d.ts +4 -3
  113. package/dist/server/app-page-response.js +4 -3
  114. package/dist/server/app-page-route-wiring.d.ts +17 -5
  115. package/dist/server/app-page-route-wiring.js +55 -33
  116. package/dist/server/app-page-rsc-render-status.d.ts +48 -0
  117. package/dist/server/app-page-rsc-render-status.js +54 -0
  118. package/dist/server/app-page-search-params-observation.js +1 -1
  119. package/dist/server/app-page-stream.d.ts +15 -8
  120. package/dist/server/app-page-stream.js +7 -1
  121. package/dist/server/app-page-tracing.js +2 -1
  122. package/dist/server/app-pages-bridge.js +3 -2
  123. package/dist/server/app-render-abort-error.d.ts +3 -0
  124. package/dist/server/app-render-abort-error.js +8 -0
  125. package/dist/server/app-request-stage-dispatch.js +1 -1
  126. package/dist/server/app-request-stage-independent-entry.js +8 -11
  127. package/dist/server/app-response-header-provenance.d.ts +2 -0
  128. package/dist/server/app-response-header-provenance.js +10 -4
  129. package/dist/server/app-route-handler-cache.d.ts +2 -1
  130. package/dist/server/app-route-handler-cache.js +11 -7
  131. package/dist/server/app-route-handler-dispatch.js +11 -4
  132. package/dist/server/app-route-handler-execution.d.ts +9 -1
  133. package/dist/server/app-route-handler-execution.js +28 -13
  134. package/dist/server/app-route-handler-policy.js +2 -2
  135. package/dist/server/app-route-handler-response.d.ts +1 -1
  136. package/dist/server/app-route-handler-response.js +14 -5
  137. package/dist/server/app-router-entry.d.ts +2 -1
  138. package/dist/server/app-router-entry.js +8 -12
  139. package/dist/server/app-rsc-errors.d.ts +0 -1
  140. package/dist/server/app-rsc-errors.js +2 -6
  141. package/dist/server/app-rsc-handler.d.ts +5 -0
  142. package/dist/server/app-rsc-handler.js +229 -102
  143. package/dist/server/app-rsc-request-normalization.d.ts +4 -2
  144. package/dist/server/app-rsc-request-normalization.js +7 -4
  145. package/dist/server/app-rsc-response-finalizer.js +4 -1
  146. package/dist/server/app-rsc-response-stage.d.ts +1 -1
  147. package/dist/server/app-rsc-response-stage.js +6 -4
  148. package/dist/server/app-rsc-route-matching.d.ts +9 -1
  149. package/dist/server/app-rsc-route-matching.js +37 -20
  150. package/dist/server/app-server-action-execution.d.ts +2 -1
  151. package/dist/server/app-server-action-execution.js +1 -1
  152. package/dist/server/app-ssr-entry.d.ts +3 -2
  153. package/dist/server/app-ssr-entry.js +9 -7
  154. package/dist/server/app-ssr-search-params-gate.js +1 -1
  155. package/dist/server/app-ssr-stream.d.ts +6 -1
  156. package/dist/server/app-ssr-stream.js +35 -16
  157. package/dist/server/app-worker-stages.d.ts +2 -2
  158. package/dist/server/app-worker-stages.js +3 -3
  159. package/dist/server/cache-control.js +3 -11
  160. package/dist/server/cacheability-request.js +56 -52
  161. package/dist/server/config-headers.js +3 -1
  162. package/dist/server/dev-server.js +23 -5
  163. package/dist/server/headers.d.ts +16 -0
  164. package/dist/server/headers.js +19 -1
  165. package/dist/server/http-error-responses.js +1 -0
  166. package/dist/server/image-optimization.d.ts +16 -0
  167. package/dist/server/image-optimization.js +26 -6
  168. package/dist/server/isr-cache.d.ts +2 -0
  169. package/dist/server/isr-cache.js +8 -3
  170. package/dist/server/metadata-route-response.js +94 -37
  171. package/dist/server/middleware-matcher-pattern.js +8 -4
  172. package/dist/server/middleware-response-headers.js +2 -0
  173. package/dist/server/multi-stage.d.ts +8 -0
  174. package/dist/server/navigation-planner.js +1 -1
  175. package/dist/server/node-response-signal.d.ts +16 -0
  176. package/dist/server/node-response-signal.js +26 -0
  177. package/dist/server/open-redirect.d.ts +47 -0
  178. package/dist/server/open-redirect.js +74 -1
  179. package/dist/server/pages-api-route.js +8 -2
  180. package/dist/server/pages-asset-tags.d.ts +1 -0
  181. package/dist/server/pages-asset-tags.js +73 -22
  182. package/dist/server/pages-client-assets.d.ts +2 -0
  183. package/dist/server/pages-page-data.d.ts +6 -1
  184. package/dist/server/pages-page-data.js +71 -65
  185. package/dist/server/pages-page-handler.js +50 -15
  186. package/dist/server/pages-page-response.js +3 -1
  187. package/dist/server/pages-request-pipeline.d.ts +2 -1
  188. package/dist/server/pages-request-pipeline.js +20 -5
  189. package/dist/server/pages-request-stage-entry.js +14 -8
  190. package/dist/server/prerender-manifest.d.ts +6 -0
  191. package/dist/server/prerender-manifest.js +1 -1
  192. package/dist/server/prod-server.d.ts +8 -7
  193. package/dist/server/prod-server.js +152 -78
  194. package/dist/server/request-pipeline.d.ts +20 -8
  195. package/dist/server/request-pipeline.js +21 -7
  196. package/dist/server/response-compression.d.ts +43 -0
  197. package/dist/server/response-compression.js +111 -0
  198. package/dist/server/response-stage-cacheability.js +1 -1
  199. package/dist/server/seed-cache.js +10 -7
  200. package/dist/server/socket-error-backstop.d.ts +14 -0
  201. package/dist/server/socket-error-backstop.js +27 -4
  202. package/dist/server/worker-revalidation-context.d.ts +2 -1
  203. package/dist/server/worker-revalidation-context.js +1 -0
  204. package/dist/server/workers-tracing.d.ts +17 -0
  205. package/dist/server/workers-tracing.js +48 -8
  206. package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
  207. package/dist/shims/cache-adapter-instantiate.js +118 -0
  208. package/dist/shims/cache-callable-runtime.d.ts +2 -40
  209. package/dist/shims/cache-callable-runtime.js +50 -168
  210. package/dist/shims/cache-flight-arguments.d.ts +22 -0
  211. package/dist/shims/cache-flight-arguments.js +56 -0
  212. package/dist/shims/cache-request-state.d.ts +18 -14
  213. package/dist/shims/cache-request-state.js +33 -21
  214. package/dist/shims/cache-runtime.d.ts +6 -19
  215. package/dist/shims/cache-runtime.js +168 -226
  216. package/dist/shims/cache.d.ts +3 -2
  217. package/dist/shims/cache.js +8 -5
  218. package/dist/shims/cacheability-classification.d.ts +8 -1
  219. package/dist/shims/cacheability-classification.js +2 -2
  220. package/dist/shims/cdn-cache.d.ts +10 -1
  221. package/dist/shims/cdn-cache.js +16 -9
  222. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  223. package/dist/shims/error-boundary-navigation.js +19 -1
  224. package/dist/shims/error-boundary.d.ts +10 -10
  225. package/dist/shims/error-boundary.js +26 -7
  226. package/dist/shims/error.d.ts +4 -18
  227. package/dist/shims/error.js +17 -10
  228. package/dist/shims/error.react-server.d.ts +4 -6
  229. package/dist/shims/error.react-server.js +4 -1
  230. package/dist/shims/fetch-cache.d.ts +6 -0
  231. package/dist/shims/fetch-cache.js +23 -4
  232. package/dist/shims/form.js +1 -1
  233. package/dist/shims/headers.d.ts +19 -69
  234. package/dist/shims/headers.js +82 -183
  235. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
  236. package/dist/shims/internal/app-page-props-cache-key.js +24 -15
  237. package/dist/shims/internal/cache-context-accessor.d.ts +16 -0
  238. package/dist/shims/internal/cache-context-accessor.js +15 -0
  239. package/dist/shims/internal/headers-state.d.ts +73 -0
  240. package/dist/shims/internal/headers-state.js +157 -0
  241. package/dist/shims/metadata.js +3 -3
  242. package/dist/shims/navigation-errors.d.ts +6 -0
  243. package/dist/shims/navigation-errors.js +11 -1
  244. package/dist/shims/navigation.d.ts +7 -0
  245. package/dist/shims/navigation.js +16 -6
  246. package/dist/shims/request-context.d.ts +9 -0
  247. package/dist/shims/request-state-types.d.ts +2 -1
  248. package/dist/shims/root-params.js +1 -1
  249. package/dist/shims/server.js +52 -2
  250. package/dist/shims/thenable-params.d.ts +4 -0
  251. package/dist/shims/thenable-params.js +25 -3
  252. package/dist/shims/unified-request-context.d.ts +1 -1
  253. package/dist/shims/unified-request-context.js +1 -0
  254. package/dist/utils/encode-cache-tag.d.ts +1 -0
  255. package/dist/utils/encode-cache-tag.js +11 -1
  256. package/dist/utils/mdx-scan.d.ts +5 -0
  257. package/dist/utils/mdx-scan.js +8 -1
  258. package/dist/utils/regex-safety.d.ts +10 -0
  259. package/dist/utils/regex-safety.js +70 -18
  260. package/dist/utils/vite-cli-invocation.js +8 -1
  261. package/package.json +8 -4
  262. package/dist/server/metadata-route-cache-policy.d.ts +0 -5
  263. package/dist/server/metadata-route-cache-policy.js +0 -6
@@ -1,6 +1,6 @@
1
1
  import "../utils/protocol-headers.js";
2
2
  import { isVinextRscVaryField } from "./app-rsc-vary.js";
3
- import { VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER } from "./headers.js";
3
+ import { VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
4
4
  import { isNonCacheableCacheControl } from "../shims/cdn-cache.js";
5
5
  import { CACHEABILITY_REQUEST_STATE, recordConfigCdnCachePolicyHeader } from "../shims/cacheability-classification.js";
6
6
  import { NO_STORE_CACHE_CONTROL, applyCdnResponseBuildIdentityHeaders, applyCdnResponseHeaders, hasExplicitNonCacheableResponsePolicy, isCdnResponsePolicyHeader, readCdnResponseCacheControl, readCdnResponsePolicyHeaderName } from "./cache-control.js";
@@ -348,17 +348,25 @@ async function captureCacheabilityAdmissionBody(body, deadlineAt, limit = CACHEA
348
348
  throw error;
349
349
  }
350
350
  }
351
- function responseWithCachePolicy(response, body, outcome) {
351
+ function responseWithCachePolicy(response, body, outcome, browserCacheControl, completedStatus) {
352
352
  const headers = new Headers(response.headers);
353
353
  if (typeof body === "string") headers.delete("Content-Length");
354
+ for (const [name, value] of Object.entries(completedStatus?.headers ?? {})) if (!headers.has(name)) headers.set(name, value);
354
355
  applyCdnResponseHeaders(headers, outcome?.cacheable === true && outcome.cacheControl ? {
355
356
  cacheControl: outcome.cacheControl,
356
- tags: outcome.tags
357
- } : { cacheControl: NO_STORE_CACHE_CONTROL });
357
+ tags: outcome.tags,
358
+ browserCacheControl
359
+ } : {
360
+ cacheControl: NO_STORE_CACHE_CONTROL,
361
+ browserCacheControl
362
+ });
363
+ const status = completedStatus?.status ?? response.status;
364
+ const completed = completedStatus?.status;
365
+ if (completed === 401 || completed === 403 || completed === 404) headers.set(VINEXT_SPECIAL_ERROR_STATUS_HEADER, String(completed));
358
366
  return new Response(body, {
359
367
  headers,
360
- status: response.status,
361
- statusText: response.statusText
368
+ status,
369
+ statusText: status === response.status ? response.statusText : ""
362
370
  });
363
371
  }
364
372
  async function stripSharedHtmlClientTraceMetadata(body, marker) {
@@ -367,21 +375,15 @@ async function stripSharedHtmlClientTraceMetadata(body, marker) {
367
375
  const { stripClientTraceMetadataBlock } = await import("./client-trace-metadata.js");
368
376
  return stripClientTraceMetadataBlock(html, marker);
369
377
  }
370
- function inferFinalAppPageCacheability(response, state) {
371
- if (!state.explicitConfigCachePolicy && !state.frameworkResponseCachePolicy) return null;
372
- const cacheControl = readCdnResponseCacheControl(response.headers);
373
- if (cacheControl === null || !state.explicitConfigCachePolicy && cacheControl === readCdnResponseCacheControl(state.frameworkResponseCachePolicy)) return null;
374
- if (isNonCacheableCacheControl(cacheControl)) return { cacheable: false };
375
- return {
376
- cacheable: true,
377
- cacheControl,
378
- ...state.cdnCacheTags ? { tags: state.cdnCacheTags } : {}
379
- };
380
- }
381
- function inferPagesPageCacheability(response, state) {
378
+ /** Only an explicitly authored provider policy may override framework storage. */
379
+ function explicitProviderOutcome(response, state) {
380
+ const name = readCdnResponsePolicyHeaderName(response.headers);
381
+ if (!name || name === "cache-control") return null;
382
+ const value = response.headers.get(name);
383
+ if (!(state.explicitResponseCachePolicy || state.configCdnCachePolicy?.get(name) === value || state.frameworkResponseCachePolicy && state.frameworkResponseCachePolicy.get(name) !== value) || !value) return null;
382
384
  const cacheControl = readCdnResponseCacheControl(response.headers);
383
- if (!cacheControl || isNonCacheableCacheControl(cacheControl)) return { cacheable: false };
384
- return {
385
+ if (!cacheControl) return null;
386
+ return isNonCacheableCacheControl(cacheControl) ? { cacheable: false } : {
385
387
  cacheable: true,
386
388
  cacheControl,
387
389
  ...state.cdnCacheTags ? { tags: state.cdnCacheTags } : {}
@@ -397,18 +399,17 @@ function completedRouteOutcome(response, state, rendererOutcome = state.outcome
397
399
  cacheable: false,
398
400
  reason: varyRejectionReason
399
401
  };
400
- if (state.route?.kind === "app-route") {
401
- if (response.headers.has("set-cookie")) return {
402
- cacheable: false,
403
- reason: "response sets a cookie"
404
- };
405
- return inferPagesPageCacheability(response, state);
406
- }
407
- if (state.route?.kind === "app-page") return inferFinalAppPageCacheability(response, state) ?? rendererOutcome;
408
- if (state.route?.kind !== "pages-page") return rendererOutcome;
409
- if (response.headers.has("set-cookie") || hasExplicitNonCacheableResponsePolicy(response.headers)) return { cacheable: false };
410
- const responseOutcome = inferPagesPageCacheability(response, state);
411
- return responseOutcome.cacheable ? responseOutcome : rendererOutcome ?? responseOutcome;
402
+ if (response.headers.has("set-cookie")) return {
403
+ cacheable: false,
404
+ reason: "response sets a cookie"
405
+ };
406
+ if (rendererOutcome?.dynamicUsage) return rendererOutcome;
407
+ const outcome = explicitProviderOutcome(response, state) ?? rendererOutcome;
408
+ const tags = outcome?.tags ?? rendererOutcome?.tags ?? state.cdnCacheTags;
409
+ return outcome && tags && outcome.tags !== tags ? {
410
+ ...outcome,
411
+ tags
412
+ } : outcome;
412
413
  }
413
414
  function staticToDynamicResponse(route) {
414
415
  const headers = new Headers({ "Content-Type": "text/plain; charset=utf-8" });
@@ -427,30 +428,32 @@ function cacheabilityEvaluationFailureResponse(pattern) {
427
428
  });
428
429
  }
429
430
  function hasStrictFinalResponseVeto(response, state) {
430
- if (state.finalResponseVetoReason || response.headers.has("set-cookie")) return true;
431
- return hasExplicitNonCacheableResponsePolicy(response.headers, state.frameworkResponseCachePolicy);
431
+ const providerHeaders = new Headers(response.headers);
432
+ providerHeaders.delete("Cache-Control");
433
+ return Boolean(state.finalResponseVetoReason || response.headers.has("set-cookie") || hasExplicitNonCacheableResponsePolicy(providerHeaders, state.frameworkResponseCachePolicy));
432
434
  }
433
435
  async function finalizeWorkerCacheabilityAdmission(response, state) {
434
436
  if (state.preserveResponseCachePolicy) return response;
437
+ const browserCacheControl = state.explicitResponseCachePolicy || state.configCdnCachePolicy?.has("cache-control") || state.route?.kind === "pages-api" || state.route?.kind === "pages-page" && state.outcome?.cacheable !== true ? response.headers.get("Cache-Control") ?? void 0 : void 0;
435
438
  const admission = state.admission;
436
439
  if (state.route?.kind === "app-route" || state.route?.kind === "pages-api") {
437
440
  let manifestRoute = null;
438
- const responseOutcome = inferPagesPageCacheability(response, state);
441
+ const responseOutcome = completedRouteOutcome(response, state);
439
442
  const representation = admission?.representation ? resolveCacheabilityRepresentation(admission.representation, state.route.kind) : null;
440
- const hasExplicitRuntimePolicy = state.explicitResponseCachePolicy === true || state.explicitConfigCachePolicy === true || state.route.kind === "pages-api" && responseOutcome.cacheable;
441
- if (!admission || admission.policy === "deny" || !representation || !admission.requestKey) return responseWithCachePolicy(response, response.body, null);
443
+ const hasExplicitRuntimePolicy = responseOutcome?.cacheable === true;
444
+ if (!admission || admission.policy === "deny" || !representation || !admission.requestKey) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
442
445
  if (admission.policy === "manifest" && state.route.kind === "app-route") {
443
446
  const manifest = admission.manifest;
444
447
  manifestRoute = findCacheabilityManifestRoute(manifest, state.route.kind, state.route.pattern);
445
448
  }
446
449
  const isManifestAuthorized = manifestRoute !== null && admission.routePathname !== void 0 && cacheabilityManifestRouteState(manifestRoute, admission.routePathname, representation) !== null;
447
450
  const canUseBoundedRuntimeAdmission = hasExplicitRuntimePolicy && (admission.policy === "runtime" || admission.policy === "manifest" && !isManifestAuthorized);
448
- if (!isManifestAuthorized && !canUseBoundedRuntimeAdmission || response.status >= 500 || state.credentialedRequest || state.forcedDynamicReason || hasStrictFinalResponseVeto(response, state) || cacheabilityVaryRejectionReason(response.headers, state) !== null) return responseWithCachePolicy(response, response.body, null);
451
+ if (!isManifestAuthorized && !canUseBoundedRuntimeAdmission || response.status >= 500 || state.credentialedRequest || state.forcedDynamicReason || hasStrictFinalResponseVeto(response, state) || cacheabilityVaryRejectionReason(response.headers, state) !== null) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
449
452
  const outcome = responseOutcome;
450
- if (!outcome.cacheable || !outcome.cacheControl) return responseWithCachePolicy(response, response.body, null);
451
453
  if (state.completedResponseBody) {
454
+ if (!outcome?.cacheable || !outcome.cacheControl) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
452
455
  if (!state.applyCompletedResponsePolicy) return response;
453
- return responseWithCachePolicy(response, response.body, outcome);
456
+ return responseWithCachePolicy(response, response.body, outcome, browserCacheControl);
454
457
  }
455
458
  let captured;
456
459
  try {
@@ -458,35 +461,36 @@ async function finalizeWorkerCacheabilityAdmission(response, state) {
458
461
  } catch {
459
462
  return cacheabilityEvaluationFailureResponse(state.route.pattern);
460
463
  }
461
- if (captured.kind === "fallback") return responseWithCachePolicy(response, captured.body, null);
462
- return responseWithCachePolicy(response, captured.body, outcome);
464
+ if (captured.kind === "fallback") return responseWithCachePolicy(response, captured.body, null, browserCacheControl);
465
+ return responseWithCachePolicy(response, captured.body, outcome, browserCacheControl);
463
466
  }
464
- if (!admission || admission.policy === "deny" || !admission.representation || !admission.requestKey || !state.route || response.status >= 500) return responseWithCachePolicy(response, response.body, null);
467
+ if (!admission || admission.policy === "deny" || !admission.representation || !admission.requestKey || !state.route || response.status >= 500) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
465
468
  const pageRoute = {
466
469
  kind: state.route.kind,
467
470
  pattern: state.route.pattern
468
471
  };
469
472
  const requestRepresentation = admission.representation;
470
473
  const representation = resolveCacheabilityRepresentation(requestRepresentation, pageRoute.kind);
471
- if (!cacheabilityRepresentationMatchesPageRoute(pageRoute.kind, representation)) return responseWithCachePolicy(response, response.body, null);
474
+ if (!cacheabilityRepresentationMatchesPageRoute(pageRoute.kind, representation)) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
472
475
  let manifestRoute = null;
473
476
  let manifestRouteState = null;
474
477
  if (admission.policy === "manifest") {
475
478
  const manifest = admission.manifest;
476
479
  manifestRoute = findCacheabilityManifestRoute(manifest, pageRoute.kind, pageRoute.pattern);
477
480
  manifestRouteState = admission.routePathname ? cacheabilityManifestPageState(manifest, pageRoute, requestRepresentation, admission.routePathname) : null;
478
- if (!manifestRoute || !manifestRouteState) return responseWithCachePolicy(response, response.body, null);
481
+ if (!manifestRoute || !manifestRouteState) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
479
482
  }
480
- if (state.forcedDynamicReason) return responseWithCachePolicy(response, response.body, null);
481
- if (hasStrictFinalResponseVeto(response, state)) return responseWithCachePolicy(response, response.body, null);
482
- if (cacheabilityVaryRejectionReason(response.headers, state) !== null) return responseWithCachePolicy(response, response.body, null);
483
+ if (state.forcedDynamicReason) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
484
+ if (hasStrictFinalResponseVeto(response, state)) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
485
+ if (cacheabilityVaryRejectionReason(response.headers, state) !== null) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
486
+ if (state.route.kind === "pages-page" && !state.completion && completedRouteOutcome(response, state)?.cacheable !== true) return responseWithCachePolicy(response, response.body, null, browserCacheControl);
483
487
  let captured;
484
488
  try {
485
489
  captured = await captureCacheabilityAdmissionBody(response.body, state.captureDeadlineAt, CACHEABILITY_ADMISSION_RESPONSE_BODY_LIMIT, state.captureBudget ?? isolateCaptureBudget);
486
490
  } catch {
487
491
  return cacheabilityEvaluationFailureResponse(state.route.pattern);
488
492
  }
489
- if (captured.kind === "fallback") return responseWithCachePolicy(response, captured.body, null);
493
+ if (captured.kind === "fallback") return responseWithCachePolicy(response, captured.body, null, browserCacheControl);
490
494
  const rendererOutcome = state.completion ? await state.completion : state.outcome ?? null;
491
495
  const outcome = completedRouteOutcome(response, state, rendererOutcome);
492
496
  if (outcome?.cacheable !== true || !outcome.cacheControl) {
@@ -494,12 +498,12 @@ async function finalizeWorkerCacheabilityAdmission(response, state) {
494
498
  await captured.body?.cancel().catch(() => {});
495
499
  return staticToDynamicResponse(manifestRoute);
496
500
  }
497
- return responseWithCachePolicy(response, captured.body, null);
501
+ return responseWithCachePolicy(response, captured.body, null, browserCacheControl);
498
502
  }
499
503
  const effectivePolicyHeader = readCdnResponsePolicyHeaderName(response.headers);
500
504
  const replacesRendererPolicy = outcome !== rendererOutcome && effectivePolicyHeader !== null && state.configCdnCachePolicy?.get(effectivePolicyHeader) === response.headers.get(effectivePolicyHeader);
501
- if (state.route.kind === "app-page" && !replacesRendererPolicy && rendererOutcome?.searchParamsUnread !== true) return responseWithCachePolicy(response, captured.body, null);
502
- return responseWithCachePolicy(response, representation === "html" && state.clientTraceMetadataMarker ? await stripSharedHtmlClientTraceMetadata(captured.body, state.clientTraceMetadataMarker) : captured.body, outcome);
505
+ if (state.route.kind === "app-page" && !replacesRendererPolicy && rendererOutcome?.searchParamsUnread !== true) return responseWithCachePolicy(response, captured.body, null, browserCacheControl);
506
+ return responseWithCachePolicy(response, representation === "html" && state.clientTraceMetadataMarker ? await stripSharedHtmlClientTraceMetadata(captured.body, state.clientTraceMetadataMarker) : captured.body, outcome, browserCacheControl, rendererOutcome ?? void 0);
503
507
  }
504
508
  async function finalizeWorkerCacheabilityResponse(response, ctx) {
505
509
  const state = readState(ctx);
@@ -1,4 +1,5 @@
1
1
  import { matchHeaders } from "../config/config-matchers.js";
2
+ import "./headers.js";
2
3
  import { markRouteCacheabilityConfigCdnCachePolicy, markRouteCacheabilityDynamic, markRouteCacheabilityFinalResponseUncacheable } from "../shims/cacheability-classification.js";
3
4
  import { isCdnResponsePolicyHeader, isNonCacheableCdnResponsePolicy } from "./cache-control.js";
4
5
  import { mergeVaryHeader } from "./middleware-response-headers.js";
@@ -28,7 +29,7 @@ function markExplicitConfigResponseVeto(matched) {
28
29
  continue;
29
30
  }
30
31
  if (isCdnResponsePolicyHeader(name)) markRouteCacheabilityConfigCdnCachePolicy(name, header.value);
31
- if (isCdnResponsePolicyHeader(name) && isNonCacheableCdnResponsePolicy(name, header.value)) markRouteCacheabilityFinalResponseUncacheable(`next.config headers set a non-cacheable ${header.key} policy`);
32
+ if (name !== "cache-control" && isCdnResponsePolicyHeader(name) && isNonCacheableCdnResponsePolicy(name, header.value)) markRouteCacheabilityFinalResponseUncacheable(`next.config headers set a non-cacheable ${header.key} policy`);
32
33
  }
33
34
  }
34
35
  function retainLastSingularConfigValues(matched) {
@@ -77,6 +78,7 @@ function applyConfigHeadersToResponse(responseHeaders, options) {
77
78
  if (options.recordCacheability !== false) markExplicitConfigResponseVeto(matched);
78
79
  for (const header of matched) {
79
80
  const lowerName = header.key.toLowerCase();
81
+ if (lowerName === "x-vinext-special-error-status") continue;
80
82
  if (lowerName === "link") {
81
83
  if (options.middlewareHeaders?.get(lowerName)) continue;
82
84
  const postConfigLink = options.appendToPostConfigLink ? responseHeaders.get(lowerName) : null;
@@ -21,6 +21,7 @@ import { createInlineScriptTag, createNonceAttribute, safeJsonStringify } from "
21
21
  import { applyDocumentAssetProps, extractDocumentAssetProps, markDocumentAssetPropsProtectedTags, stripDocumentAssetPropsProtectionMarkers } from "./pages-document-asset-props.js";
22
22
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
23
23
  import { getScriptNonceFromNodeHeaderSources } from "./csp.js";
24
+ import { stripViteModuleQuery } from "../utils/path.js";
24
25
  import { logRequest, now } from "./request-log.js";
25
26
  import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
26
27
  import { buildPagesReadinessNextData } from "./pages-readiness.js";
@@ -148,6 +149,15 @@ function stripDevPagesNotFoundFramingHeaders(res) {
148
149
  res.removeHeader("Transfer-Encoding");
149
150
  }
150
151
  /**
152
+ * Vite's `transformIndexHtml` treats its URL as the HTML document's path, so
153
+ * the request query carries no meaning there. Since Vite 8.3.3 it also maps
154
+ * `/?q` onto the project root directory and then watches the filesystem root
155
+ * for each inline `<style>` proxy module, so pass the bare path.
156
+ */
157
+ function toHtmlTransformPath(url) {
158
+ return stripViteModuleQuery(url);
159
+ }
160
+ /**
151
161
  * Stream a Pages Router page response using progressive SSR.
152
162
  *
153
163
  * Sends the HTML shell (head, layout, Suspense fallbacks) immediately
@@ -244,7 +254,7 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
244
254
  </body>
245
255
  </html>`;
246
256
  }
247
- let transformedShell = await server.transformIndexHtml(url, shellTemplate);
257
+ let transformedShell = await server.transformIndexHtml(toHtmlTransformPath(url), shellTemplate);
248
258
  transformedShell = stripDocumentAssetPropsProtectionMarkers(applyDocumentAssetProps(transformedShell, documentAssetProps, {
249
259
  configuredCrossOrigin: crossOrigin,
250
260
  protectedAssetMarker,
@@ -504,13 +514,17 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
504
514
  if (typeof pageModule.getStaticPaths === "function" && route.isDynamic) {
505
515
  const pathsResult = await pageModule.getStaticPaths({
506
516
  locales: i18nConfig?.locales ?? [],
507
- defaultLocale: currentDefaultLocale ?? ""
517
+ defaultLocale: i18nConfig?.defaultLocale ?? ""
508
518
  });
509
519
  const fallback = pathsResult?.fallback ?? false;
510
520
  const paths = pathsResult?.paths ?? [];
511
521
  const routePattern = patternToNextFormat(route.pattern);
512
522
  const routeParams = getPagesRouteParams(routePattern);
513
- const isValidPath = paths.some((pathEntry) => matchesPagesStaticPath(pathEntry, params, routeParams, url));
523
+ const isValidPath = paths.some((pathEntry) => matchesPagesStaticPath(pathEntry, params, routeParams, localeStrippedUrl, {
524
+ locale,
525
+ locales: i18nConfig?.locales,
526
+ defaultLocale: i18nConfig?.defaultLocale
527
+ }));
514
528
  if (fallback === false && !isValidPath && requestPreviewData === false) {
515
529
  if (isDataReq) {
516
530
  const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
@@ -745,6 +759,7 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
745
759
  }
746
760
  if ((statusCode ?? 200) === 200) dataHeaders["x-nextjs-matched-path"] = `${locale ? `/${locale}` : ""}${patternToNextFormat(route.pattern)}`;
747
761
  if (gsspExtraHeaders) for (const [k, v] of Object.entries(gsspExtraHeaders)) dataHeaders[k] = v;
762
+ dataHeaders["Cache-Control"] = DEV_PAGES_CACHE_CONTROL;
748
763
  applyDevPagesPreviewHeaders(dataHeaders, requestPreview);
749
764
  const dataRoutePattern = patternToNextFormat(route.pattern);
750
765
  if (dataRoutePattern !== "/_error" && dataRoutePattern !== "/500") {
@@ -836,7 +851,10 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
836
851
  domainLocales,
837
852
  ...serializedPagesNextData
838
853
  })}<\/script>`}\n ${createInlineScriptTag(`window.__VINEXT_PAGE_PATTERNS__=${safeJsonStringify(pagePatterns)}`, scriptNonce)}\n ${hydrationScript}`;
839
- const extraHeaders = { ...gsspExtraHeaders };
854
+ const extraHeaders = {
855
+ ...gsspExtraHeaders,
856
+ "Cache-Control": DEV_PAGES_CACHE_CONTROL
857
+ };
840
858
  if (typeof pageModule.getStaticProps === "function") {
841
859
  extraHeaders["Cache-Control"] = DEV_PAGES_CACHE_CONTROL;
842
860
  extraHeaders[NEXTJS_CACHE_HEADER] = isFallbackRender ? "MISS" : isOnDemandRevalidate ? "REVALIDATED" : "HIT";
@@ -1122,7 +1140,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
1122
1140
  ${protectedErrorScripts}
1123
1141
  </body>
1124
1142
  </html>`;
1125
- const transformedHtml = stripDocumentAssetPropsProtectionMarkers(applyDocumentAssetProps(await server.transformIndexHtml(url, html), {}, {
1143
+ const transformedHtml = stripDocumentAssetPropsProtectionMarkers(applyDocumentAssetProps(await server.transformIndexHtml(toHtmlTransformPath(url), html), {}, {
1126
1144
  configuredCrossOrigin: context.crossOrigin,
1127
1145
  protectedAssetMarker
1128
1146
  }), protectedAssetMarker);
@@ -58,12 +58,28 @@ export declare const VINEXT_PARAMS_HEADER = "X-Vinext-Params";
58
58
  export declare const VINEXT_DYNAMIC_STALE_TIME_HEADER = "X-Vinext-Dynamic-Stale-Time";
59
59
  /** Marks an RSC body carrying completion metadata after the Flight payload. */
60
60
  export declare const VINEXT_RSC_COMPLETION_METADATA_HEADER = "X-Vinext-Rsc-Completion-Metadata";
61
+ /**
62
+ * Carries the stored status of an App page RSC response whose 401, 403 or 404
63
+ * is its page's notFound(), forbidden() or unauthorized(). Middleware and
64
+ * config headers can't set it, and the request stage strips it.
65
+ */
66
+ export declare const VINEXT_SPECIAL_ERROR_STATUS_HEADER = "x-vinext-special-error-status";
61
67
  /** URL-encoded rendered path and search after middleware/config rewrites. */
62
68
  export declare const VINEXT_RENDERED_PATH_AND_SEARCH_HEADER = "X-Vinext-Rendered-Path-And-Search";
63
69
  /** Prerender-only JSON side channel carrying request cacheLife metadata. */
64
70
  export declare const VINEXT_PRERENDER_CACHE_LIFE_HEADER = "x-vinext-prerender-cache-life";
71
+ /** Prerender-only Pages marker: "0" confirms the page render used the requested URL. */
72
+ export declare const VINEXT_PRERENDER_REWRITTEN_HEADER = "x-vinext-prerender-rewritten";
65
73
  /** Marks a local prerender-server 500 that originated from a thrown render error. */
66
74
  export declare const VINEXT_PRERENDER_RENDER_ERROR_HEADER = "x-vinext-prerender-render-error";
75
+ /**
76
+ * Prerender-only marker: the response's 401, 403, 404 or redirect is its page's
77
+ * notFound(), forbidden(), unauthorized() or redirect(), which escaped the shell.
78
+ * Its value is the JSON of the headers to store: a redirect's own location, or
79
+ * `{}`. Only the prerender server sets it, from the special error the page
80
+ * recorded on its ctx, and it drops one that the response carries.
81
+ */
82
+ export declare const VINEXT_PRERENDER_SPECIAL_ERROR_HEADER = "x-vinext-prerender-special-error";
67
83
  /** Internal marker persisted only inside metadata-route APP_ROUTE cache values. */
68
84
  export declare const VINEXT_METADATA_ROUTE_CACHE_HEADER = "x-vinext-metadata-route-cache";
69
85
  /** Disabled-by-default client hint describing already-held App Router payload entries. */
@@ -58,12 +58,28 @@ const VINEXT_PARAMS_HEADER = "X-Vinext-Params";
58
58
  const VINEXT_DYNAMIC_STALE_TIME_HEADER = "X-Vinext-Dynamic-Stale-Time";
59
59
  /** Marks an RSC body carrying completion metadata after the Flight payload. */
60
60
  const VINEXT_RSC_COMPLETION_METADATA_HEADER = "X-Vinext-Rsc-Completion-Metadata";
61
+ /**
62
+ * Carries the stored status of an App page RSC response whose 401, 403 or 404
63
+ * is its page's notFound(), forbidden() or unauthorized(). Middleware and
64
+ * config headers can't set it, and the request stage strips it.
65
+ */
66
+ const VINEXT_SPECIAL_ERROR_STATUS_HEADER = "x-vinext-special-error-status";
61
67
  /** URL-encoded rendered path and search after middleware/config rewrites. */
62
68
  const VINEXT_RENDERED_PATH_AND_SEARCH_HEADER = "X-Vinext-Rendered-Path-And-Search";
63
69
  /** Prerender-only JSON side channel carrying request cacheLife metadata. */
64
70
  const VINEXT_PRERENDER_CACHE_LIFE_HEADER = "x-vinext-prerender-cache-life";
71
+ /** Prerender-only Pages marker: "0" confirms the page render used the requested URL. */
72
+ const VINEXT_PRERENDER_REWRITTEN_HEADER = "x-vinext-prerender-rewritten";
65
73
  /** Marks a local prerender-server 500 that originated from a thrown render error. */
66
74
  const VINEXT_PRERENDER_RENDER_ERROR_HEADER = "x-vinext-prerender-render-error";
75
+ /**
76
+ * Prerender-only marker: the response's 401, 403, 404 or redirect is its page's
77
+ * notFound(), forbidden(), unauthorized() or redirect(), which escaped the shell.
78
+ * Its value is the JSON of the headers to store: a redirect's own location, or
79
+ * `{}`. Only the prerender server sets it, from the special error the page
80
+ * recorded on its ctx, and it drops one that the response carries.
81
+ */
82
+ const VINEXT_PRERENDER_SPECIAL_ERROR_HEADER = "x-vinext-prerender-special-error";
67
83
  /** Internal marker persisted only inside metadata-route APP_ROUTE cache values. */
68
84
  const VINEXT_METADATA_ROUTE_CACHE_HEADER = "x-vinext-metadata-route-cache";
69
85
  /** Disabled-by-default client hint describing already-held App Router payload entries. */
@@ -161,9 +177,11 @@ const VINEXT_INTERNAL_HEADERS = [
161
177
  VINEXT_CACHEABILITY_PROBE_HEADER.toLowerCase(),
162
178
  VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER.toLowerCase(),
163
179
  VINEXT_EXPECTED_WORKER_VERSION_HEADER.toLowerCase(),
180
+ VINEXT_MW_CTX_HEADER,
164
181
  VINEXT_PRERENDER_ROUTE_PARAMS_HEADER,
165
182
  VINEXT_PRERENDER_SPECULATIVE_HEADER,
166
183
  VINEXT_PRERENDER_CACHE_LIFE_HEADER,
184
+ VINEXT_PRERENDER_REWRITTEN_HEADER,
167
185
  VINEXT_REVALIDATE_HOST_HEADER,
168
186
  VINEXT_REVALIDATED_CACHE_TAG_HEADER,
169
187
  VINEXT_TRACE_ERROR_HEADER.toLowerCase(),
@@ -171,4 +189,4 @@ const VINEXT_INTERNAL_HEADERS = [
171
189
  VINEXT_TRACE_ROUTE_HEADER.toLowerCase()
172
190
  ];
173
191
  //#endregion
174
- export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_CACHE_TAGS_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STALE_TIME_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_QUERY_PARAM, VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_EXPECTED_WORKER_VERSION_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERCEPTION_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_METADATA_ROUTE_CACHE_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_METADATA_ROUTES_PATH, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_READINESS_HEADER, VINEXT_PRERENDER_READINESS_PATH, VINEXT_PRERENDER_RENDER_ERROR_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER, VINEXT_REVALIDATE_HEADER, VINEXT_REVALIDATE_HOST_HEADER, VINEXT_RSC_COMPLETION_METADATA_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_STATE_FINGERPRINT_HEADER, VINEXT_RSC_VARY_HEADER, VINEXT_STALE_TIME_PENDING_HEADER, VINEXT_TIMING_HEADER, VINEXT_TRACE_BUFFERED_BODY_HEADER, VINEXT_TRACE_ERROR_HEADER, VINEXT_TRACE_ROUTE_HEADER, isVinextRscVaryField };
192
+ export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, MIDDLEWARE_SKIP_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_CACHE_TAGS_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STALE_TIME_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_QUERY_PARAM, VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_EXPECTED_WORKER_VERSION_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERCEPTION_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_METADATA_ROUTE_CACHE_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_METADATA_ROUTES_PATH, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_READINESS_HEADER, VINEXT_PRERENDER_READINESS_PATH, VINEXT_PRERENDER_RENDER_ERROR_HEADER, VINEXT_PRERENDER_REWRITTEN_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECIAL_ERROR_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER, VINEXT_REVALIDATE_HEADER, VINEXT_REVALIDATE_HOST_HEADER, VINEXT_RSC_COMPLETION_METADATA_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_STATE_FINGERPRINT_HEADER, VINEXT_RSC_VARY_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER, VINEXT_STALE_TIME_PENDING_HEADER, VINEXT_TIMING_HEADER, VINEXT_TRACE_BUFFERED_BODY_HEADER, VINEXT_TRACE_ERROR_HEADER, VINEXT_TRACE_ROUTE_HEADER, isVinextRscVaryField };
@@ -77,6 +77,7 @@ function notFoundStaticAssetResponse(headers) {
77
77
  responseHeaders.delete("content-length");
78
78
  responseHeaders.delete("transfer-encoding");
79
79
  responseHeaders.set("Content-Type", "text/plain; charset=utf-8");
80
+ responseHeaders.set("Cache-Control", "private, no-cache, no-store, max-age=0, must-revalidate");
80
81
  return new Response("Not Found", {
81
82
  status: 404,
82
83
  headers: responseHeaders
@@ -117,6 +117,22 @@ export declare const IMAGE_CONTENT_SECURITY_POLICY = "script-src 'none'; frame-s
117
117
  * Returns false for SVG (unless dangerouslyAllowSVG is true), HTML, or any non-image type.
118
118
  */
119
119
  export declare function isSafeImageContentType(contentType: string | null, dangerouslyAllowSVG?: boolean): boolean;
120
+ /**
121
+ * Cache state for a successful image response, sent as both `X-Nextjs-Cache`
122
+ * and `X-Vinext-Cache`.
123
+ *
124
+ * Next.js keeps optimized images in an image cache and labels each 200 with
125
+ * where the bytes came from: `MISS` when the optimizer ran for this request,
126
+ * `HIT` or `STALE` when the cache served them. vinext has no image cache on any
127
+ * runtime, so every successful response is transformed (or passed through) from
128
+ * the source for the request that receives it. Next.js behaves the same way
129
+ * when its image cache is disabled (`images.maximumDiskCacheSize: 0`): every
130
+ * 200 is a `MISS`. `HIT` and `STALE` need a cache of optimized images.
131
+ *
132
+ * Next.js sets the header after its ETag check, so a 304 and error responses
133
+ * go out without it. Only full image responses carry either header here too.
134
+ */
135
+ export declare const IMAGE_RESPONSE_CACHE_STATE = "MISS";
120
136
  /**
121
137
  * Handlers for image optimization I/O operations.
122
138
  * Workers provide these callbacks to adapt their specific bindings.
@@ -1,4 +1,5 @@
1
1
  import { badRequestResponse } from "./http-error-responses.js";
2
+ import { setCacheStateHeaders } from "./cache-headers.js";
2
3
  //#region src/server/image-optimization.ts
3
4
  /**
4
5
  * Image optimization request handler.
@@ -182,11 +183,32 @@ function setImageSecurityHeaders(headers, config) {
182
183
  headers.set("X-Content-Type-Options", "nosniff");
183
184
  headers.set("Content-Disposition", config?.contentDispositionType === "attachment" ? "attachment" : "inline");
184
185
  }
185
- function createPassthroughImageResponse(source, config) {
186
- const headers = new Headers(source.headers);
186
+ /**
187
+ * Cache state for a successful image response, sent as both `X-Nextjs-Cache`
188
+ * and `X-Vinext-Cache`.
189
+ *
190
+ * Next.js keeps optimized images in an image cache and labels each 200 with
191
+ * where the bytes came from: `MISS` when the optimizer ran for this request,
192
+ * `HIT` or `STALE` when the cache served them. vinext has no image cache on any
193
+ * runtime, so every successful response is transformed (or passed through) from
194
+ * the source for the request that receives it. Next.js behaves the same way
195
+ * when its image cache is disabled (`images.maximumDiskCacheSize: 0`): every
196
+ * 200 is a `MISS`. `HIT` and `STALE` need a cache of optimized images.
197
+ *
198
+ * Next.js sets the header after its ETag check, so a 304 and error responses
199
+ * go out without it. Only full image responses carry either header here too.
200
+ */
201
+ const IMAGE_RESPONSE_CACHE_STATE = "MISS";
202
+ /** Headers shared by every successful image response, transformed or not. */
203
+ function setImageResponseHeaders(headers, config) {
187
204
  headers.set("Cache-Control", IMAGE_CACHE_CONTROL);
188
205
  headers.set("Vary", "Accept");
189
206
  setImageSecurityHeaders(headers, config);
207
+ setCacheStateHeaders(headers, IMAGE_RESPONSE_CACHE_STATE);
208
+ }
209
+ function createPassthroughImageResponse(source, config) {
210
+ const headers = new Headers(source.headers);
211
+ setImageResponseHeaders(headers, config);
190
212
  return new Response(source.body, {
191
213
  status: 200,
192
214
  headers
@@ -216,9 +238,7 @@ async function handleImageOptimization(request, handlers, allowedWidths, imageCo
216
238
  quality
217
239
  });
218
240
  const headers = new Headers(transformed.headers);
219
- headers.set("Cache-Control", IMAGE_CACHE_CONTROL);
220
- headers.set("Vary", "Accept");
221
- setImageSecurityHeaders(headers, imageConfig);
241
+ setImageResponseHeaders(headers, imageConfig);
222
242
  if (!isSafeImageContentType(headers.get("Content-Type"), imageConfig?.dangerouslyAllowSVG)) headers.set("Content-Type", format);
223
243
  return new Response(transformed.body, {
224
244
  status: 200,
@@ -287,4 +307,4 @@ function handleConfiguredImageOptimization(request, fetchAsset, allowedWidths, i
287
307
  }, allowedWidths, imageConfig);
288
308
  }
289
309
  //#endregion
290
- export { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_CACHE_CONTROL, IMAGE_CONTENT_SECURITY_POLICY, IMAGE_OPTIMIZATION_PATH, VINEXT_IMAGE_OPTIMIZATION_PATH, getImageOptimizer, handleConfiguredImageOptimization, handleImageOptimization, isImageOptimizationPath, isSafeImageContentType, negotiateImageFormat, parseImageParams, resolveDevImageRedirect, setImageOptimizer };
310
+ export { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_CACHE_CONTROL, IMAGE_CONTENT_SECURITY_POLICY, IMAGE_OPTIMIZATION_PATH, IMAGE_RESPONSE_CACHE_STATE, VINEXT_IMAGE_OPTIMIZATION_PATH, getImageOptimizer, handleConfiguredImageOptimization, handleImageOptimization, isImageOptimizationPath, isSafeImageContentType, negotiateImageFormat, parseImageParams, resolveDevImageRedirect, setImageOptimizer };
@@ -102,6 +102,8 @@ export declare function buildAppPageCacheValue(html: string, rscData?: ArrayBuff
102
102
  * Long pathnames are hashed to stay within KV key-length limits (512 bytes).
103
103
  */
104
104
  export declare function isrCacheKey(router: string, pathname: string, buildId?: string): string;
105
+ /** Build and request time share the same locale-stripped Pages pathname identity. */
106
+ export declare function pagesIsrCacheKey(pathname: string, buildId?: string, i18nCacheVariant?: string | null): string;
105
107
  /**
106
108
  * Compute an App Router ISR key for one cache artifact.
107
109
  *
@@ -1,11 +1,12 @@
1
1
  import { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER } from "../utils/protocol-headers.js";
2
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
2
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
+ import { isInterceptionMatchedUrlPath } from "./normalize-path.js";
3
5
  import { reportRequestError } from "./instrumentation.js";
4
6
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
5
7
  import { fnv1a64 } from "../utils/hash.js";
6
8
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
7
9
  import { APP_RSC_RENDER_MODE_NAVIGATION, getRscRenderModeCacheVariant } from "./app-rsc-render-mode.js";
8
- import { normalizeAppPageInterceptionProofPathname } from "./app-page-render-identity.js";
9
10
  import { getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret } from "./revalidation-request.js";
10
11
  //#region src/server/isr-cache.ts
11
12
  /**
@@ -164,6 +165,10 @@ function buildCacheKey(prefix, pathname, suffix) {
164
165
  function isrCacheKey(router, pathname, buildId) {
165
166
  return buildCacheKey(buildId ? `${router}:${buildId}` : router, pathname);
166
167
  }
168
+ /** Build and request time share the same locale-stripped Pages pathname identity. */
169
+ function pagesIsrCacheKey(pathname, buildId, i18nCacheVariant) {
170
+ return isrCacheKey("pages:v2", normalizeCachePathname(normalizePathnameForRouteMatch(pathname)) + (i18nCacheVariant ? `::i18n=${encodeURIComponent(i18nCacheVariant)}` : ""), buildId);
171
+ }
167
172
  /**
168
173
  * Compute an App Router ISR key for one cache artifact.
169
174
  *
@@ -178,7 +183,7 @@ function appIsrHtmlKey(pathname) {
178
183
  return appIsrCacheKey(pathname, "html");
179
184
  }
180
185
  function normalizeInterceptionContextForCacheKey(interceptionContext) {
181
- return normalizeAppPageInterceptionProofPathname(interceptionContext);
186
+ return isInterceptionMatchedUrlPath(interceptionContext) ? interceptionContext : null;
182
187
  }
183
188
  /**
184
189
  * Build the ISR cache key for an RSC payload.
@@ -206,4 +211,4 @@ function appIsrRouteKey(pathname) {
206
211
  return appIsrCacheKey(pathname, pathname !== "/" && pathname.endsWith("/") ? "route:trailing-slash" : "route");
207
212
  }
208
213
  //#endregion
209
- export { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, appIsrCacheKey, appIsrHtmlKey, appIsrRouteKey, appIsrRscKey, buildAppPageCacheValue, buildPagesCacheValue, coalesceOnDemandRevalidation, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, isrCacheControl, isrCacheKey, isrGet, isrSet, isrSetPrerenderedAppPage, normalizeMountedSlotsHeader, resolveRouteExpireSeconds, triggerBackgroundRegeneration };
214
+ export { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, appIsrCacheKey, appIsrHtmlKey, appIsrRouteKey, appIsrRscKey, buildAppPageCacheValue, buildPagesCacheValue, coalesceOnDemandRevalidation, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, isrCacheControl, isrCacheKey, isrGet, isrSet, isrSetPrerenderedAppPage, normalizeMountedSlotsHeader, pagesIsrCacheKey, resolveRouteExpireSeconds, triggerBackgroundRegeneration };