vinext 1.3.1 → 1.4.1

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 (271) hide show
  1. package/README.md +25 -22
  2. package/THIRD_PARTY_LICENSES.md +47 -0
  3. package/dist/_virtual/_rolldown/runtime.js +3 -2
  4. package/dist/build/prerender.js +4 -3
  5. package/dist/build/report.d.ts +0 -14
  6. package/dist/build/report.js +1 -51
  7. package/dist/check.js +4 -7
  8. package/dist/cli.js +3 -0
  9. package/dist/client/dev-error-overlay-store.d.ts +1 -0
  10. package/dist/client/dev-error-overlay.d.ts +2 -0
  11. package/dist/client/dev-error-overlay.js +20 -4
  12. package/dist/client/navigation-runtime.d.ts +13 -1
  13. package/dist/client/navigation-runtime.js +1 -1
  14. package/dist/config/config-matchers.js +2 -0
  15. package/dist/config/destination-params.d.ts +2 -1
  16. package/dist/config/destination-params.js +52 -2
  17. package/dist/config/next-config.d.ts +25 -0
  18. package/dist/config/next-config.js +82 -4
  19. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
  20. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
  21. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
  22. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
  23. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
  24. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
  25. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
  26. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
  27. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
  28. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
  29. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
  30. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
  31. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
  32. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
  33. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
  34. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
  35. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
  36. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
  37. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
  38. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
  39. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
  40. package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
  41. package/dist/entries/app-rsc-entry.js +17 -49
  42. package/dist/entries/app-rsc-manifest.js +3 -4
  43. package/dist/entries/app-ssr-entry.js +1 -0
  44. package/dist/entries/pages-server-entry.js +36 -9
  45. package/dist/index.js +112 -90
  46. package/dist/init-cloudflare.d.ts +1 -3
  47. package/dist/init-cloudflare.js +10 -48
  48. package/dist/init-platform.d.ts +2 -0
  49. package/dist/init-platform.js +4 -0
  50. package/dist/plugins/extensionless-dynamic-import.js +6 -2
  51. package/dist/plugins/next-intl-catalog.d.ts +12 -0
  52. package/dist/plugins/next-intl-catalog.js +85 -0
  53. package/dist/plugins/pages-node-externals.d.ts +1 -0
  54. package/dist/plugins/pages-node-externals.js +1 -1
  55. package/dist/plugins/strip-server-exports.js +2 -1
  56. package/dist/plugins/use-cache-callable.d.ts +1 -1
  57. package/dist/plugins/use-cache-callable.js +136 -94
  58. package/dist/routing/app-route-graph.d.ts +6 -0
  59. package/dist/routing/app-route-graph.js +9 -1
  60. package/dist/server/api-handler.js +21 -5
  61. package/dist/server/app-bfcache-identity.js +1 -1
  62. package/dist/server/app-browser-entry.js +86 -66
  63. package/dist/server/app-browser-history-controller.d.ts +5 -4
  64. package/dist/server/app-browser-history-controller.js +93 -15
  65. package/dist/server/app-browser-navigation-controller.d.ts +2 -2
  66. package/dist/server/app-browser-navigation-controller.js +1 -2
  67. package/dist/server/app-browser-rsc-redirect.js +7 -7
  68. package/dist/server/app-browser-server-action-client.d.ts +2 -0
  69. package/dist/server/app-browser-server-action-client.js +5 -4
  70. package/dist/server/app-browser-state.d.ts +2 -4
  71. package/dist/server/app-browser-state.js +9 -4
  72. package/dist/server/app-browser-supplemental-refresh.js +16 -1
  73. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  74. package/dist/server/app-browser-visible-commit.js +4 -14
  75. package/dist/server/app-elements-wire.d.ts +6 -38
  76. package/dist/server/app-elements-wire.js +4 -41
  77. package/dist/server/app-elements.d.ts +2 -2
  78. package/dist/server/app-elements.js +2 -2
  79. package/dist/server/app-history-state.d.ts +2 -2
  80. package/dist/server/app-history-state.js +5 -2
  81. package/dist/server/app-mounted-layouts.d.ts +21 -0
  82. package/dist/server/app-mounted-layouts.js +67 -0
  83. package/dist/server/app-optimistic-routing.d.ts +19 -1
  84. package/dist/server/app-optimistic-routing.js +43 -4
  85. package/dist/server/app-page-boundary-render.js +10 -14
  86. package/dist/server/app-page-boundary.js +2 -2
  87. package/dist/server/app-page-cache-finalizer.d.ts +12 -1
  88. package/dist/server/app-page-cache-finalizer.js +70 -29
  89. package/dist/server/app-page-cache.d.ts +13 -1
  90. package/dist/server/app-page-cache.js +31 -9
  91. package/dist/server/app-page-dispatch.d.ts +5 -11
  92. package/dist/server/app-page-dispatch.js +84 -155
  93. package/dist/server/app-page-element-builder.d.ts +2 -2
  94. package/dist/server/app-page-element-builder.js +13 -12
  95. package/dist/server/app-page-execution.d.ts +17 -52
  96. package/dist/server/app-page-execution.js +102 -95
  97. package/dist/server/app-page-head.d.ts +13 -0
  98. package/dist/server/app-page-head.js +44 -16
  99. package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
  100. package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
  101. package/dist/server/app-page-layout-gate.d.ts +35 -0
  102. package/dist/server/app-page-layout-gate.js +50 -0
  103. package/dist/server/app-page-params.d.ts +0 -1
  104. package/dist/server/app-page-params.js +1 -14
  105. package/dist/server/app-page-probe.d.ts +3 -21
  106. package/dist/server/app-page-probe.js +4 -37
  107. package/dist/server/app-page-render.d.ts +2 -13
  108. package/dist/server/app-page-render.js +103 -234
  109. package/dist/server/app-page-request.d.ts +1 -3
  110. package/dist/server/app-page-request.js +1 -1
  111. package/dist/server/app-page-response.js +3 -3
  112. package/dist/server/app-page-route-wiring.d.ts +13 -6
  113. package/dist/server/app-page-route-wiring.js +86 -63
  114. package/dist/server/app-page-rsc-render-status.d.ts +27 -1
  115. package/dist/server/app-page-rsc-render-status.js +121 -13
  116. package/dist/server/app-page-stream.d.ts +12 -8
  117. package/dist/server/app-page-stream.js +4 -3
  118. package/dist/server/app-pages-bridge.d.ts +4 -0
  119. package/dist/server/app-pages-bridge.js +7 -3
  120. package/dist/server/app-render-dependency.d.ts +11 -4
  121. package/dist/server/app-render-dependency.js +86 -38
  122. package/dist/server/app-request-stage-dispatch.js +1 -1
  123. package/dist/server/app-request-stage-independent-entry.js +1 -1
  124. package/dist/server/app-route-handler-cache.js +2 -2
  125. package/dist/server/app-route-handler-dispatch.js +14 -9
  126. package/dist/server/app-route-handler-execution.js +11 -5
  127. package/dist/server/app-route-handler-policy.d.ts +1 -1
  128. package/dist/server/app-route-handler-policy.js +3 -3
  129. package/dist/server/app-route-handler-response.js +1 -1
  130. package/dist/server/app-route-handler-runtime.d.ts +1 -1
  131. package/dist/server/app-route-handler-runtime.js +28 -11
  132. package/dist/server/app-router-entry.js +1 -1
  133. package/dist/server/app-rsc-cache-busting.d.ts +12 -12
  134. package/dist/server/app-rsc-cache-busting.js +31 -72
  135. package/dist/server/app-rsc-error-handler.d.ts +2 -1
  136. package/dist/server/app-rsc-error-handler.js +10 -2
  137. package/dist/server/app-rsc-errors.d.ts +8 -0
  138. package/dist/server/app-rsc-errors.js +11 -1
  139. package/dist/server/app-rsc-handler.d.ts +5 -5
  140. package/dist/server/app-rsc-handler.js +80 -83
  141. package/dist/server/app-rsc-request-normalization.d.ts +10 -16
  142. package/dist/server/app-rsc-request-normalization.js +12 -18
  143. package/dist/server/app-rsc-response-finalizer.js +2 -2
  144. package/dist/server/app-rsc-response-stage.js +9 -15
  145. package/dist/server/app-server-action-execution.d.ts +3 -1
  146. package/dist/server/app-server-action-execution.js +15 -8
  147. package/dist/server/app-ssr-entry.d.ts +8 -0
  148. package/dist/server/app-ssr-entry.js +22 -16
  149. package/dist/server/app-ssr-stream.js +1 -1
  150. package/dist/server/app-visited-response-cache.d.ts +36 -1
  151. package/dist/server/app-visited-response-cache.js +46 -5
  152. package/dist/server/app-worker-stages.d.ts +37 -6
  153. package/dist/server/app-worker-stages.js +81 -9
  154. package/dist/server/artifact-compatibility.d.ts +0 -1
  155. package/dist/server/artifact-compatibility.js +1 -10
  156. package/dist/server/bfcache-identity.d.ts +7 -0
  157. package/dist/server/bfcache-identity.js +10 -1
  158. package/dist/server/cache-proof.d.ts +1 -115
  159. package/dist/server/cache-proof.js +1 -544
  160. package/dist/server/cacheability-manifest.js +1 -2
  161. package/dist/server/cacheability-request.js +13 -8
  162. package/dist/server/dev-origin-check.d.ts +2 -1
  163. package/dist/server/dev-origin-check.js +2 -1
  164. package/dist/server/dev-server.js +6 -4
  165. package/dist/server/headers.d.ts +6 -3
  166. package/dist/server/headers.js +9 -5
  167. package/dist/server/image-optimization.d.ts +5 -0
  168. package/dist/server/image-optimization.js +6 -1
  169. package/dist/server/isr-cache.d.ts +8 -2
  170. package/dist/server/isr-cache.js +30 -2
  171. package/dist/server/metadata-route-response.js +32 -15
  172. package/dist/server/middleware-matcher.js +19 -6
  173. package/dist/server/middleware-runtime.js +6 -2
  174. package/dist/server/multi-stage.d.ts +57 -12
  175. package/dist/server/multi-stage.js +13 -1
  176. package/dist/server/navigation-planner.js +1 -1
  177. package/dist/server/pages-api-route.js +28 -19
  178. package/dist/server/pages-media-type.d.ts +21 -1
  179. package/dist/server/pages-media-type.js +69 -5
  180. package/dist/server/pages-node-compat.d.ts +1 -1
  181. package/dist/server/pages-node-compat.js +54 -27
  182. package/dist/server/pages-page-data.js +2 -1
  183. package/dist/server/pages-page-handler.js +28 -26
  184. package/dist/server/pages-page-response.d.ts +9 -0
  185. package/dist/server/pages-page-response.js +18 -4
  186. package/dist/server/pages-request-pipeline.d.ts +8 -0
  187. package/dist/server/pages-request-pipeline.js +2 -2
  188. package/dist/server/pages-request-stage-entry.js +36 -14
  189. package/dist/server/pages-response-stage-entry.js +9 -3
  190. package/dist/server/pages-router-entry.js +3 -2
  191. package/dist/server/prod-server.d.ts +2 -2
  192. package/dist/server/prod-server.js +47 -9
  193. package/dist/server/request-error-log.d.ts +9 -0
  194. package/dist/server/request-error-log.js +13 -0
  195. package/dist/server/request-pipeline.d.ts +15 -4
  196. package/dist/server/request-pipeline.js +43 -15
  197. package/dist/server/rsc-completion-metadata.js +3 -0
  198. package/dist/server/shared-cache-identity.d.ts +23 -0
  199. package/dist/server/shared-cache-identity.js +36 -0
  200. package/dist/server/static-file-cache.d.ts +9 -0
  201. package/dist/server/static-file-cache.js +13 -2
  202. package/dist/server/worker-stages.d.ts +16 -3
  203. package/dist/server/worker-stages.js +23 -4
  204. package/dist/shims/cache-handler.js +2 -2
  205. package/dist/shims/cache-request-state.d.ts +23 -26
  206. package/dist/shims/cache-request-state.js +22 -57
  207. package/dist/shims/cache-runtime.d.ts +3 -1
  208. package/dist/shims/cache-runtime.js +94 -48
  209. package/dist/shims/cache.d.ts +16 -10
  210. package/dist/shims/cache.js +47 -36
  211. package/dist/shims/cacheability-classification.d.ts +2 -0
  212. package/dist/shims/cdn-cache.d.ts +22 -5
  213. package/dist/shims/client-hook-error.d.ts +2 -0
  214. package/dist/shims/client-hook-error.js +16 -1
  215. package/dist/shims/client-page-root.js +2 -2
  216. package/dist/shims/dynamic.js +9 -6
  217. package/dist/shims/error-boundary.js +2 -2
  218. package/dist/shims/fetch-cache-state.d.ts +5 -1
  219. package/dist/shims/fetch-cache-state.js +1 -3
  220. package/dist/shims/fetch-cache.d.ts +2 -1
  221. package/dist/shims/fetch-cache.js +39 -25
  222. package/dist/shims/form.js +2 -2
  223. package/dist/shims/headers.d.ts +10 -24
  224. package/dist/shims/headers.js +22 -70
  225. package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
  226. package/dist/shims/internal/navigation-untracked.js +1 -1
  227. package/dist/shims/link.js +8 -11
  228. package/dist/shims/metadata.d.ts +23 -21
  229. package/dist/shims/metadata.js +62 -24
  230. package/dist/shims/navigation-server.js +1 -1
  231. package/dist/shims/navigation.d.ts +74 -7
  232. package/dist/shims/navigation.js +184 -31
  233. package/dist/shims/navigation.react-server.js +2 -2
  234. package/dist/shims/request-state-types.d.ts +3 -2
  235. package/dist/shims/slot.d.ts +16 -0
  236. package/dist/shims/slot.js +44 -9
  237. package/dist/shims/unified-request-context.d.ts +7 -1
  238. package/dist/shims/unified-request-context.js +3 -3
  239. package/dist/utils/cache-control-metadata.d.ts +5 -0
  240. package/dist/utils/cache-control-metadata.js +9 -1
  241. package/dist/utils/cache-life-profiles.d.ts +33 -0
  242. package/dist/utils/cache-life-profiles.js +111 -0
  243. package/dist/utils/middleware-request-headers.d.ts +14 -3
  244. package/dist/utils/middleware-request-headers.js +54 -7
  245. package/dist/utils/project.d.ts +2 -2
  246. package/dist/utils/project.js +3 -16
  247. package/dist/utils/regex.d.ts +5 -0
  248. package/dist/utils/regex.js +11 -1
  249. package/dist/utils/text-stream.d.ts +10 -5
  250. package/dist/utils/text-stream.js +6 -6
  251. package/package.json +2 -1
  252. package/dist/build/layout-classification-types.d.ts +0 -60
  253. package/dist/build/layout-classification-types.js +0 -1
  254. package/dist/build/layout-classification.d.ts +0 -62
  255. package/dist/build/layout-classification.js +0 -98
  256. package/dist/build/route-classification-injector.d.ts +0 -33
  257. package/dist/build/route-classification-injector.js +0 -59
  258. package/dist/build/route-classification-manifest.d.ts +0 -54
  259. package/dist/build/route-classification-manifest.js +0 -143
  260. package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
  261. package/dist/server/app-browser-client-reuse-manifest.js +0 -101
  262. package/dist/server/app-layout-param-observation.d.ts +0 -42
  263. package/dist/server/app-layout-param-observation.js +0 -168
  264. package/dist/server/client-reuse-manifest.d.ts +0 -103
  265. package/dist/server/client-reuse-manifest.js +0 -209
  266. package/dist/server/skip-cache-proof.d.ts +0 -60
  267. package/dist/server/skip-cache-proof.js +0 -168
  268. package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
  269. package/dist/server/static-layout-client-reuse-proof.js +0 -33
  270. package/dist/utils/sorted-array.d.ts +0 -8
  271. package/dist/utils/sorted-array.js +0 -20
@@ -9,6 +9,26 @@ export declare class PagesBodyParseError extends Error {
9
9
  readonly statusCode: number;
10
10
  constructor(message: string, statusCode: number);
11
11
  }
12
- export declare function getMediaType(contentType: string | null | undefined): string;
13
12
  export declare function isJsonMediaType(mediaType: string): boolean;
13
+ /** A `TextDecoder`-shaped decoder for one request body. */
14
+ export type PagesBodyDecoder = {
15
+ decode(input?: Uint8Array, options?: {
16
+ stream?: boolean;
17
+ }): string;
18
+ };
19
+ /**
20
+ * Resolve the media type and body decoder for a Pages API request, matching
21
+ * Next.js `parseBody()`: a malformed Content-Type is treated as `text/plain`,
22
+ * the body is decoded with its `charset` (UTF-8 by default), and a charset that
23
+ * can't be decoded is rejected with `400 Invalid body`.
24
+ *
25
+ * Next.js decodes through raw-body with iconv-lite 0.4, which vinext bundles
26
+ * at the same version. It is loaded only for non-UTF-8 charsets: `TextDecoder`
27
+ * decodes UTF-8 identically, BOM stripping included, and keeps iconv-lite's
28
+ * encoding tables out of the startup path.
29
+ */
30
+ export declare function createPagesBodyDecoder(contentType: string | null | undefined): Promise<{
31
+ mediaType: string;
32
+ decoder: PagesBodyDecoder;
33
+ }>;
14
34
  //#endregion
@@ -1,3 +1,5 @@
1
+ import { __toESM } from "../_virtual/_rolldown/runtime.js";
2
+ import { Buffer } from "node:buffer";
1
3
  //#region src/server/pages-media-type.ts
2
4
  /**
3
5
  * Shared media-type helpers and body-parse error for Pages API routes.
@@ -13,12 +15,74 @@ var PagesBodyParseError = class extends Error {
13
15
  this.name = "PagesBodyParseError";
14
16
  }
15
17
  };
16
- function getMediaType(contentType) {
17
- const [type] = (contentType ?? "text/plain").split(";");
18
- return type?.trim().toLowerCase() || "text/plain";
19
- }
20
18
  function isJsonMediaType(mediaType) {
21
19
  return mediaType === "application/json" || mediaType === "application/ld+json";
22
20
  }
21
+ const TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
22
+ const PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
23
+ const QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
24
+ function parseContentType(header) {
25
+ let index = header.indexOf(";");
26
+ const type = (index === -1 ? header : header.slice(0, index)).trim();
27
+ if (!TYPE_REGEXP.test(type)) return null;
28
+ let charset;
29
+ if (index !== -1) {
30
+ const paramRegexp = new RegExp(PARAM_REGEXP);
31
+ paramRegexp.lastIndex = index;
32
+ let match;
33
+ while (match = paramRegexp.exec(header)) {
34
+ if (match.index !== index) return null;
35
+ index += match[0].length;
36
+ if (match[1].toLowerCase() !== "charset") continue;
37
+ const value = match[2];
38
+ charset = value.startsWith("\"") ? value.slice(1, -1).replace(QESC_REGEXP, "$1") : value;
39
+ }
40
+ if (index !== header.length) return null;
41
+ }
42
+ return {
43
+ mediaType: type.toLowerCase(),
44
+ charset
45
+ };
46
+ }
47
+ function iconvBodyDecoder(decoder) {
48
+ return { decode(input, options) {
49
+ let text = input ? decoder.write(Buffer.from(input.buffer, input.byteOffset, input.byteLength)) : "";
50
+ if (!options?.stream) text += decoder.end() || "";
51
+ return text;
52
+ } };
53
+ }
54
+ /**
55
+ * Resolve the media type and body decoder for a Pages API request, matching
56
+ * Next.js `parseBody()`: a malformed Content-Type is treated as `text/plain`,
57
+ * the body is decoded with its `charset` (UTF-8 by default), and a charset that
58
+ * can't be decoded is rejected with `400 Invalid body`.
59
+ *
60
+ * Next.js decodes through raw-body with iconv-lite 0.4, which vinext bundles
61
+ * at the same version. It is loaded only for non-UTF-8 charsets: `TextDecoder`
62
+ * decodes UTF-8 identically, BOM stripping included, and keeps iconv-lite's
63
+ * encoding tables out of the startup path.
64
+ */
65
+ async function createPagesBodyDecoder(contentType) {
66
+ const parsed = contentType && parseContentType(contentType) || {
67
+ mediaType: "text/plain",
68
+ charset: void 0
69
+ };
70
+ const charset = parsed.charset || "utf-8";
71
+ if (charset.toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "") === "utf8") return {
72
+ mediaType: parsed.mediaType,
73
+ decoder: new TextDecoder()
74
+ };
75
+ const iconv = (await import("../deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1))).default;
76
+ let decoder;
77
+ try {
78
+ decoder = iconv.getDecoder(charset);
79
+ } catch {
80
+ throw new PagesBodyParseError("Invalid body", 400);
81
+ }
82
+ return {
83
+ mediaType: parsed.mediaType,
84
+ decoder: iconvBodyDecoder(decoder)
85
+ };
86
+ }
23
87
  //#endregion
24
- export { PagesBodyParseError, getMediaType, isJsonMediaType };
88
+ export { PagesBodyParseError, createPagesBodyDecoder, isJsonMediaType };
@@ -7,7 +7,7 @@ export type PagesRequestQuery = Record<string, string | string[]>;
7
7
  export type PagesReqResRequest = Readable & {
8
8
  method: string;
9
9
  url: string;
10
- headers: Record<string, string>;
10
+ headers: Record<string, string | string[] | undefined>;
11
11
  query: PagesRequestQuery;
12
12
  body: unknown;
13
13
  cookies: Record<string, string>;
@@ -2,11 +2,11 @@ import { parseCookieHeader } from "../utils/parse-cookie.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
3
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
4
4
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
5
- import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
5
+ import { PagesBodyParseError, createPagesBodyDecoder, isJsonMediaType } from "./pages-media-type.js";
6
6
  import { performOnDemandRevalidate } from "./pages-revalidate.js";
7
7
  import { clearPagesPreviewData, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData } from "./pages-preview.js";
8
8
  import { decode } from "node:querystring";
9
- import { Readable, Writable } from "node:stream";
9
+ import { Readable, Stream, Writable } from "node:stream";
10
10
  //#region src/server/pages-node-compat.ts
11
11
  const MAX_PAGES_API_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;
12
12
  const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
@@ -26,11 +26,17 @@ function validateAppendedHeader(name, value) {
26
26
  if (INVALID_HEADER_VALUE_CHAR_PATTERN.test(String(item))) throw createNodeTypeError("ERR_INVALID_CHAR", `Invalid character in header content ["${name}"]`);
27
27
  }
28
28
  }
29
- async function readPagesRequestBodyWithLimit(request, maxBytes) {
30
- if (!request.body) return "";
31
- return readStreamAsTextWithLimit(request.body, maxBytes, () => {
29
+ /** The decoded body, or undefined when the request carried no body bytes. */
30
+ async function readPagesRequestBodyWithLimit(request, maxBytes, decoder) {
31
+ if (!request.body) return;
32
+ let byteLength = 0;
33
+ const text = await readStreamAsTextWithLimit(request.body, maxBytes, () => {
32
34
  throw new PagesBodyParseError("Request body too large", 413);
33
- });
35
+ }, { decode(input, options) {
36
+ byteLength += input?.byteLength ?? 0;
37
+ return decoder.decode(input, options);
38
+ } });
39
+ return byteLength > 0 ? text : void 0;
34
40
  }
35
41
  /**
36
42
  * Read and parse a Pages Router API request body for the Workers/prod path.
@@ -43,16 +49,16 @@ async function readPagesRequestBodyWithLimit(request, maxBytes) {
43
49
  * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
44
50
  */
45
51
  async function parsePagesApiBody(request, maxBytes = MAX_PAGES_API_BODY_SIZE) {
52
+ const { mediaType, decoder } = await createPagesBodyDecoder(request.headers.get("content-type"));
46
53
  if (Number.parseInt(request.headers.get("content-length") || "0", 10) > maxBytes) throw new PagesBodyParseError("Request body too large", 413);
47
- let rawBody = "";
54
+ let rawBody;
48
55
  try {
49
- rawBody = await readPagesRequestBodyWithLimit(request, maxBytes);
56
+ rawBody = await readPagesRequestBodyWithLimit(request, maxBytes, decoder);
50
57
  } catch (err) {
51
58
  if (err instanceof PagesBodyParseError) throw err;
52
59
  throw new PagesBodyParseError("Request body too large", 413);
53
60
  }
54
- const mediaType = getMediaType(request.headers.get("content-type"));
55
- if (!rawBody) return isJsonMediaType(mediaType) ? {} : mediaType === "application/x-www-form-urlencoded" ? decode(rawBody) : void 0;
61
+ if (!rawBody) return isJsonMediaType(mediaType) ? {} : mediaType === "application/x-www-form-urlencoded" ? decode("") : rawBody;
56
62
  if (isJsonMediaType(mediaType)) try {
57
63
  return JSON.parse(rawBody);
58
64
  } catch {
@@ -61,24 +67,34 @@ async function parsePagesApiBody(request, maxBytes = MAX_PAGES_API_BODY_SIZE) {
61
67
  if (mediaType === "application/x-www-form-urlencoded") return decode(rawBody);
62
68
  return rawBody;
63
69
  }
64
- async function* requestBodyChunks(request) {
65
- if (!request.body || request.bodyUsed) return;
66
- const reader = request.body.getReader();
67
- try {
68
- for (;;) {
69
- const { value, done } = await reader.read();
70
- if (done) return;
71
- yield Buffer.from(value.buffer, value.byteOffset, value.byteLength);
72
- }
73
- } finally {
74
- try {
75
- await reader.cancel();
76
- } catch {}
77
- reader.releaseLock();
78
- }
79
- }
80
70
  function createRequestReadable(request) {
81
- return Readable.from(requestBodyChunks(request), { objectMode: false });
71
+ const body = request.bodyUsed ? null : request.body;
72
+ let reader;
73
+ return new Readable({
74
+ read() {
75
+ if (!body) {
76
+ this.push(null);
77
+ return;
78
+ }
79
+ reader ??= body.getReader();
80
+ reader.read().then(({ value, done }) => {
81
+ if (this.destroyed) return;
82
+ if (done) {
83
+ this.push(null);
84
+ return;
85
+ }
86
+ this.push(Buffer.from(value.buffer, value.byteOffset, value.byteLength));
87
+ }, (error) => this.destroy(error));
88
+ },
89
+ destroy(error, callback) {
90
+ const cancelled = reader ? reader.cancel(error ?? void 0) : body?.cancel(error ?? void 0);
91
+ if (!cancelled) {
92
+ callback(error);
93
+ return;
94
+ }
95
+ cancelled.then(() => callback(error), () => callback(error));
96
+ }
97
+ });
82
98
  }
83
99
  function parsePagesRequestCookies(cookieHeader) {
84
100
  return parseCookieHeader(Array.isArray(cookieHeader) ? cookieHeader.join("; ") : cookieHeader);
@@ -189,6 +205,15 @@ var PagesResponseStream = class extends Writable {
189
205
  this.end(JSON.stringify(data));
190
206
  }
191
207
  send(data) {
208
+ if (NO_BODY_RESPONSE_STATUSES.has(this.resStatusCode)) {
209
+ this.end();
210
+ return;
211
+ }
212
+ if (data instanceof Stream) {
213
+ if (!this.resHeaders["content-type"]) this.resHeaders["content-type"] = "application/octet-stream";
214
+ data.pipe(this);
215
+ return;
216
+ }
192
217
  if (Buffer.isBuffer(data)) {
193
218
  if (!this.resHeaders["content-type"]) this.resHeaders["content-type"] = "application/octet-stream";
194
219
  this.resHeaders["content-length"] = String(data.length);
@@ -342,6 +367,8 @@ function isVinextStreamedApiResponse(response) {
342
367
  function createPagesReqRes(options) {
343
368
  const headersObj = {};
344
369
  for (const [key, value] of options.request.headers) headersObj[key.toLowerCase()] = value;
370
+ const setCookies = options.request.headers.getSetCookie();
371
+ if (setCookies.length > 1) headersObj["set-cookie"] = setCookies;
345
372
  const req = Object.assign(createRequestReadable(options.request), {
346
373
  method: options.request.method,
347
374
  url: options.url,
@@ -13,7 +13,7 @@ import { normalizeStaticPathname } from "../routing/route-pattern.js";
13
13
  import { buildCacheStateHeaders } from "./cache-headers.js";
14
14
  import { pagesPathCacheTag } from "./pages-cache-tag.js";
15
15
  import { isPageNotModified } from "./http-conditional.js";
16
- import { generatePagesETag, isPagesStreamingBot, rendersPagesNotModified } from "./pages-page-response.js";
16
+ import { applyPagesPrerenderRevalidateHeader, generatePagesETag, isPagesStreamingBot, rendersPagesNotModified } from "./pages-page-response.js";
17
17
  import { createPagesGetInitialPropsRouter, hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
18
18
  import { isSerializableProps } from "./pages-serializable-props.js";
19
19
  import { tracePagesData, tracePagesDocument } from "./pages-execution-tracing.js";
@@ -130,6 +130,7 @@ function applyPagesTerminalMissHeaders(response, revalidateSeconds, isrCachePath
130
130
  tags: [pagesPathCacheTag(isrCachePathname)]
131
131
  });
132
132
  for (const [name, value] of Object.entries(buildCacheStateHeaders("MISS"))) response.headers.set(name, value);
133
+ applyPagesPrerenderRevalidateHeader(response.headers, revalidateSeconds);
133
134
  return response;
134
135
  }
135
136
  function applyCachedPagesRepresentationHeaders(response, cacheState, entry, options) {
@@ -8,13 +8,14 @@ import { getRequestExecutionContext } from "../shims/request-context.js";
8
8
  import { extractLocaleFromUrl, resolvePagesI18nRequest } from "./pages-i18n.js";
9
9
  import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
10
10
  import { reportRequestError } from "./instrumentation.js";
11
+ import { logRequestError } from "./request-error-log.js";
11
12
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
12
13
  import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, markRouteCacheabilityExplicitResponsePolicy, markRouteCacheabilityFinalResponseUncacheable, recordRouteCacheability } from "../shims/cacheability-classification.js";
13
14
  import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, hasExplicitNonCacheableResponsePolicy, isCdnResponsePolicyHeader, shouldUseNextDeployCacheControl } from "./cache-control.js";
14
15
  import { buildMissIsrCacheControl } from "./isr-decision.js";
15
16
  import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
16
- import { coalesceOnDemandRevalidation, isrGet, isrSet, pagesIsrCacheKey, triggerBackgroundRegeneration } from "./isr-cache.js";
17
- import { ensureFetchPatch } from "../shims/fetch-cache.js";
17
+ import { coalesceOnDemandResponse, isrGet, isrSet, pagesIsrCacheKey, triggerBackgroundRegeneration } from "./isr-cache.js";
18
+ import { ensureFetchPatch, setCurrentFetchDraftMode } from "../shims/fetch-cache.js";
18
19
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
19
20
  import { getScriptNonceFromHeaderSources } from "./csp.js";
20
21
  import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
@@ -22,7 +23,7 @@ import { buildPagesReadinessNextData } from "./pages-readiness.js";
22
23
  import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
23
24
  import { setCacheStateHeaders } from "./cache-headers.js";
24
25
  import { pagesPathCacheTag } from "./pages-cache-tag.js";
25
- import { renderPagesPageResponse } from "./pages-page-response.js";
26
+ import { applyPagesPrerenderRevalidateHeader, renderPagesPageResponse } from "./pages-page-response.js";
26
27
  import { hasPagesGetInitialProps } from "./pages-get-initial-props.js";
27
28
  import { traceFindPageComponents, tracePagesDocumentStream } from "./pages-execution-tracing.js";
28
29
  import { mergePagesNotFoundSourceHeaders, resolvePagesPageData, resolvePagesStatusPageRenderPath, setPagesResponseHeader } from "./pages-page-data.js";
@@ -244,10 +245,12 @@ function createPagesPageHandler(opts) {
244
245
  hasRewrites
245
246
  });
246
247
  const isCacheabilityProbe = isRouteCacheabilityProbe();
247
- if (!isRouteMissErrorRender && options?.__forcedRoute === void 0) {
248
+ const isTopLevelPageRoute = !isRouteMissErrorRender && options?.__forcedRoute === void 0;
249
+ const isInitialPropsRender = isTopLevelPageRoute && !isStaticPropsRoute && pagesReadiness.gssp !== true && (pagesReadiness.gip === true || pagesReadiness.appGip === true);
250
+ if (isTopLevelPageRoute) {
248
251
  beginRouteCacheability("pages-page", route.pattern);
249
252
  if (isRouteCacheabilityIdentityProbe()) return new Response(null, { status: 204 });
250
- if (pagesReadiness.gssp !== true && pagesReadiness.gip !== true && !(pagesReadiness.appGip === true && !isStaticPropsRoute) && !isStaticPropsRoute) recordRouteCacheability({
253
+ if (pagesReadiness.gssp !== true && !isInitialPropsRender && !isStaticPropsRoute) recordRouteCacheability({
251
254
  cacheable: true,
252
255
  cacheControl: STATIC_CACHE_CONTROL
253
256
  });
@@ -258,23 +261,10 @@ function createPagesPageHandler(opts) {
258
261
  const isStaticPropsRender = isStaticPropsRoute && typeof pageModule.getServerSideProps !== "function";
259
262
  if (!options?.__skipOnDemandCoalesce && !options?.__forcedRoute && !cacheIdentityDiverges && isStaticPropsRoute && isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"))) {
260
263
  const cacheKey = pageIsrCacheKey("pages", routeUrl.split("?")[0]);
261
- const snapshot = await coalesceOnDemandRevalidation(cacheKey, async () => {
262
- const response = await renderPage(request, url, manifest, middlewareHeaders, {
263
- ...options,
264
- __skipOnDemandCoalesce: true
265
- }, initialResponseHeaders);
266
- return {
267
- body: request.method === "HEAD" || response.status === 204 || response.status === 304 ? null : new Uint8Array(await response.arrayBuffer()),
268
- headers: [...response.headers.entries()],
269
- status: response.status,
270
- statusText: response.statusText
271
- };
272
- });
273
- return new Response(snapshot.body?.slice() ?? null, {
274
- headers: snapshot.headers,
275
- status: snapshot.status,
276
- statusText: snapshot.statusText
277
- });
264
+ return coalesceOnDemandResponse(cacheKey, request.method, () => renderPage(request, url, manifest, middlewareHeaders, {
265
+ ...options,
266
+ __skipOnDemandCoalesce: true
267
+ }, initialResponseHeaders));
278
268
  }
279
269
  const routePattern = patternToNextFormat(route.pattern);
280
270
  const renderStatusCode = renderStatusCodeOverride ?? (routePattern === "/404" ? 404 : void 0);
@@ -283,7 +273,10 @@ function createPagesPageHandler(opts) {
283
273
  const renderRouteUrl = isStaticPropsRender && isStatusPageIdentity ? resolvePagesStatusPageRenderPath(statusPagePathname, vinextConfig.trailingSlash, originalRequestUrl.pathname) : isStaticPropsRender ? routeUrl.split("?")[0] : routeUrl;
284
274
  const routerAsPathSource = isStaticPropsRender ? renderRouteUrl : renderAsPath ?? renderRouteUrl;
285
275
  const routerAsPath = i18nConfig ? extractLocaleFromUrl(routerAsPathSource, i18nConfig, locale).url : routerAsPathSource;
286
- const uCtx = createRequestContext({ executionContext: getRequestExecutionContext() });
276
+ const uCtx = createRequestContext({
277
+ executionContext: getRequestExecutionContext(),
278
+ isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER))
279
+ });
287
280
  let pageReqRes = null;
288
281
  const pageResponseSent = () => pageReqRes?.res.headersSent === true;
289
282
  const sendsEarly = isStaticPropsRoute && !isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate"));
@@ -292,7 +285,7 @@ function createPagesPageHandler(opts) {
292
285
  resolveSentResponse = resolve;
293
286
  });
294
287
  const reportSsrError = async (e) => {
295
- console.error("[vinext] SSR error:", e);
288
+ logRequestError("[vinext] SSR error:", e);
296
289
  await reportRequestError(e, {
297
290
  path: url,
298
291
  method: request.method,
@@ -322,6 +315,7 @@ function createPagesPageHandler(opts) {
322
315
  shouldClear: false
323
316
  };
324
317
  const previewData = preview.data;
318
+ setCurrentFetchDraftMode(previewData !== false);
325
319
  const pagesNextData = {
326
320
  ...pagesReadiness,
327
321
  ...previewData === false ? {} : { isPreview: true }
@@ -444,6 +438,7 @@ function createPagesPageHandler(opts) {
444
438
  clientTraceMetadata: shouldEmitPagesClientTraceMetadata(pageModule, AppComponent) ? vinextConfig.clientTraceMetadata : void 0,
445
439
  documentReqRes: render.documentReqRes,
446
440
  gsspRes: render.gsspRes,
441
+ isInitialPropsRender,
447
442
  isrCacheKey: pageIsrCacheKey,
448
443
  isrCachePathname,
449
444
  expireSeconds: render.expireSeconds,
@@ -594,6 +589,7 @@ function createPagesPageHandler(opts) {
594
589
  notFoundResponse = stripPagesNotFoundFramingHeaders(notFoundResponse);
595
590
  if (isOnDemandRevalidate) notFoundResponse = withPagesCacheState(notFoundResponse, "REVALIDATED", isrCachePathname);
596
591
  else if (pageDataResult.cacheState) notFoundResponse = withPagesCacheState(notFoundResponse, pageDataResult.cacheState);
592
+ if (pageDataResult.revalidateSeconds !== void 0) applyPagesPrerenderRevalidateHeader(notFoundResponse.headers, pageDataResult.revalidateSeconds);
597
593
  return finalizePagesPreviewResponse(withBrowserPolicy(notFoundResponse), preview);
598
594
  }
599
595
  if (pageDataResult.kind === "response") {
@@ -623,6 +619,7 @@ function createPagesPageHandler(opts) {
623
619
  });
624
620
  if (isDataReq) {
625
621
  const headers = new Headers();
622
+ let resHasCacheControl = false;
626
623
  if (gsspRes && typeof gsspRes.getHeaders === "function") {
627
624
  const gsspHeaders = gsspRes.getHeaders();
628
625
  for (const k of Object.keys(gsspHeaders)) {
@@ -631,10 +628,15 @@ function createPagesPageHandler(opts) {
631
628
  if (k.toLowerCase() === "set-cookie" && Array.isArray(v)) for (const cookie of v) headers.append(k, String(cookie));
632
629
  else headers.set(k, Array.isArray(v) ? v.join(", ") : String(v));
633
630
  }
631
+ resHasCacheControl = headers.has("Cache-Control");
632
+ } else if (isInitialPropsRender && documentReqRes) {
633
+ const resHeaders = documentReqRes.res.getHeaders();
634
+ for (const [name, value] of Object.entries(resHeaders)) if (isCdnResponsePolicyHeader(name)) setPagesResponseHeader(headers, name, value);
635
+ resHasCacheControl = Boolean(resHeaders["cache-control"]);
634
636
  }
635
637
  if (hasCdnResponsePolicy(headers)) markRouteCacheabilityExplicitResponsePolicy();
636
- if (gsspRes) {
637
- if (!headers.has("Cache-Control")) headers.set("Cache-Control", NEVER_CACHE_CONTROL);
638
+ if (gsspRes || isInitialPropsRender) {
639
+ if (!resHasCacheControl) headers.set("Cache-Control", NEVER_CACHE_CONTROL);
638
640
  } else if (isStaticPropsRoute) {
639
641
  if (isrRevalidateSeconds !== null) applyCdnResponseHeaders(headers, {
640
642
  cacheControl: buildMissIsrCacheControl(isrRevalidateSeconds, vinextConfig.expireTime),
@@ -17,6 +17,13 @@ export declare function generatePagesETag(payload: string): string;
17
17
  * A page whose status carries no body has nothing to store.
18
18
  */
19
19
  export declare function rendersPagesNotModified(status: number): boolean;
20
+ /**
21
+ * Hand the revalidate getStaticProps returned to build/prerender.ts, which
22
+ * records it in vinext-prerender.json like Next.js's `initialRevalidateSeconds`.
23
+ * The CDN adapter may rewrite Cache-Control, so the build cannot read it there.
24
+ * Only build-time renders carry this header.
25
+ */
26
+ export declare function applyPagesPrerenderRevalidateHeader(headers: Headers, revalidateSeconds: number | false): void;
20
27
  type PagesFontPreload = {
21
28
  href: string;
22
29
  type: string;
@@ -79,6 +86,8 @@ type RenderPagesPageResponseOptions = {
79
86
  setDocumentInitialHead?: ((head: ReactNode[]) => void) | undefined;
80
87
  documentReqRes?: PagesDocumentReqRes | null;
81
88
  gsspRes: PagesGsspResponse | null;
89
+ /** A page or custom `_app` getInitialProps render; rendered per request like gSSP. */
90
+ isInitialPropsRender?: boolean;
82
91
  isrCacheKey: (router: string, pathname: string) => string;
83
92
  /** Filesystem-route identity used for ISR persistence and cache tags. */
84
93
  isrCachePathname?: string;
@@ -1,7 +1,8 @@
1
1
  import { isBotUserAgent } from "../utils/html-limited-bots.js";
2
- import { NEXTJS_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
2
+ import { NEXTJS_CACHE_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
3
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
4
  import { reportRequestError } from "./instrumentation.js";
5
+ import { logRequestError } from "./request-error-log.js";
5
6
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
6
7
  import { markRouteCacheabilityExplicitResponsePolicy } from "../shims/cacheability-classification.js";
7
8
  import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, shouldUseNextDeployCacheControl } from "./cache-control.js";
@@ -17,6 +18,7 @@ import { spliceDocumentHeadClose, spliceDocumentHeadOpen, spliceDocumentScripts,
17
18
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
18
19
  import { setCacheStateHeaders } from "./cache-headers.js";
19
20
  import { pagesPathCacheTag } from "./pages-cache-tag.js";
21
+ import { applyPrerenderCacheLifeHeader } from "./prerender-cache-life-header.js";
20
22
  import { readStreamAsText } from "../utils/text-stream.js";
21
23
  import { loadUserDocumentInitialProps, runDocumentRenderPage } from "./pages-document-initial-props.js";
22
24
  import { callDocumentGetInitialProps } from "./document-initial-head.js";
@@ -42,6 +44,17 @@ function generatePagesETag(payload) {
42
44
  function rendersPagesNotModified(status) {
43
45
  return status === 204 || status === 205 || status === 304 || getCdnCacheAdapter().deferNotModifiedResponse?.() !== true;
44
46
  }
47
+ /**
48
+ * Hand the revalidate getStaticProps returned to build/prerender.ts, which
49
+ * records it in vinext-prerender.json like Next.js's `initialRevalidateSeconds`.
50
+ * The CDN adapter may rewrite Cache-Control, so the build cannot read it there.
51
+ * Only build-time renders carry this header.
52
+ */
53
+ function applyPagesPrerenderRevalidateHeader(headers, revalidateSeconds) {
54
+ if (typeof process === "undefined" || process.env?.VINEXT_PRERENDER !== "1") return;
55
+ headers.delete(VINEXT_PRERENDER_CACHE_LIFE_HEADER);
56
+ if (typeof revalidateSeconds === "number") applyPrerenderCacheLifeHeader(headers, { revalidate: revalidateSeconds });
57
+ }
45
58
  function buildPagesFontHeadHtml(fontLinks, fontPreloads, fontStyles, scriptNonce) {
46
59
  let html = "";
47
60
  const nonceAttr = createNonceAttribute(scriptNonce);
@@ -121,7 +134,7 @@ async function buildPagesCompositeStream(bodyStream, shellPrefix, shellSuffix) {
121
134
  } });
122
135
  }
123
136
  async function reportPagesIsrCacheWriteError(error, cacheKey, routePattern) {
124
- console.error(`[vinext] Pages ISR cache write failed for ${cacheKey}:`, error);
137
+ logRequestError(`[vinext] Pages ISR cache write failed for ${cacheKey}:`, error);
125
138
  try {
126
139
  await reportRequestError(error, {
127
140
  path: cacheKey,
@@ -284,12 +297,13 @@ async function renderPagesPageResponse(options) {
284
297
  cacheControl: buildMissIsrCacheControl(options.isrRevalidateSeconds, options.expireSeconds),
285
298
  tags: [pathTag]
286
299
  });
300
+ applyPagesPrerenderRevalidateHeader(responseHeaders, options.isrRevalidateSeconds);
287
301
  if (options.isOnDemandRevalidate) {
288
302
  responseHeaders.set(NEXTJS_CACHE_HEADER, "REVALIDATED");
289
303
  responseHeaders.set(VINEXT_REVALIDATED_CACHE_TAG_HEADER, encodeURIComponent(pathTag));
290
304
  } else setCacheStateHeaders(responseHeaders, "MISS");
291
305
  } else if (options.isStaticPropsRoute && shouldUseNextDeployCacheControl()) responseHeaders.set("Cache-Control", BROWSER_REVALIDATE_CACHE_CONTROL);
292
- else if (options.gsspRes && !userSetCacheControl) responseHeaders.set("Cache-Control", NEVER_CACHE_CONTROL);
306
+ else if ((options.gsspRes || options.isInitialPropsRender || options.isFallback) && !userSetCacheControl) responseHeaders.set("Cache-Control", NEVER_CACHE_CONTROL);
293
307
  if (options.fontLinkHeader) responseHeaders.set("Link", options.fontLinkHeader);
294
308
  if (options.userAgent && isPagesStreamingBot(options.userAgent)) {
295
309
  const fullHtml = await readStreamAsText(compositeStream);
@@ -314,4 +328,4 @@ async function renderPagesPageResponse(options) {
314
328
  }), { __vinextStreamedHtmlResponse: true });
315
329
  }
316
330
  //#endregion
317
- export { buildPagesNextDataScript, generatePagesETag, isPagesStreamingBot, renderPagesPageResponse, rendersPagesNotModified };
331
+ export { applyPagesPrerenderRevalidateHeader, buildPagesNextDataScript, generatePagesETag, isPagesStreamingBot, renderPagesPageResponse, rendersPagesNotModified };
@@ -84,6 +84,14 @@ export type PagesPipelineDeps = {
84
84
  dataNotFoundResponse?: Response | null;
85
85
  renderPage?: ((request: Request, resolvedUrl: string, options?: PagesRenderOptions, stagedHeaders?: Headers) => Promise<Response>) | null;
86
86
  handleApi?: ((request: Request, apiUrl: string, ctx: unknown, stagedHeaders: Headers) => Promise<Response>) | null;
87
+ /**
88
+ * `handleApi` installs the staged headers on the handler's `res` before user
89
+ * code runs, as Next.js does, so its response already reflects any header the
90
+ * handler replaced and only middleware's status is applied here.
91
+ * Workers leaves this unset: its response stage strips the inherited cookies
92
+ * so they are not stored, and this merge adds them back.
93
+ */
94
+ handleApiAppliesStagedHeaders?: boolean;
87
95
  /**
88
96
  * Optional override for proxying external rewrite destinations.
89
97
  * When supplied, the pipeline calls this instead of proxyExternalRequest(currentRequest, url).
@@ -14,8 +14,8 @@ import { buildMiddlewarePrefetchSkipResponse } from "./pages-data-route.js";
14
14
  import { markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
15
15
  import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
16
16
  import { mergeRewriteQuery } from "../utils/query.js";
17
- import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
18
17
  import { setFrameworkRequestRoute } from "./request-tracing.js";
18
+ import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
19
19
  import { applyConfigHeadersToHeaderRecord } from "./config-headers.js";
20
20
  import { finalizeMissingStaticAssetResponse, mergeHeaders } from "./worker-utils.js";
21
21
  //#region src/server/pages-request-pipeline.ts
@@ -310,7 +310,7 @@ async function runPagesRequest(request, deps) {
310
310
  apiRequest = cloneRequestWithUrl(request, apiRequestUrl.toString());
311
311
  }
312
312
  const response = await deps.handleApi(apiRequest, apiLookupUrl, deps.ctx ?? null, headersFromRecord(middlewareHeaders));
313
- const merged = mergeHeaders(response, middlewareHeaders, middlewareStatus);
313
+ const merged = mergeHeaders(response, deps.handleApiAppliesStagedHeaders ? {} : middlewareHeaders, middlewareStatus);
314
314
  if (merged !== response) merged.__vinextStreamedApiResponse = response.__vinextStreamedApiResponse;
315
315
  return {
316
316
  type: "response",