vinext 1.0.0-beta.1 → 1.0.0-beta.3

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 (234) hide show
  1. package/README.md +10 -10
  2. package/dist/build/client-build-config.js +8 -1
  3. package/dist/build/report.d.ts +8 -1
  4. package/dist/build/report.js +12 -2
  5. package/dist/check.js +19 -2
  6. package/dist/cli.js +3 -2
  7. package/dist/config/config-matchers.d.ts +13 -37
  8. package/dist/config/config-matchers.js +35 -122
  9. package/dist/config/next-config.d.ts +15 -5
  10. package/dist/config/next-config.js +7 -1
  11. package/dist/config/request-context.d.ts +14 -0
  12. package/dist/config/request-context.js +26 -0
  13. package/dist/entries/app-browser-entry.d.ts +4 -10
  14. package/dist/entries/app-browser-entry.js +20 -4
  15. package/dist/entries/app-rsc-entry.js +30 -9
  16. package/dist/entries/app-rsc-manifest.js +36 -0
  17. package/dist/entries/pages-client-entry.js +0 -1
  18. package/dist/entries/pages-server-entry.js +13 -5
  19. package/dist/index.js +194 -101
  20. package/dist/init-cloudflare.d.ts +3 -1
  21. package/dist/init-cloudflare.js +59 -5
  22. package/dist/init.d.ts +6 -4
  23. package/dist/init.js +20 -22
  24. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  25. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  26. package/dist/plugins/import-meta-url.js +17 -6
  27. package/dist/plugins/og-assets.js +1 -1
  28. package/dist/plugins/require-context.js +20 -15
  29. package/dist/plugins/transform-cache.d.ts +19 -0
  30. package/dist/plugins/transform-cache.js +36 -0
  31. package/dist/routing/app-route-graph.d.ts +27 -11
  32. package/dist/routing/app-route-graph.js +158 -22
  33. package/dist/routing/app-router.js +12 -6
  34. package/dist/routing/file-matcher.d.ts +11 -22
  35. package/dist/routing/file-matcher.js +21 -33
  36. package/dist/routing/pages-router.js +23 -29
  37. package/dist/routing/route-matching.d.ts +14 -1
  38. package/dist/routing/route-matching.js +13 -1
  39. package/dist/routing/route-pattern.d.ts +2 -1
  40. package/dist/routing/route-pattern.js +7 -4
  41. package/dist/routing/route-trie.d.ts +5 -1
  42. package/dist/routing/route-trie.js +5 -2
  43. package/dist/server/api-handler.d.ts +2 -0
  44. package/dist/server/api-handler.js +3 -3
  45. package/dist/server/app-browser-entry.js +110 -37
  46. package/dist/server/app-browser-history-controller.d.ts +1 -1
  47. package/dist/server/app-browser-history-controller.js +3 -3
  48. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  49. package/dist/server/app-browser-navigation-controller.js +2 -2
  50. package/dist/server/app-browser-state.js +1 -1
  51. package/dist/server/app-browser-visible-commit.js +1 -1
  52. package/dist/server/app-fallback-renderer.d.ts +3 -0
  53. package/dist/server/app-fallback-renderer.js +4 -2
  54. package/dist/server/app-middleware.js +2 -1
  55. package/dist/server/app-page-boundary-render.d.ts +12 -1
  56. package/dist/server/app-page-boundary-render.js +84 -2
  57. package/dist/server/app-page-cache-finalizer.d.ts +1 -1
  58. package/dist/server/app-page-cache-finalizer.js +1 -1
  59. package/dist/server/app-page-cache.d.ts +2 -2
  60. package/dist/server/app-page-cache.js +16 -2
  61. package/dist/server/app-page-dispatch.d.ts +19 -2
  62. package/dist/server/app-page-dispatch.js +45 -23
  63. package/dist/server/app-page-element-builder.d.ts +9 -2
  64. package/dist/server/app-page-element-builder.js +144 -33
  65. package/dist/server/app-page-head.d.ts +56 -4
  66. package/dist/server/app-page-head.js +216 -85
  67. package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
  68. package/dist/server/app-page-http-access-fallback-metadata.js +114 -0
  69. package/dist/server/app-page-probe.d.ts +4 -0
  70. package/dist/server/app-page-probe.js +6 -2
  71. package/dist/server/app-page-render.d.ts +2 -2
  72. package/dist/server/app-page-render.js +1 -1
  73. package/dist/server/app-page-request.d.ts +15 -0
  74. package/dist/server/app-page-request.js +134 -14
  75. package/dist/server/app-page-response.js +1 -1
  76. package/dist/server/app-page-route-wiring.d.ts +16 -0
  77. package/dist/server/app-page-route-wiring.js +254 -52
  78. package/dist/server/app-pages-bridge.d.ts +1 -1
  79. package/dist/server/app-pages-bridge.js +2 -1
  80. package/dist/server/app-post-middleware-context.d.ts +1 -1
  81. package/dist/server/app-post-middleware-context.js +1 -1
  82. package/dist/server/app-route-handler-cache.js +4 -0
  83. package/dist/server/app-route-handler-dispatch.js +40 -20
  84. package/dist/server/app-route-handler-execution.d.ts +6 -1
  85. package/dist/server/app-route-handler-execution.js +42 -16
  86. package/dist/server/app-route-handler-policy.d.ts +2 -0
  87. package/dist/server/app-route-handler-policy.js +3 -3
  88. package/dist/server/app-route-handler-response.js +1 -1
  89. package/dist/server/app-route-module-loader.d.ts +9 -1
  90. package/dist/server/app-route-module-loader.js +4 -0
  91. package/dist/server/app-router-entry.js +6 -3
  92. package/dist/server/app-rsc-cache-busting.d.ts +1 -1
  93. package/dist/server/app-rsc-errors.d.ts +1 -1
  94. package/dist/server/app-rsc-errors.js +22 -2
  95. package/dist/server/app-rsc-handler.d.ts +10 -5
  96. package/dist/server/app-rsc-handler.js +73 -33
  97. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  98. package/dist/server/app-rsc-request-normalization.js +8 -2
  99. package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
  100. package/dist/server/app-rsc-response-finalizer.js +5 -11
  101. package/dist/server/app-rsc-route-matching.d.ts +29 -0
  102. package/dist/server/app-rsc-route-matching.js +93 -11
  103. package/dist/server/app-segment-config.js +13 -3
  104. package/dist/server/app-server-action-execution.d.ts +3 -1
  105. package/dist/server/app-server-action-execution.js +9 -7
  106. package/dist/server/app-ssr-entry.js +6 -6
  107. package/dist/server/app-ssr-stream.d.ts +1 -7
  108. package/dist/server/app-ssr-stream.js +2 -10
  109. package/dist/server/cache-control.d.ts +2 -2
  110. package/dist/server/cache-control.js +2 -1
  111. package/dist/server/config-headers.d.ts +24 -0
  112. package/dist/server/config-headers.js +52 -0
  113. package/dist/server/dev-initial-server-error.d.ts +1 -1
  114. package/dist/server/dev-server.d.ts +3 -1
  115. package/dist/server/dev-server.js +170 -321
  116. package/dist/server/headers.d.ts +2 -2
  117. package/dist/server/headers.js +4 -3
  118. package/dist/server/isr-cache.d.ts +11 -34
  119. package/dist/server/isr-cache.js +33 -43
  120. package/dist/server/isr-decision.d.ts +2 -2
  121. package/dist/server/middleware-matcher-pattern.d.ts +22 -0
  122. package/dist/server/middleware-matcher-pattern.js +219 -0
  123. package/dist/server/middleware-matcher.d.ts +2 -7
  124. package/dist/server/middleware-matcher.js +13 -60
  125. package/dist/server/middleware-path-to-regexp.d.ts +14 -0
  126. package/dist/server/middleware-path-to-regexp.js +228 -0
  127. package/dist/server/middleware-runtime.js +4 -3
  128. package/dist/server/middleware.d.ts +1 -1
  129. package/dist/server/middleware.js +2 -1
  130. package/dist/server/pages-api-route.d.ts +2 -0
  131. package/dist/server/pages-api-route.js +4 -1
  132. package/dist/server/pages-data-route.d.ts +11 -1
  133. package/dist/server/pages-data-route.js +16 -1
  134. package/dist/server/pages-dev-hydration.js +0 -1
  135. package/dist/server/pages-get-initial-props.d.ts +16 -3
  136. package/dist/server/pages-get-initial-props.js +17 -10
  137. package/dist/server/pages-i18n.js +64 -16
  138. package/dist/server/pages-node-compat.d.ts +2 -0
  139. package/dist/server/pages-node-compat.js +7 -3
  140. package/dist/server/pages-page-data.d.ts +64 -10
  141. package/dist/server/pages-page-data.js +349 -80
  142. package/dist/server/pages-page-handler.d.ts +9 -3
  143. package/dist/server/pages-page-handler.js +131 -36
  144. package/dist/server/pages-page-response.d.ts +5 -3
  145. package/dist/server/pages-page-response.js +24 -27
  146. package/dist/server/pages-readiness.d.ts +3 -3
  147. package/dist/server/pages-request-pipeline.d.ts +8 -0
  148. package/dist/server/pages-request-pipeline.js +30 -12
  149. package/dist/server/pages-revalidate.d.ts +1 -1
  150. package/dist/server/pages-revalidate.js +54 -8
  151. package/dist/server/pages-router-entry.d.ts +1 -0
  152. package/dist/server/pages-router-entry.js +16 -4
  153. package/dist/server/prerender-route-params.js +2 -2
  154. package/dist/server/prod-server.d.ts +3 -5
  155. package/dist/server/prod-server.js +72 -35
  156. package/dist/server/request-pipeline.d.ts +15 -29
  157. package/dist/server/request-pipeline.js +24 -59
  158. package/dist/server/revalidation-host.d.ts +11 -0
  159. package/dist/server/revalidation-host.js +19 -0
  160. package/dist/server/rsc-stream-hints.js +122 -18
  161. package/dist/server/worker-revalidation-context.d.ts +13 -0
  162. package/dist/server/worker-revalidation-context.js +29 -0
  163. package/dist/shims/app.d.ts +1 -1
  164. package/dist/shims/cache-handler.d.ts +1 -1
  165. package/dist/shims/cache-handler.js +10 -7
  166. package/dist/shims/cache-request-state.d.ts +27 -1
  167. package/dist/shims/cache-request-state.js +60 -1
  168. package/dist/shims/cache-runtime.d.ts +18 -1
  169. package/dist/shims/cache-runtime.js +26 -8
  170. package/dist/shims/cache.d.ts +5 -5
  171. package/dist/shims/cache.js +27 -11
  172. package/dist/shims/document.d.ts +42 -83
  173. package/dist/shims/document.js +62 -53
  174. package/dist/shims/dynamic.d.ts +5 -25
  175. package/dist/shims/dynamic.js +29 -8
  176. package/dist/shims/error.d.ts +1 -1
  177. package/dist/shims/error.js +2 -2
  178. package/dist/shims/fetch-cache.js +13 -4
  179. package/dist/shims/font-google-base.d.ts +11 -4
  180. package/dist/shims/font-google-base.js +17 -8
  181. package/dist/shims/font-local.d.ts +10 -3
  182. package/dist/shims/font-local.js +41 -10
  183. package/dist/shims/head.d.ts +13 -2
  184. package/dist/shims/head.js +3 -3
  185. package/dist/shims/headers.d.ts +37 -43
  186. package/dist/shims/headers.js +183 -74
  187. package/dist/shims/image.d.ts +27 -37
  188. package/dist/shims/image.js +21 -14
  189. package/dist/shims/internal/cookie-serialize.d.ts +12 -9
  190. package/dist/shims/internal/cookie-serialize.js +10 -7
  191. package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
  192. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  193. package/dist/shims/internal/interpolate-as.js +27 -2
  194. package/dist/shims/internal/utils.d.ts +3 -3
  195. package/dist/shims/legacy-image.d.ts +3 -37
  196. package/dist/shims/legacy-image.js +6 -16
  197. package/dist/shims/link.d.ts +15 -22
  198. package/dist/shims/link.js +34 -13
  199. package/dist/shims/metadata.d.ts +7 -17
  200. package/dist/shims/metadata.js +74 -24
  201. package/dist/shims/navigation-context-state.d.ts +1 -1
  202. package/dist/shims/navigation.d.ts +7 -3
  203. package/dist/shims/navigation.js +25 -14
  204. package/dist/shims/navigation.react-server.js +1 -1
  205. package/dist/shims/next-shims-augmentations.d.ts +1 -0
  206. package/dist/shims/next-shims-public.d.ts +1 -0
  207. package/dist/shims/public-shim-map.json.js +103 -0
  208. package/dist/shims/readonly-url-search-params.d.ts +3 -3
  209. package/dist/shims/readonly-url-search-params.js +3 -3
  210. package/dist/shims/request-context.d.ts +4 -1
  211. package/dist/shims/request-state-types.d.ts +1 -1
  212. package/dist/shims/router.d.ts +55 -21
  213. package/dist/shims/router.js +180 -44
  214. package/dist/shims/script.d.ts +6 -10
  215. package/dist/shims/script.js +7 -4
  216. package/dist/shims/server.d.ts +50 -26
  217. package/dist/shims/server.js +193 -55
  218. package/dist/shims/unified-request-context.d.ts +22 -3
  219. package/dist/shims/unified-request-context.js +84 -1
  220. package/dist/shims/url-safety.d.ts +1 -1
  221. package/dist/shims/url-safety.js +2 -2
  222. package/dist/typegen.d.ts +8 -2
  223. package/dist/typegen.js +76 -15
  224. package/dist/utils/cache-control-metadata.d.ts +2 -1
  225. package/dist/utils/cache-control-metadata.js +5 -1
  226. package/dist/utils/domain-locale.d.ts +2 -2
  227. package/dist/utils/external-url.d.ts +5 -0
  228. package/dist/utils/external-url.js +7 -0
  229. package/dist/utils/html-limited-bots.js +1 -1
  230. package/dist/utils/protocol-headers.d.ts +7 -1
  231. package/dist/utils/protocol-headers.js +7 -1
  232. package/dist/utils/regex-safety.d.ts +8 -0
  233. package/dist/utils/regex-safety.js +737 -0
  234. package/package.json +13 -2
@@ -1,35 +1,157 @@
1
- import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
2
- import { buildCacheStateHeaders } from "./cache-headers.js";
1
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
2
+ import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
3
+ import { isDangerousScheme } from "../shims/url-safety.js";
3
4
  import { isUnknownRecord } from "../utils/record.js";
4
5
  import { applyCdnResponseHeaders } from "./cache-control.js";
5
- import { decideIsr } from "./isr-decision.js";
6
+ import { buildMissIsrCacheControl, decideIsr } from "./isr-decision.js";
6
7
  import { buildPagesCacheValue } from "./isr-cache.js";
8
+ import { encodeCacheTag } from "../utils/encode-cache-tag.js";
7
9
  import { normalizeStaticPathname } from "../routing/route-pattern.js";
10
+ import { buildCacheStateHeaders } from "./cache-headers.js";
11
+ import { isBotUserAgent } from "../utils/html-limited-bots.js";
8
12
  import { buildPagesNextDataScript, etagMatches, generatePagesETag, isPagesStreamingBot, requestsNoCache } from "./pages-page-response.js";
9
- import { hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
13
+ import { createPagesGetInitialPropsRouter, hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
10
14
  import { buildNextDataPropsJsonResponse } from "./pages-data-route.js";
11
15
  import { isSerializableProps } from "./pages-serializable-props.js";
12
- import { isBotUserAgent } from "../utils/html-limited-bots.js";
13
16
  //#region src/server/pages-page-data.ts
17
+ const ALLOWED_PAGES_REDIRECT_STATUS_CODES = /* @__PURE__ */ new Set([
18
+ 301,
19
+ 302,
20
+ 303,
21
+ 307,
22
+ 308
23
+ ]);
24
+ /** Headers that are part of a cached Pages representation, never request state. */
25
+ function isCachedPagesRepresentationHeader(name) {
26
+ const lowerName = name.toLowerCase();
27
+ return lowerName === "location" || lowerName === "content-type";
28
+ }
29
+ function assertPages404DoesNotReturnNotFound(routePattern, result) {
30
+ if (routePattern === "/404" && result?.notFound) throw new Error("The /404 page can not return notFound in \"getStaticProps\", please remove it to continue!");
31
+ }
32
+ /**
33
+ * Next.js preserves an omitted/false Pages `revalidate` result as an indefinite
34
+ * cache lifetime. The one-year sentinel is only an HTTP Cache-Control detail;
35
+ * storing it as a revalidation deadline would incorrectly regenerate static
36
+ * pages after one year.
37
+ *
38
+ * Next.js source:
39
+ * - packages/next/src/server/render.tsx (`metadata.cacheControl`)
40
+ * - packages/next/src/server/route-modules/pages/pages-handler.ts
41
+ */
42
+ function resolvePagesRevalidateSeconds(result, routeUrl = "") {
43
+ const revalidate = result.revalidate;
44
+ if (revalidate === true) return 1;
45
+ if (typeof revalidate === "number") {
46
+ if (!Number.isInteger(revalidate)) throw new Error(`A page's revalidate option must be seconds expressed as a natural number for ${routeUrl}. Mixed numbers, such as '${revalidate}', cannot be used.`);
47
+ if (revalidate <= 0) throw new Error(`A page's revalidate option can not be less than or equal to zero for ${routeUrl}.`);
48
+ return revalidate;
49
+ }
50
+ if (revalidate === false || revalidate === void 0) return false;
51
+ throw new Error(`A page's revalidate option must be seconds expressed as a natural number. Mixed numbers and strings cannot be used. Received '${JSON.stringify(revalidate)}' for ${routeUrl}`);
52
+ }
53
+ function resolvePagesExpireSeconds(result, configuredExpireSeconds) {
54
+ return result.revalidate === false || result.revalidate === void 0 ? void 0 : configuredExpireSeconds;
55
+ }
56
+ /**
57
+ * Merge gSP/gSSP data into the custom App's raw pageProps value.
58
+ *
59
+ * Next.js deliberately uses Object.assign rather than object spread, so
60
+ * enumerable keys from arrays and primitive wrapper objects are retained.
61
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/render.tsx
62
+ */
63
+ function mergePagesDataProps(appPageProps, dataProps) {
64
+ return Object.assign({}, appPageProps, dataProps);
65
+ }
14
66
  function buildPagesDataNotFoundResponse(deploymentId) {
15
67
  const headers = { "Content-Type": "application/json" };
16
68
  if (deploymentId) headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
17
- return new Response("{}", {
69
+ return new Response("{\"notFound\":true}", {
18
70
  status: 404,
19
71
  headers
20
72
  });
21
73
  }
22
- function buildPagesNotFoundResult(options) {
74
+ function buildPagesNotFoundResult(options, revalidateSeconds, cacheState, expireSeconds) {
23
75
  if (options.isDataReq) return {
24
76
  kind: "response",
25
77
  response: buildPagesDataNotFoundResponse(options.deploymentId)
26
78
  };
27
- return { kind: "notFound" };
79
+ return {
80
+ kind: "notFound",
81
+ revalidateSeconds,
82
+ expireSeconds,
83
+ cacheState
84
+ };
85
+ }
86
+ function applyPagesTerminalMissHeaders(response, revalidateSeconds, isrCachePathname, expireSeconds) {
87
+ const stem = isrCachePathname.endsWith("/") ? isrCachePathname.slice(0, -1) : isrCachePathname;
88
+ applyCdnResponseHeaders(response.headers, {
89
+ cacheControl: buildMissIsrCacheControl(revalidateSeconds, expireSeconds),
90
+ tags: [encodeCacheTag(`_N_T_${stem || "/"}`)]
91
+ });
92
+ for (const [name, value] of Object.entries(buildCacheStateHeaders("MISS"))) response.headers.set(name, value);
93
+ return response;
94
+ }
95
+ function applyCachedPagesRepresentationHeaders(response, cacheState, entry, options) {
96
+ const { cacheControl } = decideIsr({
97
+ cacheState,
98
+ kind: "pages",
99
+ revalidateSeconds: entry.cacheControl?.revalidate ?? 60,
100
+ expireSeconds: entry.cacheControl?.expire === void 0 ? void 0 : options.expireSeconds,
101
+ cacheControlMeta: entry.cacheControl
102
+ });
103
+ applyCdnResponseHeaders(response.headers, { cacheControl });
104
+ for (const [name, value] of Object.entries(buildCacheStateHeaders(cacheState))) response.headers.set(name, value);
105
+ return response;
106
+ }
107
+ function buildCachedPagesNotFoundResult(options, entry, cacheState) {
108
+ const result = buildPagesNotFoundResult(options, entry.cacheControl?.revalidate ?? 60, cacheState, entry.cacheControl?.expire);
109
+ if (result.kind === "response") return {
110
+ kind: "response",
111
+ response: applyCachedPagesRepresentationHeaders(result.response, cacheState, entry, options)
112
+ };
113
+ return result;
28
114
  }
29
115
  function resolvePagesRedirectStatus(redirect) {
30
116
  return redirect.statusCode != null ? redirect.statusCode : redirect.permanent ? 308 : 307;
31
117
  }
118
+ /** Validate and normalize the redirect metadata returned by gSP/gSSP. */
119
+ function resolvePagesRedirect(redirect, options) {
120
+ const errors = [];
121
+ const hasPermanent = redirect.permanent !== void 0;
122
+ const hasStatusCode = redirect.statusCode !== void 0;
123
+ if (hasPermanent && hasStatusCode) errors.push("`permanent` and `statusCode` can not both be provided");
124
+ else if (hasPermanent && typeof redirect.permanent !== "boolean") errors.push("`permanent` must be `true` or `false`");
125
+ else if (hasStatusCode && !ALLOWED_PAGES_REDIRECT_STATUS_CODES.has(redirect.statusCode)) errors.push(`\`statusCode\` must undefined or one of ${[...ALLOWED_PAGES_REDIRECT_STATUS_CODES].join(", ")}`);
126
+ if (typeof redirect.destination !== "string") errors.push(`\`destination\` should be string but received ${typeof redirect.destination}`);
127
+ if (redirect.basePath !== void 0 && typeof redirect.basePath !== "boolean") errors.push(`\`basePath\` should be undefined or a false, received ${typeof redirect.basePath}`);
128
+ if (errors.length > 0) throw new Error(`Invalid redirect object returned from ${options.method} for ${options.routeUrl}\n${errors.join(" and ")}\nSee more info here: https://nextjs.org/docs/messages/invalid-redirect-gssp`);
129
+ return {
130
+ destination: options.sanitizeDestination(redirect.destination),
131
+ statusCode: resolvePagesRedirectStatus(redirect),
132
+ ...redirect.basePath === void 0 ? {} : { basePath: redirect.basePath }
133
+ };
134
+ }
135
+ function resolvePagesRedirectLocation(redirect, configuredBasePath = "") {
136
+ let destination = redirect.destination;
137
+ if (configuredBasePath && redirect.basePath !== false && redirect.destination.startsWith("/")) destination = `${configuredBasePath}${redirect.destination}`;
138
+ if (!destination.startsWith("/")) return destination;
139
+ const urlParts = destination.split("?");
140
+ return urlParts[0].replace(/\\/g, "/").replace(/\/\/+/g, "/") + (urlParts[1] ? `?${urlParts.slice(1).join("?")}` : "");
141
+ }
142
+ function buildPagesRedirectProps(redirect, props) {
143
+ return {
144
+ ...props,
145
+ pageProps: {
146
+ ...isUnknownRecord(props.pageProps) ? props.pageProps : {},
147
+ __N_REDIRECT: redirect.destination,
148
+ __N_REDIRECT_STATUS: redirect.statusCode,
149
+ ...redirect.basePath === void 0 ? {} : { __N_REDIRECT_BASE_PATH: redirect.basePath }
150
+ }
151
+ };
152
+ }
32
153
  function normalizePagesRenderProps(props) {
154
+ if (!("pageProps" in props)) return { pageProps: props };
33
155
  return {
34
156
  ...props,
35
157
  pageProps: props.pageProps
@@ -57,11 +179,7 @@ async function loadPagesAppInitialRenderProps(options, getSharedReqRes) {
57
179
  const initialProps = await loadPagesGetInitialProps(options.AppComponent, {
58
180
  AppTree: options.createAppTree ?? options.createPageElement,
59
181
  Component: options.pageModule.default,
60
- router: {
61
- pathname: options.routePattern,
62
- query: options.query,
63
- asPath: options.asPath ?? options.routeUrl
64
- },
182
+ router: options.router ?? createPagesGetInitialPropsRouter(options.routePattern, options.query, options.asPath ?? options.routeUrl),
65
183
  ctx: {
66
184
  req,
67
185
  res,
@@ -79,8 +197,8 @@ async function loadPagesAppInitialRenderProps(options, getSharedReqRes) {
79
197
  response: responsePromise
80
198
  };
81
199
  if (initialProps) {
82
- renderProps = normalizePagesRenderProps(initialProps);
83
- pageProps = isUnknownRecord(renderProps.pageProps) ? renderProps.pageProps : {};
200
+ renderProps = initialProps;
201
+ pageProps = isUnknownRecord(initialProps.pageProps) ? initialProps.pageProps : {};
84
202
  }
85
203
  return {
86
204
  kind: "props",
@@ -109,25 +227,67 @@ async function loadPagesAppInitialRenderProps(options, getSharedReqRes) {
109
227
  * redirects (search `__N_REDIRECT`), consumed in
110
228
  * `packages/next/src/shared/lib/router/router.ts` (`pageProps.__N_REDIRECT`).
111
229
  */
112
- function buildPagesRedirectResponse(redirect, options, props = { pageProps: {} }) {
113
- const destination = options.sanitizeDestination(redirect.destination);
230
+ function buildPagesRedirectResponse(redirect, options, props = { pageProps: {} }, method = "getStaticProps") {
231
+ const resolved = resolvePagesRedirect(redirect, {
232
+ method,
233
+ routeUrl: options.routeUrl,
234
+ sanitizeDestination: options.sanitizeDestination
235
+ });
236
+ const redirectProps = buildPagesRedirectProps(resolved, props);
237
+ if (isDangerousScheme(resolved.destination)) {
238
+ const headers = new Headers({
239
+ "Cache-Control": "private, no-cache, no-store, max-age=0, must-revalidate",
240
+ "Content-Type": "text/plain; charset=utf-8"
241
+ });
242
+ if (options.deploymentId) headers.set(NEXTJS_DEPLOYMENT_ID_HEADER, options.deploymentId);
243
+ return new Response("Invalid redirect destination", {
244
+ status: 500,
245
+ headers
246
+ });
247
+ }
114
248
  if (options.isDataReq) {
115
249
  const init = { headers: {} };
116
250
  if (options.deploymentId) init.headers[NEXTJS_DEPLOYMENT_ID_HEADER] = options.deploymentId;
117
- return buildNextDataPropsJsonResponse({
118
- ...props,
119
- pageProps: {
120
- ...isUnknownRecord(props.pageProps) ? props.pageProps : {},
121
- __N_REDIRECT: destination,
122
- __N_REDIRECT_STATUS: resolvePagesRedirectStatus(redirect)
123
- }
124
- }, options.safeJsonStringify, init);
251
+ return buildNextDataPropsJsonResponse(redirectProps, options.safeJsonStringify, init);
125
252
  }
126
- return new Response(null, {
127
- status: resolvePagesRedirectStatus(redirect),
128
- headers: { Location: destination }
253
+ const location = resolvePagesRedirectLocation(resolved, options.basePath);
254
+ return new Response(location, {
255
+ status: resolved.statusCode,
256
+ headers: {
257
+ Location: location,
258
+ ...resolved.statusCode === 308 ? { Refresh: `0;url=${location}` } : {}
259
+ }
129
260
  });
130
261
  }
262
+ function buildCachedPagesRedirectResponse(cached, options) {
263
+ const props = normalizePagesRenderProps(cached.props);
264
+ const pageProps = isUnknownRecord(props.pageProps) ? props.pageProps : {};
265
+ const destination = pageProps.__N_REDIRECT;
266
+ const statusCode = pageProps.__N_REDIRECT_STATUS;
267
+ const redirectBasePath = pageProps.__N_REDIRECT_BASE_PATH;
268
+ if (typeof destination !== "string") throw new Error("Invalid cached Pages redirect: missing __N_REDIRECT");
269
+ return buildPagesRedirectResponse({
270
+ destination,
271
+ ...typeof statusCode === "number" ? { statusCode } : {},
272
+ ...redirectBasePath === void 0 ? {} : { basePath: redirectBasePath }
273
+ }, options, props);
274
+ }
275
+ function getCachedPagesRedirect(cached) {
276
+ if (cached?.kind === "REDIRECT") return cached;
277
+ if (cached?.kind !== "PAGES") return null;
278
+ const locationHeader = cached.headers ? Object.entries(cached.headers).find(([name]) => name.toLowerCase() === "location")?.[1] : void 0;
279
+ const destination = Array.isArray(locationHeader) ? locationHeader[0] : locationHeader;
280
+ if (typeof destination !== "string" || typeof cached.status !== "number" || !ALLOWED_PAGES_REDIRECT_STATUS_CODES.has(cached.status)) return null;
281
+ const props = normalizePagesRenderProps(cached.pageData);
282
+ return {
283
+ kind: "REDIRECT",
284
+ props: buildPagesRedirectProps({
285
+ destination,
286
+ statusCode: cached.status,
287
+ basePath: false
288
+ }, props)
289
+ };
290
+ }
131
291
  function getPagesRouteParams(routePattern) {
132
292
  return routePattern.split("/").map((segment) => {
133
293
  const optionalCatchAll = segment.match(/^\[\[\.\.\.(.+)\]\]$/);
@@ -152,7 +312,7 @@ function getPagesRouteParams(routePattern) {
152
312
  }).filter((param) => param !== null);
153
313
  }
154
314
  function matchesPagesStaticPath(pathEntry, params, routeParams, routeUrl) {
155
- if (typeof pathEntry === "string") return normalizeStaticPathname(pathEntry) === normalizeStaticPathname(routeUrl);
315
+ if (typeof pathEntry === "string") return normalizePathnameForRouteMatch(normalizeStaticPathname(pathEntry)) === normalizePathnameForRouteMatch(normalizeStaticPathname(routeUrl));
156
316
  const entryParams = pathEntry.params;
157
317
  if (entryParams === void 0 || entryParams === null) return false;
158
318
  return routeParams.every(({ key, repeat, optional }) => {
@@ -170,12 +330,12 @@ function matchesPagesStaticPath(pathEntry, params, routeParams, routeUrl) {
170
330
  return String(value) === String(actual);
171
331
  });
172
332
  }
173
- function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSeconds, expireSeconds, cacheControl, status) {
333
+ function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSeconds, expireSeconds, cacheControl, status, cachedHeaders) {
174
334
  const { cacheControl: cacheControlHeader } = decideIsr({
175
335
  cacheState,
176
336
  kind: "pages",
177
337
  revalidateSeconds: revalidateSeconds ?? 60,
178
- expireSeconds,
338
+ expireSeconds: cacheControl?.expire === void 0 ? void 0 : expireSeconds,
179
339
  cacheControlMeta: cacheControl
180
340
  });
181
341
  const headers = new Headers({
@@ -184,6 +344,13 @@ function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSec
184
344
  });
185
345
  applyCdnResponseHeaders(headers, { cacheControl: cacheControlHeader });
186
346
  if (fontLinkHeader) headers.set("Link", fontLinkHeader);
347
+ if (cachedHeaders) for (const [name, value] of Object.entries(cachedHeaders)) {
348
+ if (!isCachedPagesRepresentationHeader(name.toLowerCase())) continue;
349
+ if (Array.isArray(value)) {
350
+ headers.delete(name);
351
+ for (const item of value) headers.append(name, item);
352
+ } else headers.set(name, value);
353
+ }
187
354
  return new Response(html, {
188
355
  status: status ?? 200,
189
356
  headers
@@ -248,6 +415,7 @@ async function resolvePagesPageData(options) {
248
415
  const userFacingParams = options.route.isDynamic ? options.params : null;
249
416
  let isFallback = false;
250
417
  let shouldPersistFallbackData = false;
418
+ let onDemandPreviousCacheEntry;
251
419
  const previewData = options.isOnDemandRevalidate ? false : options.previewData ?? false;
252
420
  if (typeof options.pageModule.getStaticPaths === "function" && options.route.isDynamic) {
253
421
  const pathsResult = await options.pageModule.getStaticPaths({
@@ -258,11 +426,29 @@ async function resolvePagesPageData(options) {
258
426
  const paths = pathsResult?.paths ?? [];
259
427
  const routeParams = getPagesRouteParams(options.routePattern);
260
428
  const isValidPath = paths.some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, routeParams, options.routeUrl));
261
- if (fallback === false && !isValidPath && previewData === false) return buildPagesNotFoundResult(options);
429
+ if (fallback === false && !isValidPath && previewData === false) {
430
+ if (options.isOnDemandRevalidate && !options.revalidateOnlyGenerated) return {
431
+ kind: "response",
432
+ response: new Response("This page could not be found", { status: 404 }),
433
+ onDemandRevalidateSuccess: false
434
+ };
435
+ return buildPagesNotFoundResult(options);
436
+ }
262
437
  const isBotRequest = !!options.userAgent && isBotUserAgent(options.userAgent, options.htmlLimitedBots);
263
438
  if (fallback === true && !isValidPath && !options.isDataReq && !isBotRequest && previewData === false) isFallback = true;
264
439
  shouldPersistFallbackData = fallback === true && !isValidPath && options.isDataReq === true;
265
440
  }
441
+ if (typeof options.pageModule.getStaticProps === "function" && options.isOnDemandRevalidate && options.revalidateOnlyGenerated) {
442
+ const pathname = options.isrCachePathname ?? options.routeUrl.split("?")[0];
443
+ onDemandPreviousCacheEntry = await options.isrGet(options.isrCacheKey("pages", pathname));
444
+ if (!onDemandPreviousCacheEntry) return {
445
+ kind: "response",
446
+ response: new Response("This page could not be found", {
447
+ status: 404,
448
+ headers: { [NEXTJS_CACHE_HEADER]: "REVALIDATED" }
449
+ })
450
+ };
451
+ }
266
452
  let pageProps = {};
267
453
  let gsspRes = null;
268
454
  const previewContext = previewData === false ? {} : {
@@ -288,7 +474,7 @@ async function resolvePagesPageData(options) {
288
474
  return null;
289
475
  }
290
476
  if (isFallback) {
291
- const pathname = options.routeUrl.split("?")[0];
477
+ const pathname = options.isrCachePathname ?? options.routeUrl.split("?")[0];
292
478
  if ((await options.isrGet(options.isrCacheKey("pages", pathname)))?.value.value?.kind !== "PAGES") {
293
479
  const appShortCircuit = await loadForegroundAppInitialRenderProps();
294
480
  if (appShortCircuit) return appShortCircuit;
@@ -332,10 +518,7 @@ async function resolvePagesPageData(options) {
332
518
  response: await responsePromise
333
519
  };
334
520
  if (result?.props) {
335
- pageProps = {
336
- ...pageProps,
337
- ...await Promise.resolve(result.props)
338
- };
521
+ pageProps = mergePagesDataProps(renderProps.pageProps, await Promise.resolve(result.props));
339
522
  renderProps = {
340
523
  ...renderProps,
341
524
  pageProps
@@ -343,28 +526,22 @@ async function resolvePagesPageData(options) {
343
526
  }
344
527
  if (result?.redirect) return {
345
528
  kind: "response",
346
- response: buildPagesRedirectResponse(result.redirect, options, renderProps)
529
+ response: buildPagesRedirectResponse(result.redirect, options, renderProps, "getServerSideProps")
347
530
  };
348
531
  if (result?.notFound) return buildPagesNotFoundResult(options);
349
532
  if (result?.props !== void 0 && options.validatePropsSerialization !== false) isSerializableProps(options.routePattern, "getServerSideProps", pageProps);
350
533
  gsspRes = res;
351
534
  }
352
535
  let isrRevalidateSeconds = null;
536
+ let isrExpireSeconds;
353
537
  if (typeof options.pageModule.getStaticProps === "function") {
354
- const pathname = options.routeUrl.split("?")[0];
538
+ const pathname = options.isrCachePathname ?? options.routeUrl.split("?")[0];
355
539
  const cacheKey = options.isrCacheKey("pages", pathname);
356
- const cached = await options.isrGet(cacheKey);
540
+ const cached = onDemandPreviousCacheEntry !== void 0 ? onDemandPreviousCacheEntry : await options.isrGet(cacheKey);
357
541
  const cachedValue = cached?.value.value;
358
- if (!options.isOnDemandRevalidate && cached?.isStale === false && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) {
359
- const hitResponse = buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status);
360
- const hitBotResult = applyBotETagAndCheck(hitResponse, cachedValue.html, options);
361
- if (hitBotResult) return hitBotResult;
362
- return {
363
- kind: "response",
364
- response: hitResponse
365
- };
366
- }
367
- if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) {
542
+ const isLegacyCachedNotFound = cachedValue?.kind === "PAGES" && cachedValue.status === 404 && options.routePattern !== "/404" && options.routePattern !== "/_error";
543
+ const cachedRedirect = getCachedPagesRedirect(cachedValue);
544
+ const scheduleStaleRegeneration = () => {
368
545
  options.triggerBackgroundRegeneration(cacheKey, async function() {
369
546
  return options.runInFreshUnifiedContext(async () => {
370
547
  options.applyRequestContexts();
@@ -379,18 +556,35 @@ async function resolvePagesPageData(options) {
379
556
  defaultLocale: options.i18n.defaultLocale,
380
557
  revalidateReason: "stale"
381
558
  });
382
- if (freshResult?.props) {
383
- freshPageProps = {
384
- ...freshPageProps,
385
- ...freshResult.props
386
- };
387
- freshRenderProps = {
388
- ...freshRenderProps,
389
- pageProps: freshPageProps
390
- };
559
+ if (!freshResult) return;
560
+ assertPages404DoesNotReturnNotFound(options.routePattern, freshResult);
561
+ const revalidateSeconds = resolvePagesRevalidateSeconds(freshResult, options.routeUrl);
562
+ const expireSeconds = resolvePagesExpireSeconds(freshResult, options.expireSeconds);
563
+ if (freshResult.redirect) {
564
+ const redirect = resolvePagesRedirect(freshResult.redirect, {
565
+ method: "getStaticProps",
566
+ routeUrl: options.routeUrl,
567
+ sanitizeDestination: options.sanitizeDestination
568
+ });
569
+ await options.isrSet(cacheKey, {
570
+ kind: "REDIRECT",
571
+ props: buildPagesRedirectProps(redirect, freshRenderProps)
572
+ }, revalidateSeconds, void 0, expireSeconds);
573
+ return;
391
574
  }
392
- const freshRevalidateSeconds = typeof freshResult?.revalidate === "number" && freshResult.revalidate > 0 ? freshResult.revalidate : cached.value.cacheControl?.revalidate;
393
- if (freshResult?.props && freshRevalidateSeconds && freshRevalidateSeconds > 0) {
575
+ if (freshResult.notFound) {
576
+ await options.isrSet(cacheKey, null, revalidateSeconds, void 0, expireSeconds);
577
+ return;
578
+ }
579
+ if (freshResult.props === void 0) return;
580
+ const resolvedFreshProps = await Promise.resolve(freshResult.props);
581
+ freshPageProps = mergePagesDataProps(freshRenderProps.pageProps, resolvedFreshProps);
582
+ freshRenderProps = {
583
+ ...freshRenderProps,
584
+ pageProps: freshPageProps
585
+ };
586
+ if (options.validatePropsSerialization !== false) isSerializableProps(options.routePattern, "getStaticProps", freshPageProps);
587
+ if (cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest) {
394
588
  const freshHtml = await renderPagesIsrHtml({
395
589
  buildId: options.buildId,
396
590
  cachedHtml: cachedValue.html,
@@ -405,15 +599,61 @@ async function resolvePagesPageData(options) {
405
599
  nextData: options.nextData,
406
600
  vinext: options.vinext
407
601
  });
408
- await options.isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshRenderProps, options.statusCode), freshRevalidateSeconds, void 0, options.expireSeconds);
602
+ await options.isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshRenderProps, options.statusCode), revalidateSeconds, void 0, expireSeconds);
603
+ return;
409
604
  }
605
+ await options.isrSet(cacheKey, {
606
+ kind: "PAGES",
607
+ html: "",
608
+ pageData: freshRenderProps,
609
+ generatedFromDataRequest: true,
610
+ headers: void 0,
611
+ status: void 0
612
+ }, revalidateSeconds, void 0, expireSeconds);
410
613
  });
411
614
  }, {
412
615
  routerKind: "Pages Router",
413
616
  routePath: options.routePattern,
414
617
  routeType: "render"
415
618
  });
416
- const staleResponse = buildPagesCacheResponse(cachedValue.html, "STALE", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status);
619
+ };
620
+ if (!options.isOnDemandRevalidate && cached && !cached.isStale && !cached.isExpired && previewData === false) {
621
+ if (cachedValue === null) return buildCachedPagesNotFoundResult(options, cached.value, "HIT");
622
+ if (isLegacyCachedNotFound) return buildCachedPagesNotFoundResult(options, cached.value, "HIT");
623
+ if (cachedRedirect) return {
624
+ kind: "response",
625
+ response: applyCachedPagesRepresentationHeaders(buildCachedPagesRedirectResponse(cachedRedirect, options), "HIT", cached.value, options)
626
+ };
627
+ if (options.isDataReq && cachedValue?.kind === "PAGES") return {
628
+ kind: "response",
629
+ response: applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(cachedValue.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "HIT", cached.value, options)
630
+ };
631
+ }
632
+ if (!options.isOnDemandRevalidate && cached?.isStale === false && !cached.isExpired && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) {
633
+ const hitResponse = buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status, cachedValue.headers);
634
+ const hitBotResult = applyBotETagAndCheck(hitResponse, cachedValue.html, options);
635
+ if (hitBotResult) return hitBotResult;
636
+ return {
637
+ kind: "response",
638
+ response: hitResponse
639
+ };
640
+ }
641
+ if (!options.isOnDemandRevalidate && cached && cached.isStale && !cached.isExpired && !options.scriptNonce && previewData === false && (cachedValue === null || cachedRedirect !== null || isLegacyCachedNotFound || options.isDataReq)) {
642
+ scheduleStaleRegeneration();
643
+ if (cachedValue === null) return buildCachedPagesNotFoundResult(options, cached.value, "STALE");
644
+ if (isLegacyCachedNotFound) return buildCachedPagesNotFoundResult(options, cached.value, "STALE");
645
+ if (cachedRedirect) return {
646
+ kind: "response",
647
+ response: applyCachedPagesRepresentationHeaders(buildCachedPagesRedirectResponse(cachedRedirect, options), "STALE", cached.value, options)
648
+ };
649
+ if (cachedValue?.kind === "PAGES") return {
650
+ kind: "response",
651
+ response: applyCachedPagesRepresentationHeaders(buildNextDataPropsJsonResponse(normalizePagesRenderProps(cachedValue.pageData), options.safeJsonStringify, options.deploymentId ? { headers: { [NEXTJS_DEPLOYMENT_ID_HEADER]: options.deploymentId } } : void 0), "STALE", cached.value, options)
652
+ };
653
+ }
654
+ if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && cached.isStale && !cached.isExpired && !options.scriptNonce && !options.isDataReq && previewData === false) {
655
+ scheduleStaleRegeneration();
656
+ const staleResponse = buildPagesCacheResponse(cachedValue.html, "STALE", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status, cachedValue.headers);
417
657
  const staleBotResult = applyBotETagAndCheck(staleResponse, cachedValue.html, options);
418
658
  if (staleBotResult) return staleBotResult;
419
659
  return {
@@ -421,7 +661,7 @@ async function resolvePagesPageData(options) {
421
661
  response: staleResponse
422
662
  };
423
663
  }
424
- const generatedPageData = !options.isOnDemandRevalidate && previewData === false && cached?.isStale === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest && isUnknownRecord(cachedValue.pageData) ? cachedValue.pageData : null;
664
+ const generatedPageData = !options.isOnDemandRevalidate && previewData === false && cached?.isStale === false && !cached.isExpired && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest && isUnknownRecord(cachedValue.pageData) ? cachedValue.pageData : null;
425
665
  if (!generatedPageData) {
426
666
  const shortCircuit = await loadForegroundAppInitialRenderProps();
427
667
  if (shortCircuit) return shortCircuit;
@@ -434,30 +674,58 @@ async function resolvePagesPageData(options) {
434
674
  ...previewContext,
435
675
  revalidateReason: options.isOnDemandRevalidate ? "on-demand" : options.isBuildTimePrerendering ? "build" : "stale"
436
676
  });
677
+ assertPages404DoesNotReturnNotFound(options.routePattern, result);
437
678
  if (generatedPageData) {
438
- renderProps = generatedPageData;
679
+ renderProps = normalizePagesRenderProps(generatedPageData);
439
680
  pageProps = isUnknownRecord(renderProps.pageProps) ? renderProps.pageProps : {};
440
681
  }
441
- if (result?.props) {
442
- pageProps = {
443
- ...pageProps,
444
- ...result.props
445
- };
682
+ if (result?.props !== void 0) {
683
+ pageProps = mergePagesDataProps(renderProps.pageProps, await Promise.resolve(result.props));
446
684
  renderProps = {
447
685
  ...renderProps,
448
686
  pageProps
449
687
  };
450
688
  }
451
- if (result?.redirect) return {
452
- kind: "response",
453
- response: buildPagesRedirectResponse(result.redirect, options, renderProps)
454
- };
455
- if (result?.notFound) return buildPagesNotFoundResult(options);
689
+ if (result?.redirect) {
690
+ const response = buildPagesRedirectResponse(result.redirect, options, renderProps);
691
+ if (previewData === false) {
692
+ const revalidateSeconds = resolvePagesRevalidateSeconds(result, options.routeUrl);
693
+ const expireSeconds = resolvePagesExpireSeconds(result, options.expireSeconds);
694
+ const redirect = resolvePagesRedirect(result.redirect, {
695
+ method: "getStaticProps",
696
+ routeUrl: options.routeUrl,
697
+ sanitizeDestination: options.sanitizeDestination
698
+ });
699
+ await options.isrSet(cacheKey, {
700
+ kind: "REDIRECT",
701
+ props: buildPagesRedirectProps(redirect, renderProps)
702
+ }, revalidateSeconds, void 0, expireSeconds);
703
+ applyPagesTerminalMissHeaders(response, revalidateSeconds, pathname, expireSeconds);
704
+ }
705
+ return {
706
+ kind: "response",
707
+ response
708
+ };
709
+ }
710
+ if (result?.notFound) {
711
+ const revalidateSeconds = resolvePagesRevalidateSeconds(result, options.routeUrl);
712
+ const expireSeconds = resolvePagesExpireSeconds(result, options.expireSeconds);
713
+ if (previewData === false) await options.isrSet(cacheKey, null, revalidateSeconds, void 0, expireSeconds);
714
+ const notFoundResult = buildPagesNotFoundResult(options, revalidateSeconds, previewData === false ? "MISS" : void 0, expireSeconds);
715
+ if (notFoundResult.kind === "response" && previewData === false) applyPagesTerminalMissHeaders(notFoundResult.response, revalidateSeconds, pathname, expireSeconds);
716
+ return notFoundResult;
717
+ }
456
718
  if (result?.props !== void 0 && options.validatePropsSerialization !== false) isSerializableProps(options.routePattern, "getStaticProps", pageProps);
457
- if (previewData === false && typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
458
- else if (previewData === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest) isrRevalidateSeconds = cached?.value.cacheControl?.revalidate ?? 31536e3;
719
+ if (previewData === false && result) {
720
+ isrRevalidateSeconds = resolvePagesRevalidateSeconds(result, options.routeUrl);
721
+ isrExpireSeconds = resolvePagesExpireSeconds(result, options.expireSeconds);
722
+ } else if (previewData === false && options.isOnDemandRevalidate) isrRevalidateSeconds = false;
723
+ else if (previewData === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest) {
724
+ isrRevalidateSeconds = cached?.value.cacheControl?.revalidate ?? false;
725
+ isrExpireSeconds = cached?.value.cacheControl?.expire;
726
+ }
459
727
  if (shouldPersistFallbackData && previewData === false) {
460
- const revalidateSeconds = isrRevalidateSeconds ?? 31536e3;
728
+ const revalidateSeconds = isrRevalidateSeconds ?? false;
461
729
  await options.isrSet(cacheKey, {
462
730
  kind: "PAGES",
463
731
  html: "",
@@ -465,7 +733,7 @@ async function resolvePagesPageData(options) {
465
733
  generatedFromDataRequest: true,
466
734
  headers: void 0,
467
735
  status: void 0
468
- }, revalidateSeconds, void 0, options.expireSeconds);
736
+ }, revalidateSeconds, void 0, isrExpireSeconds);
469
737
  }
470
738
  }
471
739
  if (typeof options.pageModule.getServerSideProps !== "function" && typeof options.pageModule.getStaticProps !== "function" && hasPagesGetInitialProps(options.AppComponent)) {
@@ -505,10 +773,11 @@ async function resolvePagesPageData(options) {
505
773
  documentReqRes: sharedReqRes,
506
774
  gsspRes,
507
775
  isrRevalidateSeconds,
776
+ isrExpireSeconds,
508
777
  pageProps,
509
778
  props: renderProps,
510
779
  isFallback: false
511
780
  };
512
781
  }
513
782
  //#endregion
514
- export { getPagesRouteParams, matchesPagesStaticPath, renderPagesIsrHtml, resolvePagesPageData };
783
+ export { assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, renderPagesIsrHtml, resolvePagesPageData, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds };
@@ -1,4 +1,5 @@
1
1
  import { RenderPageEnhancers } from "./pages-document-initial-props.js";
2
+ import { PagesGetInitialPropsRouter } from "./pages-get-initial-props.js";
2
3
  import { PagesPageModule } from "./pages-page-data.js";
3
4
  import { ComponentType, ReactNode } from "react";
4
5
 
@@ -23,7 +24,7 @@ type I18nConfig = {
23
24
  domain: string;
24
25
  defaultLocale: string;
25
26
  locales?: string[];
26
- http?: boolean;
27
+ http?: true;
27
28
  }>;
28
29
  } | null;
29
30
  type VinextConfigSubset = {
@@ -60,7 +61,8 @@ type CreatePagesPageHandlerOptions = {
60
61
  */
61
62
  getPagesNavigationIsReadyFromSerializedState: ((routePattern: string | undefined, searchString: string, nextData?: Record<string, unknown>) => boolean) | null; /** `setI18nContext` from `vinext/i18n-context`. */
62
63
  setI18nContext: ((ctx: Record<string, unknown>) => void) | null; /** `wrapWithRouterContext` from `next/router`. */
63
- wrapWithRouterContext: ((element: ReactNode) => ReactNode) | null; /** `resetSSRHead` from `next/head`. */
64
+ wrapWithRouterContext: ((element: ReactNode) => ReactNode) | null; /** Request-scoped `next/router` server instance. */
65
+ router?: PagesGetInitialPropsRouter; /** `resetSSRHead` from `next/head`. */
64
66
  resetSSRHead: (() => void) | undefined; /** `getSSRHeadHTML` from `next/head`. */
65
67
  getSSRHeadHTML: (() => string) | undefined; /** `setDocumentInitialHead` from `next/head`. */
66
68
  setDocumentInitialHead: ((head: ReactNode[]) => void) | undefined; /** `flushPreloads` from `next/dynamic`. */
@@ -87,7 +89,11 @@ type RenderPageOptions = {
87
89
  originalUrl?: string;
88
90
  renderErrorPageOnMiss?: boolean;
89
91
  __isInternalErrorRender?: boolean;
90
- __forcedRoute?: PageRoute;
92
+ __forcedRoute?: PageRoute; /** Source-page cache lifetime forwarded while rendering a notFound error page. */
93
+ __notFoundRevalidateSeconds?: number | false; /** Source-page expire ceiling forwarded for the outgoing notFound response. */
94
+ __notFoundExpireSeconds?: number; /** Source-page identity used for the outgoing notFound cache tag. */
95
+ __notFoundCachePathname?: string; /** Internal recursion guard while a top-level on-demand request owns the batch. */
96
+ __skipOnDemandCoalesce?: boolean;
91
97
  err?: unknown;
92
98
  };
93
99
  /**