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
@@ -13,12 +13,73 @@ import { getPagesClientAssets } from "./pages-client-assets.js";
13
13
  * unit-testable and lives in a normal typed module rather than a codegen
14
14
  * template string.
15
15
  */
16
+ const nonEmptyManifests = /* @__PURE__ */ new WeakMap();
17
+ const moduleKeyOrder = /* @__PURE__ */ new WeakMap();
18
+ const sharedChunkFiles = /* @__PURE__ */ new WeakMap();
19
+ const lazyChunkSets = /* @__PURE__ */ new WeakMap();
20
+ function findModuleKey(manifest, moduleId) {
21
+ if (manifest[moduleId]) return moduleId;
22
+ let uniqueKey = null;
23
+ let candidate = moduleId;
24
+ while (true) {
25
+ if (Object.prototype.propertyIsEnumerable.call(manifest, candidate)) {
26
+ if (uniqueKey !== null) {
27
+ uniqueKey = null;
28
+ break;
29
+ }
30
+ uniqueKey = candidate;
31
+ }
32
+ const slash = candidate.indexOf("/");
33
+ if (slash === -1) break;
34
+ candidate = candidate.slice(slash + 1);
35
+ }
36
+ if (uniqueKey !== null) return uniqueKey;
37
+ let keyOrder = moduleKeyOrder.get(manifest);
38
+ if (!keyOrder) {
39
+ keyOrder = /* @__PURE__ */ new Map();
40
+ for (const key in manifest) keyOrder.set(key, keyOrder.size);
41
+ moduleKeyOrder.set(manifest, keyOrder);
42
+ }
43
+ let matchedKey = null;
44
+ let matchedOrder = Infinity;
45
+ let suffix = moduleId;
46
+ while (true) {
47
+ const order = keyOrder.get(suffix);
48
+ if (order !== void 0 && order < matchedOrder) {
49
+ matchedKey = suffix;
50
+ matchedOrder = order;
51
+ }
52
+ const slash = suffix.indexOf("/");
53
+ if (slash === -1) break;
54
+ suffix = suffix.slice(slash + 1);
55
+ }
56
+ return matchedKey;
57
+ }
58
+ function getSharedChunkFiles(manifest) {
59
+ const cached = sharedChunkFiles.get(manifest);
60
+ if (cached) return cached;
61
+ const files = /* @__PURE__ */ new Set();
62
+ for (const key in manifest) for (const file of manifest[key] ?? []) {
63
+ const basename = file.slice(file.lastIndexOf("/") + 1);
64
+ if (basename.startsWith("framework-") || basename.startsWith("vinext-") || basename.includes("vinext-client-entry") || basename.includes("vinext-app-browser-entry")) files.add(file);
65
+ }
66
+ const result = [...files];
67
+ sharedChunkFiles.set(manifest, result);
68
+ return result;
69
+ }
16
70
  /**
17
71
  * Resolve the effective SSR manifest: prefer the caller-supplied object and
18
72
  * fall back to the registered client build metadata.
19
73
  */
20
74
  function resolveSsrManifest(manifest) {
21
- if (manifest && Object.keys(manifest).length > 0) return manifest;
75
+ if (manifest) {
76
+ let nonEmpty = nonEmptyManifests.get(manifest);
77
+ if (nonEmpty === void 0) {
78
+ nonEmpty = Object.keys(manifest).length > 0;
79
+ nonEmptyManifests.set(manifest, nonEmpty);
80
+ }
81
+ if (nonEmpty) return manifest;
82
+ }
22
83
  return getPagesClientAssets().ssrManifest ?? null;
23
84
  }
24
85
  /**
@@ -29,20 +90,13 @@ function resolveSsrManifest(manifest) {
29
90
  */
30
91
  function getManifestFilesForModule(manifest, moduleId) {
31
92
  if (!manifest || !moduleId) return null;
32
- const files = manifest[moduleId];
33
- if (files) return files;
34
- for (const key in manifest) if (moduleId.endsWith("/" + key) || moduleId === key) return manifest[key];
35
- return null;
93
+ const key = findModuleKey(manifest, moduleId);
94
+ return key === null ? null : manifest[key];
36
95
  }
37
96
  function collectGraphOrderedCss(graph, moduleIds) {
38
97
  const ordered = [];
39
98
  const emitted = /* @__PURE__ */ new Set();
40
99
  const visited = /* @__PURE__ */ new Set();
41
- function findKey(moduleId) {
42
- if (!moduleId) return void 0;
43
- if (graph[moduleId]) return moduleId;
44
- for (const key in graph) if (moduleId === key || moduleId.endsWith("/" + key)) return key;
45
- }
46
100
  function visit(key) {
47
101
  if (!key || visited.has(key)) return;
48
102
  visited.add(key);
@@ -55,7 +109,7 @@ function collectGraphOrderedCss(graph, moduleIds) {
55
109
  ordered.push(file);
56
110
  }
57
111
  }
58
- for (const moduleId of moduleIds) visit(findKey(moduleId));
112
+ for (const moduleId of moduleIds) if (moduleId) visit(findModuleKey(graph, moduleId));
59
113
  return ordered;
60
114
  }
61
115
  /**
@@ -104,7 +158,11 @@ function collectAssetTags(options) {
104
158
  };
105
159
  const runtimeAssets = getPagesClientAssets();
106
160
  const lazyChunks = runtimeAssets.lazyChunks ?? null;
107
- const lazySet = lazyChunks && lazyChunks.length > 0 ? new Set(lazyChunks) : null;
161
+ let lazySet = lazyChunks ? lazyChunkSets.get(lazyChunks) : void 0;
162
+ if (lazyChunks && !lazySet) {
163
+ lazySet = new Set(lazyChunks);
164
+ lazyChunkSets.set(lazyChunks, lazySet);
165
+ }
108
166
  const clientEntry = runtimeAssets.clientEntry;
109
167
  if (clientEntry) {
110
168
  seen.add(clientEntry);
@@ -128,15 +186,8 @@ function collectAssetTags(options) {
128
186
  const files = getManifestFilesForModule(m, id);
129
187
  if (files) for (let fi = 0; fi < files.length; fi++) allFiles.push(files[fi]);
130
188
  }
131
- for (const key in m) {
132
- const vals = m[key];
133
- if (!vals) continue;
134
- for (let vi = 0; vi < vals.length; vi++) {
135
- const file = vals[vi];
136
- const basename = file.split("/").pop() || "";
137
- if (basename.startsWith("framework-") || basename.startsWith("vinext-") || basename.includes("vinext-client-entry") || basename.includes("vinext-app-browser-entry")) allFiles.push(file);
138
- }
139
- }
189
+ const sharedFiles = m === runtimeAssets.ssrManifest && runtimeAssets.sharedChunks ? runtimeAssets.sharedChunks : getSharedChunkFiles(m);
190
+ for (const file of sharedFiles) allFiles.push(file);
140
191
  } else for (const akey in m) {
141
192
  const avals = m[akey];
142
193
  if (avals) for (let ai = 0; ai < avals.length; ai++) allFiles.push(avals[ai]);
@@ -160,4 +211,4 @@ function collectAssetTags(options) {
160
211
  return tags.join("\n ");
161
212
  }
162
213
  //#endregion
163
- export { collectAssetTags, getManifestFilesForModule, resolveClientModuleUrl, resolveSsrManifest };
214
+ export { collectAssetTags, getManifestFilesForModule, getSharedChunkFiles, resolveClientModuleUrl, resolveSsrManifest };
@@ -4,6 +4,8 @@ export type PagesClientAssets = {
4
4
  clientEntry?: string;
5
5
  appBootstrapPreinitModules?: string[];
6
6
  ssrManifest?: Record<string, string[]>;
7
+ /** Build-time shared file list, valid only for this ssrManifest object. */
8
+ sharedChunks?: string[];
7
9
  cssGraph?: Record<string, {
8
10
  imports?: string[];
9
11
  css?: string[];
@@ -149,8 +149,11 @@ export type ResolvePagesPageDataOptions = {
149
149
  createPageElement: (props: Record<string, unknown>) => ReactNode;
150
150
  fontLinkHeader: string;
151
151
  i18n: PagesI18nRenderContext;
152
+ /** Build-time default locale, which can differ from a domain's render default. */
153
+ staticPathsDefaultLocale?: string;
152
154
  isrCacheKey: (router: string, pathname: string) => string;
153
155
  isrGet: (key: string) => Promise<ISRCacheEntry | null>;
156
+ hasPrerenderedPages?: boolean;
154
157
  isrSet: (key: string, data: CachedPagesValue | CachedRedirectValue | null, policy: IsrWritePolicy) => Promise<void>;
155
158
  expireSeconds?: number;
156
159
  /**
@@ -216,6 +219,8 @@ export type ResolvePagesPageDataOptions = {
216
219
  sanitizeDestination: (destination: string) => string;
217
220
  scriptNonce?: string;
218
221
  statusCode?: number;
222
+ /** Request-local headers inherited when rendering a source page's notFound result. */
223
+ notFoundSourceHeaders?: Record<string, string | number | boolean | string[]>;
219
224
  triggerBackgroundRegeneration: (key: string, renderFn: () => Promise<void>, errorContext?: {
220
225
  routerKind: "Pages Router";
221
226
  routePath: string;
@@ -314,7 +319,7 @@ export type PagesRouteParam = {
314
319
  optional: boolean;
315
320
  };
316
321
  export declare function getPagesRouteParams(routePattern: string): PagesRouteParam[];
317
- export declare function matchesPagesStaticPath(pathEntry: PagesStaticPathsEntry, params: Record<string, unknown>, routeParams: PagesRouteParam[], routeUrl: string): boolean;
322
+ export declare function matchesPagesStaticPath(pathEntry: PagesStaticPathsEntry, params: Record<string, unknown>, routeParams: PagesRouteParam[], routeUrl: string, i18n?: Pick<PagesI18nRenderContext, "locale" | "locales" | "defaultLocale">): boolean;
318
323
  export declare function renderPagesIsrHtml(options: RenderPagesIsrHtmlOptions): Promise<string>;
319
324
  export declare function resolvePagesPageData(options: ResolvePagesPageDataOptions): Promise<ResolvePagesPageDataResult>;
320
325
  //#endregion
@@ -3,6 +3,8 @@ import { isBotUserAgent } from "../utils/html-limited-bots.js";
3
3
  import { normalizePathnameForRouteMatch } from "../routing/utils.js";
4
4
  import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
5
5
  import { isDangerousScheme } from "../shims/url-safety.js";
6
+ import { extractLocaleFromUrl } from "./pages-i18n.js";
7
+ import { recordRouteCacheability } from "../shims/cacheability-classification.js";
6
8
  import { applyCdnResponseHeaders } from "./cache-control.js";
7
9
  import { buildMissIsrCacheControl, decideIsr } from "./isr-decision.js";
8
10
  import { buildPagesCacheValue, isrCacheControl } from "./isr-cache.js";
@@ -102,6 +104,10 @@ function mergePagesNotFoundSourceHeaders(response, sourceHeaders) {
102
104
  }
103
105
  function applyPagesTerminalMissHeaders(response, revalidateSeconds, isrCachePathname, expireSeconds) {
104
106
  const stem = isrCachePathname.endsWith("/") ? isrCachePathname.slice(0, -1) : isrCachePathname;
107
+ recordRouteCacheability({
108
+ cacheable: revalidateSeconds !== 0,
109
+ cacheControl: buildMissIsrCacheControl(revalidateSeconds, expireSeconds)
110
+ });
105
111
  applyCdnResponseHeaders(response.headers, {
106
112
  cacheControl: buildMissIsrCacheControl(revalidateSeconds, expireSeconds),
107
113
  tags: [encodeCacheTag(`_N_T_${stem || "/"}`)]
@@ -117,16 +123,17 @@ function applyCachedPagesRepresentationHeaders(response, cacheState, entry, opti
117
123
  expireSeconds: entry.cacheControl?.expire === void 0 ? void 0 : options.expireSeconds,
118
124
  cacheControlMeta: entry.cacheControl
119
125
  });
126
+ recordRouteCacheability({
127
+ cacheable: true,
128
+ cacheControl
129
+ });
120
130
  applyCdnResponseHeaders(response.headers, { cacheControl });
121
131
  for (const [name, value] of Object.entries(buildCacheStateHeaders(cacheState))) response.headers.set(name, value);
122
132
  return response;
123
133
  }
124
134
  function buildCachedPagesNotFoundResult(options, entry, cacheState) {
125
135
  const result = buildPagesNotFoundResult(options, entry.cacheControl?.revalidate ?? 60, cacheState, entry.cacheControl?.expire);
126
- if (result.kind === "response") return {
127
- kind: "response",
128
- response: applyCachedPagesRepresentationHeaders(result.response, cacheState, entry, options)
129
- };
136
+ if (result.kind === "response") return finalizeCachedPagesResponse(applyCachedPagesRepresentationHeaders(result.response, cacheState, entry, options), options);
130
137
  return result;
131
138
  }
132
139
  function resolvePagesRedirectStatus(redirect) {
@@ -270,7 +277,8 @@ function buildPagesRedirectResponse(redirect, options, props = { pageProps: {} }
270
277
  const headers = new Headers(responseHeaders);
271
278
  headers.set("Location", location);
272
279
  if (resolved.statusCode === 308) headers.set("Refresh", `0;url=${location}`);
273
- return new Response(location, {
280
+ if (options.isBuildTimePrerendering) headers.set("Content-Type", "application/json");
281
+ return new Response(options.isBuildTimePrerendering ? options.safeJsonStringify(redirectProps) : location, {
274
282
  status: resolved.statusCode,
275
283
  headers
276
284
  });
@@ -333,7 +341,19 @@ function getPagesRouteParams(routePattern) {
333
341
  return null;
334
342
  }).filter((param) => param !== null);
335
343
  }
336
- function matchesPagesStaticPath(pathEntry, params, routeParams, routeUrl) {
344
+ function matchesPagesStaticPath(pathEntry, params, routeParams, routeUrl, i18n) {
345
+ if (i18n?.locales && i18n.defaultLocale) {
346
+ let entryLocale = i18n.defaultLocale;
347
+ if (typeof pathEntry === "string") {
348
+ const localized = extractLocaleFromUrl(pathEntry, {
349
+ locales: i18n.locales,
350
+ defaultLocale: i18n.defaultLocale
351
+ });
352
+ pathEntry = localized.url;
353
+ entryLocale = localized.locale;
354
+ } else entryLocale = pathEntry.locale ?? entryLocale;
355
+ if (entryLocale !== (i18n.locale ?? i18n.defaultLocale)) return false;
356
+ }
337
357
  if (typeof pathEntry === "string") return normalizePathnameForRouteMatch(normalizeStaticPathname(pathEntry)) === normalizePathnameForRouteMatch(normalizeStaticPathname(routeUrl));
338
358
  const entryParams = pathEntry.params;
339
359
  if (entryParams === void 0 || entryParams === null) return false;
@@ -364,6 +384,10 @@ function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSec
364
384
  "Content-Type": "text/html; charset=utf-8",
365
385
  ...buildCacheStateHeaders(cacheState)
366
386
  });
387
+ recordRouteCacheability({
388
+ cacheable: true,
389
+ cacheControl: cacheControlHeader
390
+ });
367
391
  applyCdnResponseHeaders(headers, { cacheControl: cacheControlHeader });
368
392
  if (fontLinkHeader) headers.set("Link", fontLinkHeader);
369
393
  if (cachedHeaders) for (const [name, value] of Object.entries(cachedHeaders)) {
@@ -378,28 +402,21 @@ function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSec
378
402
  headers
379
403
  });
380
404
  }
381
- /**
382
- * For bot / crawler UAs, attach an ETag to a cached ISR response (HIT or
383
- * STALE) so it is consistent with the fresh-MISS path, then check for a
384
- * matching `If-None-Match`. When the check passes — and the request did NOT
385
- * carry `Cache-Control: no-cache` — returns a 304 response; otherwise returns
386
- * `null` so the caller can return the full response.
387
- *
388
- * Extracted to avoid duplicating the same three-line block across the HIT and
389
- * STALE branches.
390
- */
391
- function applyBotETagAndCheck(cachedResponse, html, options) {
392
- if (!options.userAgent || !isPagesStreamingBot(options.userAgent)) return null;
393
- const etag = generatePagesETag(html);
394
- cachedResponse.headers.set("ETag", etag);
395
- if (!requestsNoCache(options.requestCacheControl) && options.ifNoneMatch && matchesIfNoneMatch(options.ifNoneMatch, etag)) return {
396
- kind: "response",
397
- response: new Response(null, {
405
+ /** Merge source headers before the cached HTML's bot ETag and freshness check. */
406
+ function finalizeCachedPagesResponse(response, options, html) {
407
+ response = mergePagesNotFoundSourceHeaders(response, options.notFoundSourceHeaders);
408
+ if (html !== void 0 && options.userAgent && isPagesStreamingBot(options.userAgent)) {
409
+ const etag = generatePagesETag(html);
410
+ response.headers.set("ETag", etag);
411
+ if (!requestsNoCache(options.requestCacheControl) && options.ifNoneMatch && matchesIfNoneMatch(options.ifNoneMatch, etag)) response = new Response(null, {
398
412
  status: 304,
399
- headers: cachedResponse.headers
400
- })
413
+ headers: response.headers
414
+ });
415
+ }
416
+ return {
417
+ kind: "response",
418
+ response
401
419
  };
402
- return null;
403
420
  }
404
421
  /**
405
422
  * Matches one serialized `next/head` tag. `getSSRHeadHTML()` stamps every tag
@@ -491,17 +508,32 @@ async function resolvePagesPageData(options) {
491
508
  const userFacingParams = options.route.isDynamic ? options.params : null;
492
509
  let isFallback = false;
493
510
  let shouldPersistFallbackData = false;
494
- let onDemandPreviousCacheEntry;
511
+ let previousCacheEntry;
495
512
  const previewData = options.isOnDemandRevalidate ? false : options.previewData ?? false;
496
- if (typeof options.pageModule.getStaticPaths === "function" && options.route.isDynamic) {
513
+ if (options.hasPrerenderedPages && options.nextData?.autoExport && !options.scriptNonce && !options.isOnDemandRevalidate && previewData === false) {
514
+ const cached = await options.isrGet(options.isrCacheKey("pages", options.isrCachePathname ?? options.routeUrl.split("?")[0]));
515
+ const value = cached?.value.value;
516
+ if (cached && !cached.isStale && !cached.isExpired && value?.kind === "PAGES") return finalizeCachedPagesResponse(options.isDataReq ? applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(value.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "HIT", cached.value, options) : buildPagesCacheResponse(value.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, options.statusCode ?? value.status, value.headers), options, options.isDataReq ? void 0 : value.html);
517
+ }
518
+ let hasFreshPrerenderedEntry = false;
519
+ if (options.hasPrerenderedPages && options.route.isDynamic && typeof options.pageModule.getStaticProps === "function" && typeof options.pageModule.getServerSideProps !== "function" && !options.isOnDemandRevalidate && previewData === false) {
520
+ previousCacheEntry = await options.isrGet(options.isrCacheKey("pages", options.isrCachePathname ?? options.routeUrl.split("?")[0]));
521
+ const value = previousCacheEntry?.value.value;
522
+ hasFreshPrerenderedEntry = !!previousCacheEntry && !previousCacheEntry.isStale && !previousCacheEntry.isExpired && (value === null || value?.kind === "PAGES" || value?.kind === "REDIRECT");
523
+ }
524
+ if (!hasFreshPrerenderedEntry && typeof options.pageModule.getStaticPaths === "function" && options.route.isDynamic) {
525
+ const staticPathsI18n = {
526
+ ...options.i18n,
527
+ defaultLocale: options.staticPathsDefaultLocale ?? options.i18n.defaultLocale
528
+ };
497
529
  const pathsResult = await options.pageModule.getStaticPaths({
498
530
  locales: options.i18n.locales ?? [],
499
- defaultLocale: options.i18n.defaultLocale ?? ""
531
+ defaultLocale: staticPathsI18n.defaultLocale ?? ""
500
532
  });
501
533
  const fallback = pathsResult?.fallback ?? false;
502
534
  const paths = pathsResult?.paths ?? [];
503
535
  const routeParams = getPagesRouteParams(options.routePattern);
504
- const isValidPath = paths.some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, routeParams, options.routeUrl));
536
+ const isValidPath = paths.some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, routeParams, options.routeUrl, staticPathsI18n));
505
537
  if (fallback === false && !isValidPath && previewData === false) {
506
538
  if (options.isOnDemandRevalidate && !options.revalidateOnlyGenerated) return {
507
539
  kind: "response",
@@ -516,8 +548,8 @@ async function resolvePagesPageData(options) {
516
548
  }
517
549
  if (typeof options.pageModule.getStaticProps === "function" && options.isOnDemandRevalidate && options.revalidateOnlyGenerated) {
518
550
  const pathname = options.isrCachePathname ?? options.routeUrl.split("?")[0];
519
- onDemandPreviousCacheEntry = await options.isrGet(options.isrCacheKey("pages", pathname));
520
- if (!onDemandPreviousCacheEntry) return {
551
+ previousCacheEntry = await options.isrGet(options.isrCacheKey("pages", pathname));
552
+ if (!previousCacheEntry) return {
521
553
  kind: "response",
522
554
  response: new Response("This page could not be found", {
523
555
  status: 404,
@@ -616,7 +648,7 @@ async function resolvePagesPageData(options) {
616
648
  if (typeof options.pageModule.getStaticProps === "function") {
617
649
  const pathname = options.isrCachePathname ?? options.routeUrl.split("?")[0];
618
650
  const cacheKey = options.isrCacheKey("pages", pathname);
619
- const cached = onDemandPreviousCacheEntry !== void 0 ? onDemandPreviousCacheEntry : await options.isrGet(cacheKey);
651
+ const cached = previousCacheEntry !== void 0 ? previousCacheEntry : await options.isrGet(cacheKey);
620
652
  const cachedValue = cached?.value.value;
621
653
  const isLegacyCachedNotFound = cachedValue?.kind === "PAGES" && cachedValue.status === 404 && options.routePattern !== "/404" && options.routePattern !== "/_error";
622
654
  const cachedRedirect = getCachedPagesRedirect(cachedValue);
@@ -700,46 +732,20 @@ async function resolvePagesPageData(options) {
700
732
  if (!options.isOnDemandRevalidate && cached && !cached.isStale && !cached.isExpired && previewData === false) {
701
733
  if (cachedValue === null) return buildCachedPagesNotFoundResult(options, cached.value, "HIT");
702
734
  if (isLegacyCachedNotFound) return buildCachedPagesNotFoundResult(options, cached.value, "HIT");
703
- if (cachedRedirect) return {
704
- kind: "response",
705
- response: applyCachedPagesRepresentationHeaders(buildCachedPagesRedirectResponse(cachedRedirect, options), "HIT", cached.value, options)
706
- };
707
- if (options.isDataReq && cachedValue?.kind === "PAGES") return {
708
- kind: "response",
709
- response: applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(cachedValue.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "HIT", cached.value, options)
710
- };
711
- }
712
- if (!options.isOnDemandRevalidate && cached?.isStale === false && !cached.isExpired && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) {
713
- const hitResponse = buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status, cachedValue.headers);
714
- const hitBotResult = applyBotETagAndCheck(hitResponse, cachedValue.html, options);
715
- if (hitBotResult) return hitBotResult;
716
- return {
717
- kind: "response",
718
- response: hitResponse
719
- };
735
+ if (cachedRedirect) return finalizeCachedPagesResponse(applyCachedPagesRepresentationHeaders(buildCachedPagesRedirectResponse(cachedRedirect, options), "HIT", cached.value, options), options);
736
+ if (options.isDataReq && cachedValue?.kind === "PAGES") return finalizeCachedPagesResponse(applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(cachedValue.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "HIT", cached.value, options), options);
720
737
  }
738
+ if (!options.isOnDemandRevalidate && cached?.isStale === false && !cached.isExpired && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) return finalizeCachedPagesResponse(buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status, cachedValue.headers), options, cachedValue.html);
721
739
  if (!options.isOnDemandRevalidate && cached && cached.isStale && !cached.isExpired && !options.scriptNonce && previewData === false && (cachedValue === null || cachedRedirect !== null || isLegacyCachedNotFound || options.isDataReq)) {
722
740
  scheduleStaleRegeneration();
723
741
  if (cachedValue === null) return buildCachedPagesNotFoundResult(options, cached.value, "STALE");
724
742
  if (isLegacyCachedNotFound) return buildCachedPagesNotFoundResult(options, cached.value, "STALE");
725
- if (cachedRedirect) return {
726
- kind: "response",
727
- response: applyCachedPagesRepresentationHeaders(buildCachedPagesRedirectResponse(cachedRedirect, options), "STALE", cached.value, options)
728
- };
729
- if (cachedValue?.kind === "PAGES") return {
730
- kind: "response",
731
- response: applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(cachedValue.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "STALE", cached.value, options)
732
- };
743
+ if (cachedRedirect) return finalizeCachedPagesResponse(applyCachedPagesRepresentationHeaders(buildCachedPagesRedirectResponse(cachedRedirect, options), "STALE", cached.value, options), options);
744
+ if (cachedValue?.kind === "PAGES") return finalizeCachedPagesResponse(applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(cachedValue.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "STALE", cached.value, options), options);
733
745
  }
734
746
  if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && cached.isStale && !cached.isExpired && !options.scriptNonce && !options.isDataReq && previewData === false) {
735
747
  scheduleStaleRegeneration();
736
- const staleResponse = buildPagesCacheResponse(cachedValue.html, "STALE", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status, cachedValue.headers);
737
- const staleBotResult = applyBotETagAndCheck(staleResponse, cachedValue.html, options);
738
- if (staleBotResult) return staleBotResult;
739
- return {
740
- kind: "response",
741
- response: staleResponse
742
- };
748
+ return finalizeCachedPagesResponse(buildPagesCacheResponse(cachedValue.html, "STALE", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status, cachedValue.headers), options, cachedValue.html);
743
749
  }
744
750
  const generatedPageData = !options.isOnDemandRevalidate && previewData === false && cached?.isStale === false && !cached.isExpired && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest && isUnknownRecord(cachedValue.pageData) ? cachedValue.pageData : null;
745
751
  if (!generatedPageData) {
@@ -1,16 +1,18 @@
1
1
  import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
2
2
  import { closeAfterResponse, closeAfterResponseWithBody, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
3
3
  import { PRERENDER_REVALIDATE_HEADER } from "../utils/protocol-headers.js";
4
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
4
5
  import { patternToNextFormat } from "../routing/route-validation.js";
5
6
  import { getRequestExecutionContext } from "../shims/request-context.js";
6
7
  import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
7
8
  import { extractLocaleFromUrl, resolvePagesI18nRequest } from "./pages-i18n.js";
8
9
  import { reportRequestError } from "./instrumentation.js";
9
- import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, recordRouteCacheability } from "../shims/cacheability-classification.js";
10
- import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, hasExplicitNonCacheableResponsePolicy, shouldUseNextDeployCacheControl } from "./cache-control.js";
10
+ import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
11
+ import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, markRouteCacheabilityExplicitResponsePolicy, recordRouteCacheability } from "../shims/cacheability-classification.js";
12
+ import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, hasExplicitNonCacheableResponsePolicy, shouldUseNextDeployCacheControl } from "./cache-control.js";
11
13
  import { buildMissIsrCacheControl } from "./isr-decision.js";
12
14
  import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
13
- import { coalesceOnDemandRevalidation, isrCacheKey, isrGet, isrSet, triggerBackgroundRegeneration } from "./isr-cache.js";
15
+ import { coalesceOnDemandRevalidation, isrGet, isrSet, pagesIsrCacheKey, triggerBackgroundRegeneration } from "./isr-cache.js";
14
16
  import { encodeCacheTag } from "../utils/encode-cache-tag.js";
15
17
  import { ensureFetchPatch } from "../shims/fetch-cache.js";
16
18
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
@@ -91,6 +93,10 @@ function stripPagesNotFoundFramingHeaders(response) {
91
93
  }
92
94
  function applyPagesErrorCachePolicy(response, revalidateSeconds, expireSeconds, cacheTagPathname) {
93
95
  const headers = new Headers(response.headers);
96
+ recordRouteCacheability(revalidateSeconds === void 0 ? { cacheable: false } : {
97
+ cacheable: revalidateSeconds !== 0,
98
+ cacheControl: buildMissIsrCacheControl(revalidateSeconds, expireSeconds)
99
+ });
94
100
  if (hasExplicitNonCacheableResponsePolicy(headers)) return response;
95
101
  if (revalidateSeconds === void 0) applyCdnResponseHeaders(headers, { cacheControl: NEVER_CACHE_CONTROL });
96
102
  else {
@@ -135,8 +141,7 @@ function createPagesPageHandler(opts) {
135
141
  return errorPageRoute;
136
142
  }
137
143
  function isrCacheKeyForRequest(i18nCacheVariant) {
138
- if (!i18nCacheVariant) return (router, pathname) => isrCacheKey(router, pathname, buildId ?? void 0);
139
- return (router, pathname) => isrCacheKey(router, pathname + "::i18n=" + encodeURIComponent(i18nCacheVariant), buildId ?? void 0);
144
+ return (_router, pathname) => pagesIsrCacheKey(pathname, buildId ?? void 0, i18nCacheVariant);
140
145
  }
141
146
  async function renderPage(request, url, manifest, middlewareHeaders, options, initialResponseHeaders) {
142
147
  let isDataReq = !!(options && options.isDataReq);
@@ -183,10 +188,10 @@ function createPagesPageHandler(opts) {
183
188
  redirectUrl: void 0
184
189
  };
185
190
  const locale = localeInfo.locale;
186
- const routeUrl = localeInfo.url;
191
+ let routeUrl = localeInfo.url;
187
192
  const currentDefaultLocale = i18nConfig ? localeInfo.domainLocale ? localeInfo.domainLocale.defaultLocale : i18nConfig.defaultLocale : void 0;
188
193
  const domainLocales = i18nConfig ? i18nConfig.domains : void 0;
189
- const pageIsrCacheKey = isrCacheKeyForRequest(i18nConfig ? localeInfo.domainLocale ? "domain:" + String(localeInfo.domainLocale.domain).toLowerCase() : "locale:" + String(locale) : null);
194
+ const pageIsrCacheKey = isrCacheKeyForRequest(i18nConfig ? localeInfo.domainLocale ? JSON.stringify([String(localeInfo.domainLocale.domain).toLowerCase(), locale]) : "locale:" + String(locale) : null);
190
195
  if (localeInfo.redirectUrl) return new Response(null, {
191
196
  status: 307,
192
197
  headers: { Location: localeInfo.redirectUrl }
@@ -212,6 +217,22 @@ function createPagesPageHandler(opts) {
212
217
  renderAsPath = routeUrl;
213
218
  } else return buildDefaultPagesNotFoundResponse();
214
219
  }
220
+ const routePathname = routeUrl.split("?")[0];
221
+ const cachePathname = normalizePathnameForRouteMatch(routePathname);
222
+ let cacheIdentityDiverges = false;
223
+ if (!isRouteMissErrorRender && options?.__forcedRoute === void 0 && cachePathname !== routePathname) {
224
+ const cachePathRoute = matchRoute(cachePathname, pageRoutes)?.route;
225
+ if (cachePathRoute !== match.route) {
226
+ const cachePathModule = cachePathRoute?.module;
227
+ if (match.route.isDynamic && typeof match.route.module.getStaticProps === "function" && cachePathRoute && !cachePathRoute.isDynamic && typeof cachePathModule?.getStaticProps === "function" && typeof cachePathModule.getServerSideProps !== "function" && getPagesPreviewState(request.headers.get("cookie"), { isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) }).data === false) {
228
+ match = {
229
+ route: cachePathRoute,
230
+ params: {}
231
+ };
232
+ routeUrl = cachePathname + routeUrl.slice(routePathname.length);
233
+ } else cacheIdentityDiverges = true;
234
+ }
235
+ }
215
236
  const { route, params } = match;
216
237
  const pageModule = traceFindPageComponents(route.pattern, () => route.module);
217
238
  const isStaticPropsRoute = typeof pageModule.getStaticProps === "function";
@@ -228,11 +249,12 @@ function createPagesPageHandler(opts) {
228
249
  cacheable: true,
229
250
  cacheControl: STATIC_CACHE_CONTROL
230
251
  });
252
+ else recordRouteCacheability({ cacheable: false });
231
253
  }
232
- const routeIsrGet = isCacheabilityProbe ? async () => null : isrGet;
233
- const routeIsrSet = isCacheabilityProbe ? async () => {} : isrSet;
254
+ const routeIsrGet = isCacheabilityProbe || cacheIdentityDiverges ? async () => null : isrGet;
255
+ const routeIsrSet = isCacheabilityProbe || cacheIdentityDiverges ? async () => {} : isrSet;
234
256
  const isStaticPropsRender = isStaticPropsRoute && typeof pageModule.getServerSideProps !== "function";
235
- if (!options?.__skipOnDemandCoalesce && !options?.__forcedRoute && isStaticPropsRoute && isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"))) {
257
+ if (!options?.__skipOnDemandCoalesce && !options?.__forcedRoute && !cacheIdentityDiverges && isStaticPropsRoute && isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"))) {
236
258
  const cacheKey = pageIsrCacheKey("pages", routeUrl.split("?")[0]);
237
259
  const snapshot = await coalesceOnDemandRevalidation(cacheKey, async () => {
238
260
  const response = await renderPage(request, url, manifest, middlewareHeaders, {
@@ -262,7 +284,7 @@ function createPagesPageHandler(opts) {
262
284
  const routePattern = patternToNextFormat(route.pattern);
263
285
  setFrameworkRequestRoute(routePattern);
264
286
  const renderStatusCode = renderStatusCodeOverride ?? (routePattern === "/404" ? 404 : void 0);
265
- const isrCachePathname = isStaticPropsRender && (routePattern === "/404" || routePattern === "/500" || routePattern === "/_error") ? routePattern : renderRouteUrl.split("?")[0];
287
+ const isrCachePathname = (isStaticPropsRender || pagesReadiness.autoExport) && (routePattern === "/404" || routePattern === "/500" || routePattern === "/_error") ? routePattern === "/_error" && renderStatusCode === 404 ? "/404" : routePattern : renderRouteUrl.split("?")[0];
266
288
  const isNotFoundErrorRender = routePattern === "/404" || routePattern === "/_error" && renderStatusCode === 404;
267
289
  const isStatusErrorRender = isNotFoundErrorRender || routePattern === "/500" || routePattern === "/_error" && renderStatusCode === 500;
268
290
  const errorPageRevalidateSeconds = isNotFoundErrorRender ? options?.__notFoundRevalidateSeconds : void 0;
@@ -327,6 +349,11 @@ function createPagesPageHandler(opts) {
327
349
  }
328
350
  };
329
351
  const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareHeaders);
352
+ const browserCacheControl = isStaticPropsRoute && !scriptNonce ? (initialResponseHeaders ?? middlewareHeaders)?.get("Cache-Control") : null;
353
+ const withBrowserPolicy = (response) => {
354
+ if (browserCacheControl) response.headers.set("Cache-Control", browserCacheControl);
355
+ return response;
356
+ };
330
357
  const shouldApplyErrorResponsePolicy = previewData === false && !scriptNonce && isStatusErrorRender && (isStaticPropsRoute || isRouteMissErrorRender || options?.__forcedRoute !== void 0);
331
358
  let fontLinkHeader = "";
332
359
  let allFontPreloads = [];
@@ -366,8 +393,10 @@ function createPagesPageHandler(opts) {
366
393
  },
367
394
  fontLinkHeader,
368
395
  i18n: buildI18nRenderContext(i18nConfig, locale, currentDefaultLocale, domainLocales),
396
+ staticPathsDefaultLocale: i18nConfig?.defaultLocale,
369
397
  isrCacheKey: pageIsrCacheKey,
370
398
  isrGet: routeIsrGet,
399
+ hasPrerenderedPages: getCdnCacheAdapter().hasPrerenderedPages,
371
400
  isrSet: routeIsrSet,
372
401
  expireSeconds: vinextConfig.expireTime,
373
402
  isBuildTimePrerendering: typeof process !== "undefined" && process.env && process.env.VINEXT_PRERENDER === "1",
@@ -403,6 +432,7 @@ function createPagesPageHandler(opts) {
403
432
  sanitizeDestination,
404
433
  scriptNonce,
405
434
  statusCode: renderStatusCode,
435
+ notFoundSourceHeaders: options?.__notFoundSourceHeaders,
406
436
  triggerBackgroundRegeneration,
407
437
  vinext: serializedPagesNextData.__vinext,
408
438
  nextData: serializedPagesNextData,
@@ -427,12 +457,12 @@ function createPagesPageHandler(opts) {
427
457
  notFoundResponse = stripPagesNotFoundFramingHeaders(notFoundResponse);
428
458
  if (isOnDemandRevalidate) notFoundResponse = withPagesCacheState(notFoundResponse, "REVALIDATED", isrCachePathname);
429
459
  else if (pageDataResult.cacheState) notFoundResponse = withPagesCacheState(notFoundResponse, pageDataResult.cacheState);
430
- return finalizePagesPreviewResponse(notFoundResponse, preview);
460
+ return finalizePagesPreviewResponse(withBrowserPolicy(notFoundResponse), preview);
431
461
  }
432
462
  if (pageDataResult.kind === "response") {
433
463
  let response = isOnDemandRevalidate && pageDataResult.onDemandRevalidateSuccess !== false ? withPagesCacheState(pageDataResult.response, "REVALIDATED", isrCachePathname) : pageDataResult.response;
434
464
  if (shouldApplyErrorResponsePolicy) response = applyPagesErrorCachePolicy(response, errorPageRevalidateSeconds, errorPageExpireSeconds, errorResponseCachePathname);
435
- return finalizePagesPreviewResponse(response, preview);
465
+ return finalizePagesPreviewResponse(withBrowserPolicy(response), preview);
436
466
  }
437
467
  let pageProps = pageDataResult.pageProps;
438
468
  let renderProps = pageDataResult.props;
@@ -453,6 +483,10 @@ function createPagesPageHandler(opts) {
453
483
  const gsspRes = pageDataResult.gsspRes;
454
484
  const documentReqRes = serializedPagesNextData.autoExport === true && !options?.__notFoundSourceHeaders ? null : pageDataResult.documentReqRes ?? createPageReqRes();
455
485
  const isrRevalidateSeconds = pageDataResult.isrRevalidateSeconds;
486
+ if (isStaticPropsRoute && preview.data === false && !preview.shouldClear && isrRevalidateSeconds !== null) recordRouteCacheability({
487
+ cacheable: isrRevalidateSeconds !== 0,
488
+ cacheControl: buildMissIsrCacheControl(isrRevalidateSeconds, vinextConfig.expireTime)
489
+ });
456
490
  const isrExpireSeconds = pageDataResult.isrExpireSeconds;
457
491
  const isFallbackRender = pageDataResult.isFallback === true;
458
492
  if (isFallbackRender) applySSRContext({
@@ -472,6 +506,7 @@ function createPagesPageHandler(opts) {
472
506
  else headers.set(k, Array.isArray(v) ? v.join(", ") : String(v));
473
507
  }
474
508
  }
509
+ if (hasCdnResponsePolicy(headers)) markRouteCacheabilityExplicitResponsePolicy();
475
510
  if (gsspRes) {
476
511
  if (!headers.has("Cache-Control")) headers.set("Cache-Control", NEVER_CACHE_CONTROL);
477
512
  } else if (isStaticPropsRoute) {
@@ -487,7 +522,7 @@ function createPagesPageHandler(opts) {
487
522
  const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
488
523
  if (deploymentId) headers.set(NEXTJS_DEPLOYMENT_ID_HEADER, deploymentId);
489
524
  }
490
- return finalizePagesPreviewResponse(buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, { headers }), preview);
525
+ return finalizePagesPreviewResponse(withBrowserPolicy(buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, { headers })), preview);
491
526
  }
492
527
  const pageModuleIds = [];
493
528
  if (appAssetPath) pageModuleIds.push(appAssetPath);
@@ -561,7 +596,7 @@ function createPagesPageHandler(opts) {
561
596
  requestCacheControl: request.headers.get("cache-control") ?? void 0
562
597
  });
563
598
  if (shouldApplyErrorResponsePolicy) pageResponse = applyPagesErrorCachePolicy(pageResponse, errorPageRevalidateSeconds, errorPageExpireSeconds, errorResponseCachePathname);
564
- return finalizePagesPreviewResponse(pageResponse, preview);
599
+ return finalizePagesPreviewResponse(withBrowserPolicy(pageResponse), preview);
565
600
  } catch (e) {
566
601
  console.error("[vinext] SSR error:", e);
567
602
  await reportRequestError(e, {
@@ -2,7 +2,8 @@ import { isBotUserAgent } from "../utils/html-limited-bots.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
3
  import { NEXTJS_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
4
4
  import { reportRequestError } from "./instrumentation.js";
5
- import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders, shouldUseNextDeployCacheControl } from "./cache-control.js";
5
+ import { markRouteCacheabilityExplicitResponsePolicy } from "../shims/cacheability-classification.js";
6
+ import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, shouldUseNextDeployCacheControl } from "./cache-control.js";
6
7
  import { buildMissIsrCacheControl } from "./isr-decision.js";
7
8
  import { fnv1a52 } from "../utils/hash.js";
8
9
  import { isrCacheControl } from "./isr-cache.js";
@@ -271,6 +272,7 @@ async function renderPagesPageResponse(options) {
271
272
  }
272
273
  const compositeStream = await buildPagesCompositeStream(responseBodyStream, shellPrefix, shellSuffix);
273
274
  const userSetCacheControl = responseHeaders.has("Cache-Control");
275
+ if (hasCdnResponsePolicy(responseHeaders)) markRouteCacheabilityExplicitResponsePolicy();
274
276
  if (options.scriptNonce) responseHeaders.set("Cache-Control", NO_STORE_CACHE_CONTROL);
275
277
  else if (options.isrRevalidateSeconds !== null) {
276
278
  const isrPathname = options.isrCachePathname ?? options.routeUrl.split("?")[0];
@@ -15,7 +15,7 @@ type PageRouteMatch = {
15
15
  dataKind?: PagesRouteDataKind;
16
16
  };
17
17
  };
18
- export declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>, publicFiles?: ReadonlySet<string>, isDirectBuildAsset?: boolean): Promise<Response | false>;
18
+ export declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>, publicFiles: ReadonlySet<string>, basePath?: string, assetPathPrefix?: string): Promise<Response | false>;
19
19
  export type MiddlewareResult = {
20
20
  continue: boolean;
21
21
  /** The pathname matches middleware, irrespective of request `has`/`missing` conditions. */
@@ -30,6 +30,7 @@ export type MiddlewareResult = {
30
30
  waitUntilPromises?: Promise<unknown>[];
31
31
  };
32
32
  export type PagesPipelineDeps = {
33
+ assetPrefix?: string;
33
34
  basePath: string;
34
35
  trailingSlash: boolean;
35
36
  i18nConfig: NextI18nConfig | null;