vinext 0.2.1 → 1.0.0-beta.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 (236) hide show
  1. package/README.md +67 -30
  2. package/dist/build/assets-ignore.js +1 -1
  3. package/dist/build/clean-output.js +1 -1
  4. package/dist/build/client-build-config.d.ts +13 -92
  5. package/dist/build/client-build-config.js +23 -99
  6. package/dist/build/css-url-assets.js +3 -3
  7. package/dist/build/google-fonts/fallback-metrics.js +1 -1
  8. package/dist/build/google-fonts/font-metadata.js +1 -1
  9. package/dist/build/inject-pregenerated-paths.js +1 -1
  10. package/dist/build/inline-css.js +2 -5
  11. package/dist/build/module-dependency-cache.d.ts +4 -0
  12. package/dist/build/module-dependency-cache.js +13 -0
  13. package/dist/build/next-client-runtime-manifests.js +1 -1
  14. package/dist/build/pages-client-assets-module.js +1 -1
  15. package/dist/build/precompress.js +7 -7
  16. package/dist/build/prerender-paths.d.ts +23 -0
  17. package/dist/build/prerender-paths.js +291 -0
  18. package/dist/build/prerender-server-pool.js +2 -2
  19. package/dist/build/prerender.d.ts +12 -1
  20. package/dist/build/prerender.js +2 -2
  21. package/dist/build/preview-credentials.d.ts +11 -0
  22. package/dist/build/preview-credentials.js +19 -0
  23. package/dist/build/report.d.ts +0 -3
  24. package/dist/build/report.js +2 -4
  25. package/dist/build/run-prerender.d.ts +2 -11
  26. package/dist/build/run-prerender.js +2 -10
  27. package/dist/build/server-manifest.js +1 -1
  28. package/dist/build/ssr-manifest.d.ts +4 -0
  29. package/dist/build/ssr-manifest.js +10 -6
  30. package/dist/build/standalone.js +37 -37
  31. package/dist/cache/cache-adapters-virtual.d.ts +7 -17
  32. package/dist/cache/cache-adapters-virtual.js +35 -2
  33. package/dist/check.d.ts +0 -16
  34. package/dist/check.js +17 -34
  35. package/dist/cli.js +86 -101
  36. package/dist/client/instrumentation-client-inject.js +1 -1
  37. package/dist/client/pages-router-link-navigation.js +1 -1
  38. package/dist/config/config-matchers.js +2 -2
  39. package/dist/config/dotenv.js +1 -1
  40. package/dist/config/next-config.d.ts +4 -1
  41. package/dist/config/next-config.js +82 -16
  42. package/dist/config/prerender.d.ts +12 -2
  43. package/dist/config/prerender.js +22 -12
  44. package/dist/config/server-external-packages.js +1 -1
  45. package/dist/config/tsconfig-paths.js +7 -3
  46. package/dist/{node_modules/.pnpm/am-i-vibing@0.5.0/node_modules → deps/.pnpm/am-i-vibing@0.5.0/deps}/am-i-vibing/dist/detector-1yx2Hoe0.js +2 -2
  47. package/dist/deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js +50 -0
  48. package/dist/entries/app-rsc-entry.js +12 -5
  49. package/dist/entries/app-rsc-manifest.js +4 -4
  50. package/dist/entries/pages-client-entry.js +6 -5
  51. package/dist/entries/pages-server-entry.js +15 -26
  52. package/dist/entries/runtime-entry-module.js +2 -2
  53. package/dist/image/image-adapters-virtual.js +1 -0
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.js +500 -338
  56. package/dist/init-cloudflare.js +13 -4
  57. package/dist/init-platform.d.ts +10 -1
  58. package/dist/init-platform.js +79 -13
  59. package/dist/init.d.ts +11 -3
  60. package/dist/init.js +133 -35
  61. package/dist/plugins/ast-utils.js +1 -1
  62. package/dist/plugins/dynamic-preload-metadata.js +7 -7
  63. package/dist/plugins/extensionless-dynamic-import.js +1 -1
  64. package/dist/plugins/fonts.js +3 -3
  65. package/dist/plugins/ignore-dynamic-requests.js +13 -8
  66. package/dist/plugins/import-meta-url.js +16 -17
  67. package/dist/plugins/middleware-export-validation.js +1 -1
  68. package/dist/plugins/middleware-server-only.js +2 -2
  69. package/dist/plugins/og-asset-ownership.js +7 -6
  70. package/dist/plugins/og-assets.js +4 -5
  71. package/dist/plugins/optimize-imports.js +12 -13
  72. package/dist/plugins/postcss.js +1 -1
  73. package/dist/plugins/remove-console.js +1 -1
  74. package/dist/plugins/require-context.js +1 -1
  75. package/dist/plugins/sass.js +2 -2
  76. package/dist/plugins/server-externals-manifest.js +1 -1
  77. package/dist/plugins/strip-server-exports.js +1 -1
  78. package/dist/plugins/styled-jsx.js +3 -2
  79. package/dist/plugins/typeof-window.js +1 -1
  80. package/dist/routing/app-route-graph.d.ts +3 -10
  81. package/dist/routing/app-route-graph.js +28 -76
  82. package/dist/routing/app-router.d.ts +0 -5
  83. package/dist/routing/app-router.js +0 -5
  84. package/dist/routing/file-matcher.d.ts +2 -6
  85. package/dist/routing/file-matcher.js +10 -11
  86. package/dist/routing/pages-router.js +3 -3
  87. package/dist/server/api-handler.js +41 -33
  88. package/dist/server/app-browser-entry.js +15 -11
  89. package/dist/server/app-browser-navigation-controller.js +9 -4
  90. package/dist/server/app-browser-server-action-client.js +1 -1
  91. package/dist/server/app-elements-wire.d.ts +2 -1
  92. package/dist/server/app-fallback-renderer.d.ts +8 -0
  93. package/dist/server/app-fallback-renderer.js +13 -1
  94. package/dist/server/app-layout-param-observation.d.ts +1 -1
  95. package/dist/server/app-page-boundary-render.d.ts +14 -1
  96. package/dist/server/app-page-boundary-render.js +107 -54
  97. package/dist/server/app-page-cache-render.d.ts +1 -1
  98. package/dist/server/app-page-dispatch.d.ts +2 -1
  99. package/dist/server/app-page-dispatch.js +29 -40
  100. package/dist/server/app-page-element-builder.d.ts +2 -1
  101. package/dist/server/app-page-element-builder.js +3 -3
  102. package/dist/server/app-page-execution.d.ts +3 -1
  103. package/dist/server/app-page-execution.js +31 -39
  104. package/dist/server/app-page-render.d.ts +1 -1
  105. package/dist/server/app-page-request.js +1 -1
  106. package/dist/server/app-page-route-wiring.js +4 -4
  107. package/dist/server/app-route-handler-execution.d.ts +1 -1
  108. package/dist/server/app-route-tree-prefetch.js +1 -1
  109. package/dist/server/app-rsc-cache-busting.js +1 -2
  110. package/dist/server/app-rsc-handler.js +2 -2
  111. package/dist/server/app-rsc-redirect-flight.d.ts +66 -0
  112. package/dist/server/app-rsc-redirect-flight.js +71 -0
  113. package/dist/server/app-rsc-render-mode.d.ts +2 -5
  114. package/dist/server/app-rsc-render-mode.js +2 -12
  115. package/dist/server/app-segment-config.js +2 -2
  116. package/dist/server/app-server-action-execution.js +3 -3
  117. package/dist/server/app-ssr-entry.js +4 -1
  118. package/dist/server/app-ssr-stream.d.ts +2 -1
  119. package/dist/server/app-ssr-stream.js +4 -1
  120. package/dist/server/cache-proof.js +1 -1
  121. package/dist/server/default-global-error-module.d.ts +3 -1
  122. package/dist/server/default-not-found-module.d.ts +3 -1
  123. package/dist/server/dev-lockfile.js +2 -3
  124. package/dist/server/dev-module-runner.js +1 -1
  125. package/dist/server/dev-origin-check.d.ts +2 -2
  126. package/dist/server/dev-origin-check.js +2 -2
  127. package/dist/server/dev-route-files.js +1 -1
  128. package/dist/server/dev-server.js +256 -164
  129. package/dist/server/dev-stack-sourcemap.js +4 -3
  130. package/dist/server/headers.d.ts +3 -1
  131. package/dist/server/headers.js +3 -1
  132. package/dist/server/image-optimization.d.ts +12 -1
  133. package/dist/server/image-optimization.js +15 -3
  134. package/dist/server/implicit-tags.js +2 -1
  135. package/dist/server/instrumentation.js +2 -2
  136. package/dist/server/isr-cache.d.ts +12 -4
  137. package/dist/server/isr-cache.js +3 -3
  138. package/dist/server/metadata-routes.js +4 -4
  139. package/dist/server/middleware-response-headers.js +1 -1
  140. package/dist/server/middleware-runtime.js +1 -1
  141. package/dist/server/middleware.d.ts +1 -0
  142. package/dist/server/middleware.js +1 -1
  143. package/dist/server/navigation-planner.d.ts +2 -0
  144. package/dist/server/navigation-planner.js +8 -2
  145. package/dist/server/next-error-digest.d.ts +9 -24
  146. package/dist/server/next-error-digest.js +23 -15
  147. package/dist/server/operation-token.js +1 -1
  148. package/dist/server/pages-body-parser-config.js +2 -1
  149. package/dist/server/pages-dev-hydration.d.ts +14 -0
  150. package/dist/server/pages-dev-hydration.js +83 -0
  151. package/dist/server/pages-dev-module-url.js +2 -2
  152. package/dist/server/pages-node-compat.d.ts +13 -6
  153. package/dist/server/pages-node-compat.js +44 -45
  154. package/dist/server/pages-page-data.d.ts +1 -1
  155. package/dist/server/pages-page-data.js +5 -4
  156. package/dist/server/pages-page-handler.js +61 -29
  157. package/dist/server/pages-page-response.d.ts +2 -2
  158. package/dist/server/pages-page-response.js +2 -2
  159. package/dist/server/pages-preview.d.ts +26 -0
  160. package/dist/server/pages-preview.js +165 -0
  161. package/dist/server/pages-readiness.d.ts +2 -1
  162. package/dist/server/pages-readiness.js +4 -2
  163. package/dist/server/pages-request-pipeline.js +1 -1
  164. package/dist/server/prerender-manifest.d.ts +15 -1
  165. package/dist/server/prerender-manifest.js +29 -1
  166. package/dist/server/prod-server.d.ts +6 -5
  167. package/dist/server/prod-server.js +15 -15
  168. package/dist/server/request-pipeline.js +1 -1
  169. package/dist/server/seed-cache.js +1 -1
  170. package/dist/server/socket-error-backstop.js +1 -1
  171. package/dist/server/static-file-cache.js +8 -9
  172. package/dist/server/worker-utils.js +1 -1
  173. package/dist/shims/cache.d.ts +1 -1
  174. package/dist/shims/cache.js +2 -1
  175. package/dist/shims/cdn-cache.d.ts +2 -7
  176. package/dist/shims/cdn-cache.js +2 -14
  177. package/dist/shims/constants.js +1 -1
  178. package/dist/shims/error-boundary.d.ts +4 -4
  179. package/dist/shims/error.d.ts +21 -5
  180. package/dist/shims/error.js +52 -14
  181. package/dist/shims/fetch-cache.js +1 -1
  182. package/dist/shims/font-utils.js +1 -1
  183. package/dist/shims/form.d.ts +1 -1
  184. package/dist/shims/head.js +3 -3
  185. package/dist/shims/headers.js +6 -4
  186. package/dist/shims/internal/pages-data-fetch-dedup.js +5 -3
  187. package/dist/shims/layout-segment-context.d.ts +1 -1
  188. package/dist/shims/link.d.ts +3 -1
  189. package/dist/shims/link.js +6 -3
  190. package/dist/shims/navigation-errors.d.ts +2 -1
  191. package/dist/shims/navigation-errors.js +9 -13
  192. package/dist/shims/navigation.d.ts +1 -1
  193. package/dist/shims/navigation.js +5 -5
  194. package/dist/shims/request-state-types.d.ts +2 -2
  195. package/dist/shims/router-state.d.ts +1 -0
  196. package/dist/shims/router.d.ts +2 -1
  197. package/dist/shims/router.js +18 -11
  198. package/dist/shims/script.js +1 -1
  199. package/dist/shims/server.js +2 -2
  200. package/dist/shims/slot.d.ts +1 -1
  201. package/dist/shims/thenable-params.js +1 -1
  202. package/dist/shims/unified-request-context.d.ts +1 -1
  203. package/dist/typegen.js +9 -11
  204. package/dist/utils/client-build-manifest.js +2 -2
  205. package/dist/utils/client-entry-manifest.js +1 -1
  206. package/dist/utils/client-runtime-metadata.js +1 -1
  207. package/dist/utils/commonjs-loader.js +3 -3
  208. package/dist/utils/mdx-scan.js +1 -1
  209. package/dist/utils/path.d.ts +1 -13
  210. package/dist/utils/path.js +1 -15
  211. package/dist/utils/plugin-options.d.ts +4 -0
  212. package/dist/utils/plugin-options.js +8 -0
  213. package/dist/utils/project.d.ts +1 -7
  214. package/dist/utils/project.js +2 -8
  215. package/dist/utils/public-routes.js +2 -2
  216. package/dist/utils/react-version.js +1 -1
  217. package/dist/utils/redirect-digest.d.ts +9 -0
  218. package/dist/utils/redirect-digest.js +25 -0
  219. package/dist/utils/vinext-root.js +1 -1
  220. package/dist/utils/vite-version.d.ts +6 -13
  221. package/dist/utils/vite-version.js +68 -34
  222. package/package.json +33 -14
  223. package/dist/cloudflare/index.d.ts +0 -3
  224. package/dist/cloudflare/index.js +0 -3
  225. package/dist/packages/cloudflare/src/cache/cdn-adapter.runtime.js +0 -102
  226. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +0 -126
  227. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +0 -442
  228. package/dist/packages/cloudflare/src/deploy-config.js +0 -150
  229. package/dist/packages/cloudflare/src/deploy-help.js +0 -55
  230. package/dist/packages/cloudflare/src/deploy.js +0 -272
  231. package/dist/packages/cloudflare/src/tpr.d.ts +0 -45
  232. package/dist/packages/cloudflare/src/tpr.js +0 -582
  233. package/dist/packages/cloudflare/src/utils/cache-control-metadata.js +0 -20
  234. /package/dist/build/google-fonts/{fallback-metrics-data.js → fallback-metrics-data.json.js} +0 -0
  235. /package/dist/build/google-fonts/{font-data.js → font-data.json.js} +0 -0
  236. /package/dist/{node_modules/.pnpm/process-ancestry@0.1.0/node_modules → deps/.pnpm/process-ancestry@0.1.0/deps}/process-ancestry/dist/index.js +0 -0
@@ -1,5 +1,6 @@
1
1
  import { PagesBodyParseError } from "./pages-media-type.js";
2
2
  import { RevalidateOptions } from "./pages-revalidate.js";
3
+ import { PagesPreviewData } from "./pages-preview.js";
3
4
  import { Readable, Writable } from "node:stream";
4
5
 
5
6
  //#region src/server/pages-node-compat.d.ts
@@ -11,6 +12,9 @@ type PagesReqResRequest = Readable & {
11
12
  query: PagesRequestQuery;
12
13
  body: unknown;
13
14
  cookies: Record<string, string>;
15
+ preview?: true;
16
+ draftMode?: true;
17
+ previewData: PagesPreviewData | false;
14
18
  };
15
19
  type PagesReqResHeaders = {
16
20
  [key: string]: string | number | boolean | string[];
@@ -24,13 +28,19 @@ type PagesReqResResponse = Writable & {
24
28
  status: (code: number) => PagesReqResResponse;
25
29
  json: (data: unknown) => void;
26
30
  send: (data: unknown) => void;
27
- redirect: (statusOrUrl: number | string, url?: string) => void;
31
+ redirect: (statusOrUrl: number | string, url?: string) => PagesReqResResponse;
28
32
  getHeaders: () => PagesReqResHeaders;
29
33
  revalidate: (urlPath: string, opts?: RevalidateOptions) => Promise<void>;
30
34
  setPreviewData: (data: object | string, options?: {
31
35
  maxAge?: number;
32
36
  path?: string;
33
37
  }) => PagesReqResResponse;
38
+ clearPreviewData: (options?: {
39
+ path?: string;
40
+ }) => PagesReqResResponse;
41
+ setDraftMode: (options?: {
42
+ enable?: boolean;
43
+ }) => PagesReqResResponse;
34
44
  };
35
45
  type PagesRequestCookiesCarrier = {
36
46
  headers: {
@@ -49,7 +59,6 @@ type CreatePagesReqResResult = {
49
59
  res: PagesReqResResponse;
50
60
  responsePromise: Promise<Response>;
51
61
  };
52
- type PagesPreviewData = object | string;
53
62
  /**
54
63
  * Read and parse a Pages Router API request body for the Workers/prod path.
55
64
  *
@@ -61,13 +70,11 @@ type PagesPreviewData = object | string;
61
70
  * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
62
71
  */
63
72
  declare function parsePagesApiBody(request: Request, maxBytes?: number): Promise<unknown>;
64
- declare function getPagesPreviewDataFromCookieHeader(cookieHeader: string | string[] | null | undefined, options?: {
65
- isOnDemandRevalidate?: boolean;
66
- }): PagesPreviewData | false;
67
73
  declare function getPagesPreviewData(request: Request, options?: {
68
74
  isOnDemandRevalidate?: boolean;
69
75
  }): PagesPreviewData | false;
70
76
  declare function attachPagesRequestCookies(req: PagesRequestCookiesCarrier): void;
77
+ declare function attachPagesPreviewApi(req: PagesReqResRequest, res: PagesReqResResponse): void;
71
78
  declare function createPagesReqRes(options: CreatePagesReqResOptions): CreatePagesReqResResult;
72
79
  //#endregion
73
- export { PagesBodyParseError as PagesApiBodyParseError, PagesPreviewData, PagesReqResRequest, PagesReqResResponse, PagesRequestQuery, attachPagesRequestCookies, createPagesReqRes, getPagesPreviewData, getPagesPreviewDataFromCookieHeader, parsePagesApiBody };
80
+ export { PagesBodyParseError as PagesApiBodyParseError, PagesReqResRequest, PagesReqResResponse, PagesRequestQuery, attachPagesPreviewApi, attachPagesRequestCookies, createPagesReqRes, getPagesPreviewData, parsePagesApiBody };
@@ -1,9 +1,9 @@
1
1
  import { parseCookieHeader } from "../utils/parse-cookie.js";
2
- import { getRevalidateSecret, isRevalidateSecret } from "./isr-cache.js";
3
2
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
4
3
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
5
4
  import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
6
5
  import { performOnDemandRevalidate } from "./pages-revalidate.js";
6
+ import { clearPagesPreviewData, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData } from "./pages-preview.js";
7
7
  import { decode } from "node:querystring";
8
8
  import { Readable, Writable } from "node:stream";
9
9
  //#region src/server/pages-node-compat.ts
@@ -65,44 +65,12 @@ function createRequestReadable(request) {
65
65
  function parsePagesRequestCookies(cookieHeader) {
66
66
  return parseCookieHeader(Array.isArray(cookieHeader) ? cookieHeader.join("; ") : cookieHeader);
67
67
  }
68
- function serializePreviewCookie(name, value, options = {}) {
69
- const parts = [
70
- `${name}=${encodeURIComponent(value)}`,
71
- "HttpOnly",
72
- `Path=${options.path ?? "/"}`,
73
- process.env.NODE_ENV !== "development" ? "SameSite=None" : "SameSite=Lax"
74
- ];
75
- if (process.env.NODE_ENV !== "development") parts.push("Secure");
76
- if (options.maxAge !== void 0) parts.push(`Max-Age=${Math.trunc(options.maxAge)}`);
77
- return parts.join("; ");
78
- }
79
- function decodePagesPreviewPayload(payload) {
80
- try {
81
- const decoded = Buffer.from(payload, "base64url").toString("utf8");
82
- const value = JSON.parse(decoded);
83
- return typeof value === "object" && value !== null ? value : String(value);
84
- } catch {
85
- return false;
86
- }
87
- }
88
68
  function getPagesPreviewDataFromCookieHeader(cookieHeader, options = {}) {
89
- if (options.isOnDemandRevalidate) return false;
90
- const cookies = parsePagesRequestCookies(cookieHeader);
91
- const bypass = cookies.__prerender_bypass;
92
- const payload = cookies.__next_preview_data;
93
- if (!bypass && !payload) return false;
94
- if (!isRevalidateSecret(bypass)) return false;
95
- if (!payload) return {};
96
- return decodePagesPreviewPayload(payload);
69
+ return getPagesPreviewState(cookieHeader, options).data;
97
70
  }
98
71
  function getPagesPreviewData(request, options = {}) {
99
72
  return getPagesPreviewDataFromCookieHeader(request.headers.get("cookie"), options);
100
73
  }
101
- function normalizeSetCookieHeader(value) {
102
- if (value === void 0) return [];
103
- if (Array.isArray(value)) return value.map(String);
104
- return [String(value)];
105
- }
106
74
  function attachPagesRequestCookies(req) {
107
75
  if (Object.hasOwn(req, "cookies")) return;
108
76
  Object.defineProperty(req, "cookies", {
@@ -128,6 +96,27 @@ function attachPagesRequestCookies(req) {
128
96
  }
129
97
  });
130
98
  }
99
+ function attachPagesPreviewApi(req, res) {
100
+ const preview = getPagesPreviewState(req.headers.cookie);
101
+ req.previewData = preview.data;
102
+ if (preview.data !== false) {
103
+ req.preview = true;
104
+ req.draftMode = true;
105
+ }
106
+ res.setPreviewData = (data, options = {}) => {
107
+ setPagesPreviewData(res, data, options);
108
+ return res;
109
+ };
110
+ res.clearPreviewData = (options = {}) => {
111
+ clearPagesPreviewData(res, options);
112
+ return res;
113
+ };
114
+ res.setDraftMode = (options = { enable: true }) => {
115
+ setPagesDraftMode(res, options.enable !== false);
116
+ return res;
117
+ };
118
+ if (preview.shouldClear) clearPagesPreviewData(res);
119
+ }
131
120
  var PagesResponseStream = class extends Writable {
132
121
  resolveResponse;
133
122
  rejectResponse;
@@ -197,9 +186,15 @@ var PagesResponseStream = class extends Writable {
197
186
  this.end(String(data));
198
187
  }
199
188
  redirect(statusOrUrl, url) {
200
- if (typeof statusOrUrl === "string") this.writeHead(307, { Location: statusOrUrl });
201
- else this.writeHead(statusOrUrl, { Location: url ?? "" });
189
+ if (typeof statusOrUrl === "string") {
190
+ url = statusOrUrl;
191
+ statusOrUrl = 307;
192
+ }
193
+ if (typeof statusOrUrl !== "number" || typeof url !== "string") throw new Error("Invalid redirect arguments. Please use a single argument URL, e.g. res.redirect('/destination') or use a status code and URL, e.g. res.redirect(307, '/destination').");
194
+ this.writeHead(statusOrUrl, { Location: url });
195
+ this.write(url);
202
196
  this.end();
197
+ return this;
203
198
  }
204
199
  getHeaders() {
205
200
  const headers = { ...this.resHeaders };
@@ -210,13 +205,15 @@ var PagesResponseStream = class extends Writable {
210
205
  await performOnDemandRevalidate(this.requestHeaders, urlPath, opts);
211
206
  }
212
207
  setPreviewData(data, options = {}) {
213
- const payload = Buffer.from(JSON.stringify(data)).toString("base64url");
214
- if (payload.length > 2048) throw new Error("Preview data is limited to 2KB currently, reduce how much data you are storing as preview data to continue");
215
- this.setHeader("Set-Cookie", [
216
- ...normalizeSetCookieHeader(this.getHeader("Set-Cookie")),
217
- serializePreviewCookie("__prerender_bypass", getRevalidateSecret(), options),
218
- serializePreviewCookie("__next_preview_data", payload, options)
219
- ]);
208
+ setPagesPreviewData(this, data, options);
209
+ return this;
210
+ }
211
+ clearPreviewData(options = {}) {
212
+ clearPagesPreviewData(this, options);
213
+ return this;
214
+ }
215
+ setDraftMode(options = { enable: true }) {
216
+ setPagesDraftMode(this, options.enable !== false);
220
217
  return this;
221
218
  }
222
219
  _write(chunk, encoding, callback) {
@@ -302,11 +299,13 @@ function createPagesReqRes(options) {
302
299
  resolveResponse = resolve;
303
300
  rejectResponse = reject;
304
301
  });
302
+ const res = new PagesResponseStream(resolveResponse, rejectResponse, options.request.headers);
303
+ attachPagesPreviewApi(req, res);
305
304
  return {
306
305
  req,
307
- res: new PagesResponseStream(resolveResponse, rejectResponse, options.request.headers),
306
+ res,
308
307
  responsePromise
309
308
  };
310
309
  }
311
310
  //#endregion
312
- export { PagesBodyParseError as PagesApiBodyParseError, attachPagesRequestCookies, createPagesReqRes, getPagesPreviewData, getPagesPreviewDataFromCookieHeader, parsePagesApiBody };
311
+ export { PagesBodyParseError as PagesApiBodyParseError, attachPagesPreviewApi, attachPagesRequestCookies, createPagesReqRes, getPagesPreviewData, parsePagesApiBody };
@@ -2,7 +2,7 @@ import { Route } from "../routing/pages-router.js";
2
2
  import { VinextNextData } from "../client/vinext-next-data.js";
3
3
  import { CachedPagesValue } from "../shims/cache-handler.js";
4
4
  import { ISRCacheEntry } from "./isr-cache.js";
5
- import { PagesPreviewData } from "./pages-node-compat.js";
5
+ import { PagesPreviewData } from "./pages-preview.js";
6
6
  import { PagesGsspResponse, PagesI18nRenderContext, PagesNextDataExtras } from "./pages-page-response.js";
7
7
  import { ReactNode } from "react";
8
8
 
@@ -179,7 +179,7 @@ function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSec
179
179
  cacheControlMeta: cacheControl
180
180
  });
181
181
  const headers = new Headers({
182
- "Content-Type": "text/html",
182
+ "Content-Type": "text/html; charset=utf-8",
183
183
  ...buildCacheStateHeaders(cacheState)
184
184
  });
185
185
  applyCdnResponseHeaders(headers, { cacheControl: cacheControlHeader });
@@ -248,6 +248,7 @@ async function resolvePagesPageData(options) {
248
248
  const userFacingParams = options.route.isDynamic ? options.params : null;
249
249
  let isFallback = false;
250
250
  let shouldPersistFallbackData = false;
251
+ const previewData = options.isOnDemandRevalidate ? false : options.previewData ?? false;
251
252
  if (typeof options.pageModule.getStaticPaths === "function" && options.route.isDynamic) {
252
253
  const pathsResult = await options.pageModule.getStaticPaths({
253
254
  locales: options.i18n.locales ?? [],
@@ -257,14 +258,13 @@ async function resolvePagesPageData(options) {
257
258
  const paths = pathsResult?.paths ?? [];
258
259
  const routeParams = getPagesRouteParams(options.routePattern);
259
260
  const isValidPath = paths.some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, routeParams, options.routeUrl));
260
- if (fallback === false && !isValidPath) return buildPagesNotFoundResult(options);
261
+ if (fallback === false && !isValidPath && previewData === false) return buildPagesNotFoundResult(options);
261
262
  const isBotRequest = !!options.userAgent && isBotUserAgent(options.userAgent, options.htmlLimitedBots);
262
- if (fallback === true && !isValidPath && !options.isDataReq && !isBotRequest) isFallback = true;
263
+ if (fallback === true && !isValidPath && !options.isDataReq && !isBotRequest && previewData === false) isFallback = true;
263
264
  shouldPersistFallbackData = fallback === true && !isValidPath && options.isDataReq === true;
264
265
  }
265
266
  let pageProps = {};
266
267
  let gsspRes = null;
267
- const previewData = options.isOnDemandRevalidate ? false : options.previewData ?? false;
268
268
  const previewContext = previewData === false ? {} : {
269
269
  draftMode: true,
270
270
  preview: true,
@@ -276,6 +276,7 @@ async function resolvePagesPageData(options) {
276
276
  return sharedReqRes;
277
277
  }
278
278
  let renderProps = { pageProps };
279
+ if (previewData !== false) renderProps.__N_PREVIEW = true;
279
280
  async function loadForegroundAppInitialRenderProps() {
280
281
  const result = await loadPagesAppInitialRenderProps(options, getSharedReqRes);
281
282
  if (result.kind === "response") return {
@@ -10,7 +10,7 @@ import { ensureFetchPatch } from "../shims/fetch-cache.js";
10
10
  import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
11
11
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
12
12
  import { getScriptNonceFromHeaderSources } from "./csp.js";
13
- import { resolvePagesI18nRequest } from "./pages-i18n.js";
13
+ import { extractLocaleFromUrl, resolvePagesI18nRequest } from "./pages-i18n.js";
14
14
  import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
15
15
  import { buildPagesReadinessNextData } from "./pages-readiness.js";
16
16
  import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
@@ -19,8 +19,20 @@ import { hasPagesGetInitialProps } from "./pages-get-initial-props.js";
19
19
  import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
20
20
  import { resolvePagesPageData } from "./pages-page-data.js";
21
21
  import { collectAssetTags, resolveClientModuleUrl } from "./pages-asset-tags.js";
22
- import { createPagesReqRes, getPagesPreviewData } from "./pages-node-compat.js";
22
+ import { PAGES_PREVIEW_CACHE_CONTROL, appendPagesPreviewClearCookies, getPagesPreviewState } from "./pages-preview.js";
23
+ import { createPagesReqRes } from "./pages-node-compat.js";
23
24
  //#region src/server/pages-page-handler.ts
25
+ function finalizePagesPreviewResponse(response, preview) {
26
+ if (preview.data === false && !preview.shouldClear) return response;
27
+ const headers = new Headers(response.headers);
28
+ if (preview.data !== false) headers.set("Cache-Control", PAGES_PREVIEW_CACHE_CONTROL);
29
+ if (preview.shouldClear) appendPagesPreviewClearCookies(headers);
30
+ return new Response(response.body, {
31
+ headers,
32
+ status: response.status,
33
+ statusText: response.statusText
34
+ });
35
+ }
24
36
  function shouldEmitPagesClientTraceMetadata(pageModule, appComponent) {
25
37
  if (typeof pageModule.getServerSideProps === "function") return true;
26
38
  if (typeof pageModule.getStaticProps === "function") return false;
@@ -126,6 +138,7 @@ function createPagesPageHandler(opts) {
126
138
  } else return buildDefaultPagesNotFoundResponse();
127
139
  }
128
140
  const { route, params } = match;
141
+ const routerAsPath = i18nConfig ? extractLocaleFromUrl(renderAsPath ?? routeUrl, i18nConfig, locale).url : renderAsPath ?? routeUrl;
129
142
  return runWithRequestContext(createRequestContext({ executionContext: getRequestExecutionContext() }), async () => {
130
143
  ensureFetchPatch();
131
144
  try {
@@ -134,17 +147,26 @@ function createPagesPageHandler(opts) {
134
147
  const query = mergeRouteParamsIntoQuery(parseQueryString(routeUrl), params);
135
148
  const pageModule = route.module;
136
149
  const isStaticPropsRoute = typeof pageModule.getStaticProps === "function";
137
- const pagesNextData = buildPagesReadinessNextData({
138
- pageModule,
139
- appComponent: AppComponent,
140
- hasRewrites
141
- });
142
- const navigationIsReady = typeof getPagesNavigationIsReadyFromSerializedState === "function" ? getPagesNavigationIsReadyFromSerializedState(routePattern, new URL(renderAsPath ?? routeUrl, "http://_").search, pagesNextData) : true;
150
+ const isOnDemandRevalidate = isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER));
151
+ const preview = isStaticPropsRoute || typeof pageModule.getServerSideProps === "function" ? getPagesPreviewState(request.headers.get("cookie"), { isOnDemandRevalidate }) : {
152
+ data: false,
153
+ shouldClear: false
154
+ };
155
+ const previewData = preview.data;
156
+ const pagesNextData = {
157
+ ...buildPagesReadinessNextData({
158
+ pageModule,
159
+ appComponent: AppComponent,
160
+ hasRewrites
161
+ }),
162
+ ...previewData === false ? {} : { isPreview: true }
163
+ };
164
+ const navigationIsReady = typeof getPagesNavigationIsReadyFromSerializedState === "function" ? getPagesNavigationIsReadyFromSerializedState(routePattern, new URL(routerAsPath, "http://_").search, pagesNextData) : true;
143
165
  function applySSRContext(extra) {
144
166
  if (typeof setSSRContext === "function") setSSRContext({
145
167
  pathname: routePattern,
146
168
  query,
147
- asPath: renderAsPath ?? routeUrl,
169
+ asPath: routerAsPath,
148
170
  navigationIsReady,
149
171
  locale,
150
172
  locales: i18nConfig ? i18nConfig.locales : void 0,
@@ -160,7 +182,10 @@ function createPagesPageHandler(opts) {
160
182
  hostname: new URL(request.url).hostname
161
183
  });
162
184
  }
163
- applySSRContext({ nextData: pagesNextData });
185
+ applySSRContext({
186
+ isPreview: previewData !== false,
187
+ nextData: pagesNextData
188
+ });
164
189
  const PageComponent = pageModule.default;
165
190
  if (!PageComponent) return new Response("Page has no default export", { status: 500 });
166
191
  if (!isDataReq && routePattern !== "/_error" && routePattern !== "/404" && routePattern !== "/500" && renderStatusCodeOverride === void 0) {
@@ -190,13 +215,16 @@ function createPagesPageHandler(opts) {
190
215
  if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + appendAssetDeploymentIdQuery(p.href) + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
191
216
  } catch {}
192
217
  const pagesResolvedUrl = (new URL(routeUrl, originalRequestUrl).pathname || "/") + originalRequestUrl.search;
193
- const createPageReqRes = () => createPagesReqRes({
194
- body: void 0,
195
- query,
196
- request,
197
- url: originalRequestPathAndSearch
198
- });
199
- const isOnDemandRevalidate = isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER));
218
+ const createPageReqRes = () => {
219
+ const reqRes = createPagesReqRes({
220
+ body: void 0,
221
+ query,
222
+ request,
223
+ url: originalRequestPathAndSearch
224
+ });
225
+ if (typeof renderStatusCode === "number") reqRes.res.statusCode = renderStatusCode;
226
+ return reqRes;
227
+ };
200
228
  const pageDataResult = await resolvePagesPageData({
201
229
  isDataReq,
202
230
  err: err instanceof Error ? err : void 0,
@@ -222,12 +250,12 @@ function createPagesPageHandler(opts) {
222
250
  isBuildTimePrerendering: typeof process !== "undefined" && process.env && process.env.VINEXT_PRERENDER === "1",
223
251
  validatePropsSerialization: process.env.NODE_ENV !== "production" || process.env.VINEXT_PRERENDER === "1",
224
252
  isOnDemandRevalidate,
225
- previewData: getPagesPreviewData(request, { isOnDemandRevalidate }),
253
+ previewData,
226
254
  pageModule,
227
255
  AppComponent,
228
256
  params,
229
257
  query,
230
- asPath: renderAsPath ?? routeUrl,
258
+ asPath: routerAsPath,
231
259
  resolvedUrl: pagesResolvedUrl,
232
260
  renderIsrPassToStringAsync,
233
261
  route: { isDynamic: route.isDynamic },
@@ -252,18 +280,22 @@ function createPagesPageHandler(opts) {
252
280
  });
253
281
  if (pageDataResult.kind === "notFound") {
254
282
  const notFoundRoute = findNotFoundRoute();
255
- if (notFoundRoute && routePattern !== "/404" && routePattern !== "/_error") return renderPage(request, url, manifest, middlewareHeaders, {
283
+ if (notFoundRoute && routePattern !== "/404" && routePattern !== "/_error") return finalizePagesPreviewResponse(await renderPage(request, url, manifest, middlewareHeaders, {
256
284
  statusCode: 404,
257
- asPath: renderAsPath ?? routeUrl,
285
+ asPath: routerAsPath,
258
286
  renderErrorPageOnMiss: false,
259
287
  __forcedRoute: notFoundRoute
260
- });
261
- return buildDefaultPagesNotFoundResponse();
288
+ }), preview);
289
+ return finalizePagesPreviewResponse(buildDefaultPagesNotFoundResponse(), preview);
262
290
  }
263
- if (pageDataResult.kind === "response") return pageDataResult.response;
291
+ if (pageDataResult.kind === "response") return finalizePagesPreviewResponse(pageDataResult.response, preview);
264
292
  let pageProps = pageDataResult.pageProps;
265
293
  let renderProps = pageDataResult.props;
266
- if (routePattern === "/_error" && typeof renderStatusCode === "number") {
294
+ if (previewData !== false) renderProps = {
295
+ ...renderProps,
296
+ __N_PREVIEW: true
297
+ };
298
+ if (routePattern === "/_error" && typeof renderStatusCode === "number" && renderProps.pageProps !== void 0) {
267
299
  pageProps = {
268
300
  ...pageProps,
269
301
  statusCode: renderStatusCode
@@ -280,7 +312,7 @@ function createPagesPageHandler(opts) {
280
312
  if (isFallbackRender && typeof setSSRContext === "function") setSSRContext({
281
313
  pathname: routePattern,
282
314
  query,
283
- asPath: renderAsPath ?? routeUrl,
315
+ asPath: routerAsPath,
284
316
  navigationIsReady: false,
285
317
  locale,
286
318
  locales: i18nConfig ? i18nConfig.locales : void 0,
@@ -316,12 +348,12 @@ function createPagesPageHandler(opts) {
316
348
  const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
317
349
  if (deploymentId) init.headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
318
350
  }
319
- return buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, init);
351
+ return finalizePagesPreviewResponse(buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, init), preview);
320
352
  }
321
353
  const pageModuleIds = [];
322
354
  if (appAssetPath) pageModuleIds.push(appAssetPath);
323
355
  if (route.filePath) pageModuleIds.push(route.filePath);
324
- return await renderPagesPageResponse({
356
+ return finalizePagesPreviewResponse(await renderPagesPageResponse({
325
357
  assetTags: collectAssetTags({
326
358
  manifest,
327
359
  moduleIds: pageModuleIds,
@@ -380,7 +412,7 @@ function createPagesPageHandler(opts) {
380
412
  userAgent: request.headers.get("user-agent") ?? void 0,
381
413
  ifNoneMatch: request.headers.get("if-none-match") ?? void 0,
382
414
  requestCacheControl: request.headers.get("cache-control") ?? void 0
383
- });
415
+ }), preview);
384
416
  } catch (e) {
385
417
  console.error("[vinext] SSR error:", e);
386
418
  reportRequestError(e instanceof Error ? e : new Error(String(e)), {
@@ -33,11 +33,11 @@ type PagesFontPreload = {
33
33
  /**
34
34
  * The `__NEXT_DATA__` fields beyond the always-present core that the Pages
35
35
  * renderer serializes: the `__vinext` block plus the readiness flags
36
- * (gssp/gsp/gip/appGip/autoExport/isExperimentalCompile) the client uses to
36
+ * (gssp/gsp/gip/appGip/autoExport/nextExport/isExperimentalCompile) the client uses to
37
37
  * recompute the initial `router.isReady`. Shared by every render path
38
38
  * (initial, ISR regeneration) so they emit identical readiness state.
39
39
  */
40
- type PagesNextDataExtras = Pick<VinextNextData, "__vinext" | "appGip" | "autoExport" | "gip" | "gsp" | "gssp" | "isExperimentalCompile">;
40
+ type PagesNextDataExtras = Pick<VinextNextData, "__vinext" | "appGip" | "autoExport" | "gip" | "gsp" | "gssp" | "isExperimentalCompile" | "nextExport">;
41
41
  type PagesI18nRenderContext = {
42
42
  locale?: string;
43
43
  locales?: string[];
@@ -167,7 +167,7 @@ function applyGsspHeaders(headers, gsspRes, statusCode) {
167
167
  }
168
168
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") headers.set(key, String(value));
169
169
  }
170
- headers.set("Content-Type", "text/html");
170
+ headers.set("Content-Type", "text/html; charset=utf-8");
171
171
  return statusCode ?? gsspRes.statusCode;
172
172
  }
173
173
  async function renderPagesPageResponse(options) {
@@ -232,7 +232,7 @@ async function renderPagesPageResponse(options) {
232
232
  const markerIndex = shellHtml.indexOf(bodyMarker);
233
233
  const shellPrefix = shellHtml.slice(0, markerIndex);
234
234
  const shellSuffix = shellHtml.slice(markerIndex + 25);
235
- const responseHeaders = new Headers({ "Content-Type": "text/html" });
235
+ const responseHeaders = new Headers({ "Content-Type": "text/html; charset=utf-8" });
236
236
  const finalStatus = applyGsspHeaders(responseHeaders, options.gsspRes ?? options.documentReqRes?.res ?? null, options.statusCode);
237
237
  let responseBodyStream = bodyStream;
238
238
  if (!options.scriptNonce && options.isrRevalidateSeconds !== null && options.isrRevalidateSeconds > 0) {
@@ -0,0 +1,26 @@
1
+ //#region src/server/pages-preview.d.ts
2
+ declare const PAGES_PREVIEW_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
3
+ type PagesPreviewData = object | string;
4
+ type PagesPreviewState = {
5
+ data: PagesPreviewData | false;
6
+ shouldClear: boolean;
7
+ };
8
+ type PreviewResponse = {
9
+ getHeader(name: string): string | number | boolean | string[] | undefined;
10
+ setHeader(name: string, value: string | number | boolean | string[]): unknown;
11
+ };
12
+ declare function getPagesPreviewModeId(): string;
13
+ declare function getPagesPreviewState(cookieHeader: string | string[] | null | undefined, options?: {
14
+ isOnDemandRevalidate?: boolean;
15
+ }): PagesPreviewState;
16
+ declare function setPagesDraftMode(response: PreviewResponse, enabled: boolean): void;
17
+ declare function setPagesPreviewData(response: PreviewResponse, data: PagesPreviewData, options?: {
18
+ maxAge?: number;
19
+ path?: string;
20
+ }): void;
21
+ declare function clearPagesPreviewData(response: PreviewResponse, options?: {
22
+ path?: string;
23
+ }): void;
24
+ declare function appendPagesPreviewClearCookies(headers: Headers): void;
25
+ //#endregion
26
+ export { PAGES_PREVIEW_CACHE_CONTROL, PagesPreviewData, PagesPreviewState, appendPagesPreviewClearCookies, clearPagesPreviewData, getPagesPreviewModeId, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData };
@@ -0,0 +1,165 @@
1
+ import { parseCookieHeader } from "../utils/parse-cookie.js";
2
+ import { createCipheriv, createDecipheriv, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
3
+ //#region src/server/pages-preview.ts
4
+ const PAGES_PREVIEW_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
5
+ const pagesPreviewCookiesCleared = Symbol("__prerender_bypass");
6
+ let devCredentials;
7
+ function decodeKey(value) {
8
+ if (!value || !/^[0-9a-f]{64}$/i.test(value)) return null;
9
+ return Buffer.from(value, "hex");
10
+ }
11
+ function getPagesPreviewCredentials() {
12
+ const bypassId = process.env.__VINEXT_PREVIEW_MODE_ID;
13
+ const encryptionKey = decodeKey(process.env.__VINEXT_PREVIEW_MODE_ENCRYPTION_KEY);
14
+ const signingKey = decodeKey(process.env.__VINEXT_PREVIEW_MODE_SIGNING_KEY);
15
+ if (bypassId && encryptionKey && signingKey) return {
16
+ bypassId,
17
+ encryptionKey,
18
+ signingKey
19
+ };
20
+ if (!devCredentials) devCredentials = {
21
+ bypassId: randomBytes(16).toString("hex"),
22
+ encryptionKey: randomBytes(32),
23
+ signingKey: randomBytes(32)
24
+ };
25
+ return devCredentials;
26
+ }
27
+ function getPagesPreviewModeId() {
28
+ return getPagesPreviewCredentials().bypassId;
29
+ }
30
+ function serializeCookie(name, value, options = {}) {
31
+ const parts = [
32
+ `${name}=${encodeURIComponent(value)}`,
33
+ "HttpOnly",
34
+ `Path=${options.path ?? "/"}`,
35
+ process.env.NODE_ENV !== "development" ? "SameSite=None" : "SameSite=Lax"
36
+ ];
37
+ if (process.env.NODE_ENV !== "development") parts.push("Secure");
38
+ if (options.maxAge !== void 0) parts.push(`Max-Age=${Math.trunc(options.maxAge)}`);
39
+ return parts.join("; ");
40
+ }
41
+ function serializeClearedCookie(name, options = {}) {
42
+ return [
43
+ `${name}=`,
44
+ "Expires=Thu, 01 Jan 1970 00:00:00 GMT",
45
+ "HttpOnly",
46
+ `Path=${options.path ?? "/"}`,
47
+ process.env.NODE_ENV !== "development" ? "SameSite=None" : "SameSite=Lax",
48
+ ...process.env.NODE_ENV !== "development" ? ["Secure"] : []
49
+ ].join("; ");
50
+ }
51
+ function normalizeSetCookie(value) {
52
+ if (value === void 0) return [];
53
+ return Array.isArray(value) ? value.map(String) : [String(value)];
54
+ }
55
+ function encodePayload(data, maxAge) {
56
+ const iv = randomBytes(12);
57
+ const credentials = getPagesPreviewCredentials();
58
+ const cipher = createCipheriv("aes-256-gcm", credentials.encryptionKey, iv);
59
+ const plaintext = JSON.stringify({
60
+ data,
61
+ ...maxAge === void 0 ? {} : { expiresAt: Date.now() + maxAge * 1e3 }
62
+ });
63
+ const encryptedToken = [
64
+ iv,
65
+ Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]),
66
+ cipher.getAuthTag()
67
+ ].map((part) => part.toString("base64url")).join(".");
68
+ return `${encryptedToken}.${createHmac("sha256", credentials.signingKey).update(encryptedToken).digest("base64url")}`;
69
+ }
70
+ function decodePayload(payload) {
71
+ try {
72
+ const [ivValue, encryptedValue, tagValue, signatureValue, ...extra] = payload.split(".");
73
+ if (!ivValue || !encryptedValue || !tagValue || !signatureValue || extra.length > 0) return false;
74
+ const encryptedToken = `${ivValue}.${encryptedValue}.${tagValue}`;
75
+ const credentials = getPagesPreviewCredentials();
76
+ const expected = createHmac("sha256", credentials.signingKey).update(encryptedToken).digest();
77
+ const signature = Buffer.from(signatureValue, "base64url");
78
+ if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) return false;
79
+ const decipher = createDecipheriv("aes-256-gcm", credentials.encryptionKey, Buffer.from(ivValue, "base64url"));
80
+ decipher.setAuthTag(Buffer.from(tagValue, "base64url"));
81
+ const decoded = Buffer.concat([decipher.update(Buffer.from(encryptedValue, "base64url")), decipher.final()]).toString("utf8");
82
+ const value = JSON.parse(decoded);
83
+ if (typeof value !== "object" || value === null || !("data" in value)) return false;
84
+ const expiresAt = "expiresAt" in value ? value.expiresAt : void 0;
85
+ if (typeof expiresAt === "number" && Date.now() >= expiresAt) return false;
86
+ const data = value.data;
87
+ return typeof data === "object" && data !== null ? data : String(data);
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+ function getPagesPreviewState(cookieHeader, options = {}) {
93
+ if (options.isOnDemandRevalidate) return {
94
+ data: false,
95
+ shouldClear: false
96
+ };
97
+ const cookies = parseCookieHeader(Array.isArray(cookieHeader) ? cookieHeader.join("; ") : cookieHeader);
98
+ const bypass = cookies.__prerender_bypass;
99
+ const payload = cookies.__next_preview_data;
100
+ if (!bypass && !payload) return {
101
+ data: false,
102
+ shouldClear: false
103
+ };
104
+ if (!bypass || bypass !== getPagesPreviewCredentials().bypassId) return {
105
+ data: false,
106
+ shouldClear: true
107
+ };
108
+ if (!payload) return {
109
+ data: {},
110
+ shouldClear: false
111
+ };
112
+ const data = decodePayload(payload);
113
+ return {
114
+ data,
115
+ shouldClear: data === false
116
+ };
117
+ }
118
+ function setPagesDraftMode(response, enabled) {
119
+ const cookie = enabled ? serializeCookie("__prerender_bypass", getPagesPreviewModeId()) : serializeClearedCookie("__prerender_bypass");
120
+ response.setHeader("Set-Cookie", [...normalizeSetCookie(response.getHeader("Set-Cookie")), cookie]);
121
+ }
122
+ function setPagesPreviewData(response, data, options = {}) {
123
+ const payload = encodePayload(data, options.maxAge);
124
+ if (payload.length > 2048) throw new Error("Preview data is limited to 2KB currently, reduce how much data you are storing as preview data to continue");
125
+ response.setHeader("Set-Cookie", [
126
+ ...normalizeSetCookie(response.getHeader("Set-Cookie")),
127
+ serializeCookie("__prerender_bypass", getPagesPreviewModeId(), options),
128
+ serializeCookie("__next_preview_data", payload, options)
129
+ ]);
130
+ }
131
+ function clearPagesPreviewData(response, options = {}) {
132
+ if (pagesPreviewCookiesCleared in response) return;
133
+ response.setHeader("Set-Cookie", [
134
+ ...normalizeSetCookie(response.getHeader("Set-Cookie")),
135
+ serializeClearedCookie("__prerender_bypass", options),
136
+ serializeClearedCookie("__next_preview_data", options)
137
+ ]);
138
+ Object.defineProperty(response, pagesPreviewCookiesCleared, {
139
+ value: true,
140
+ enumerable: false
141
+ });
142
+ }
143
+ function appendPagesPreviewClearCookies(headers) {
144
+ const cookies = headers.getSetCookie();
145
+ const hasExpiredCookie = (name) => cookies.some((cookie) => {
146
+ const [cookieValue, ...attributes] = cookie.split(";").map((part) => part.trim());
147
+ if (!cookieValue?.startsWith(`${name}=`)) return false;
148
+ let expiresAtEpoch = false;
149
+ let path;
150
+ let hasDomain = false;
151
+ for (const attribute of attributes) {
152
+ const separator = attribute.indexOf("=");
153
+ const attributeName = (separator === -1 ? attribute : attribute.slice(0, separator)).trim().toLowerCase();
154
+ const attributeValue = separator === -1 ? "" : attribute.slice(separator + 1).trim();
155
+ if (attributeName === "expires") expiresAtEpoch = Date.parse(attributeValue) === 0;
156
+ if (attributeName === "path") path = attributeValue;
157
+ if (attributeName === "domain") hasDomain = true;
158
+ }
159
+ return expiresAtEpoch && path === "/" && !hasDomain;
160
+ });
161
+ if (!hasExpiredCookie("__prerender_bypass")) headers.append("Set-Cookie", serializeClearedCookie("__prerender_bypass"));
162
+ if (!hasExpiredCookie("__next_preview_data")) headers.append("Set-Cookie", serializeClearedCookie("__next_preview_data"));
163
+ }
164
+ //#endregion
165
+ export { PAGES_PREVIEW_CACHE_CONTROL, appendPagesPreviewClearCookies, clearPagesPreviewData, getPagesPreviewModeId, getPagesPreviewState, setPagesDraftMode, setPagesPreviewData };