vinext 0.1.1 → 0.1.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 (266) hide show
  1. package/README.md +2 -5
  2. package/dist/build/client-build-config.d.ts +7 -1
  3. package/dist/build/client-build-config.js +9 -1
  4. package/dist/build/prerender.d.ts +9 -1
  5. package/dist/build/prerender.js +41 -12
  6. package/dist/build/run-prerender.d.ts +10 -2
  7. package/dist/build/run-prerender.js +15 -1
  8. package/dist/check.js +4 -3
  9. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  10. package/dist/client/app-nav-failure-handler.js +44 -0
  11. package/dist/client/navigation-runtime.d.ts +3 -2
  12. package/dist/client/vinext-next-data.d.ts +18 -1
  13. package/dist/client/window-next.d.ts +8 -5
  14. package/dist/client/window-next.js +12 -1
  15. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  16. package/dist/config/config-matchers.d.ts +11 -4
  17. package/dist/config/config-matchers.js +88 -16
  18. package/dist/config/next-config.d.ts +59 -4
  19. package/dist/config/next-config.js +149 -48
  20. package/dist/deploy.d.ts +30 -11
  21. package/dist/deploy.js +189 -101
  22. package/dist/entries/app-browser-entry.d.ts +9 -3
  23. package/dist/entries/app-browser-entry.js +21 -3
  24. package/dist/entries/app-rsc-entry.d.ts +2 -0
  25. package/dist/entries/app-rsc-entry.js +71 -6
  26. package/dist/entries/app-rsc-manifest.js +2 -0
  27. package/dist/entries/app-ssr-entry.js +1 -1
  28. package/dist/entries/pages-client-entry.js +54 -9
  29. package/dist/entries/pages-server-entry.js +48 -11
  30. package/dist/index.d.ts +0 -2
  31. package/dist/index.js +285 -139
  32. package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
  33. package/dist/plugins/dynamic-preload-metadata.js +415 -0
  34. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  35. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  36. package/dist/plugins/og-assets.js +2 -2
  37. package/dist/plugins/optimize-imports.d.ts +10 -5
  38. package/dist/plugins/optimize-imports.js +27 -21
  39. package/dist/plugins/postcss.js +7 -7
  40. package/dist/plugins/sass.d.ts +53 -24
  41. package/dist/plugins/sass.js +249 -1
  42. package/dist/plugins/typeof-window.d.ts +14 -0
  43. package/dist/plugins/typeof-window.js +150 -0
  44. package/dist/plugins/wasm-module-import.d.ts +15 -0
  45. package/dist/plugins/wasm-module-import.js +50 -0
  46. package/dist/routing/app-route-graph.d.ts +25 -2
  47. package/dist/routing/app-route-graph.js +91 -22
  48. package/dist/routing/file-matcher.d.ts +10 -1
  49. package/dist/routing/file-matcher.js +23 -2
  50. package/dist/routing/pages-router.js +3 -3
  51. package/dist/routing/utils.d.ts +35 -6
  52. package/dist/routing/utils.js +59 -7
  53. package/dist/server/api-handler.d.ts +6 -1
  54. package/dist/server/api-handler.js +21 -15
  55. package/dist/server/app-browser-action-result.d.ts +19 -6
  56. package/dist/server/app-browser-action-result.js +19 -10
  57. package/dist/server/app-browser-entry.js +269 -297
  58. package/dist/server/app-browser-error.d.ts +10 -3
  59. package/dist/server/app-browser-error.js +47 -6
  60. package/dist/server/app-browser-history-controller.d.ts +104 -0
  61. package/dist/server/app-browser-history-controller.js +210 -0
  62. package/dist/server/app-browser-hydration.d.ts +2 -0
  63. package/dist/server/app-browser-hydration.js +1 -0
  64. package/dist/server/app-browser-navigation-controller.d.ts +7 -4
  65. package/dist/server/app-browser-navigation-controller.js +33 -9
  66. package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
  67. package/dist/server/app-browser-rsc-redirect.js +30 -8
  68. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  69. package/dist/server/app-browser-server-action-navigation.js +9 -0
  70. package/dist/server/app-browser-state.js +4 -7
  71. package/dist/server/app-browser-stream.js +86 -43
  72. package/dist/server/app-browser-visible-commit.js +1 -1
  73. package/dist/server/app-elements-wire.d.ts +6 -1
  74. package/dist/server/app-elements-wire.js +14 -4
  75. package/dist/server/app-elements.d.ts +2 -2
  76. package/dist/server/app-elements.js +2 -2
  77. package/dist/server/app-fallback-renderer.d.ts +3 -1
  78. package/dist/server/app-fallback-renderer.js +6 -2
  79. package/dist/server/app-middleware.js +1 -0
  80. package/dist/server/app-optimistic-routing.js +24 -3
  81. package/dist/server/app-page-boundary-render.d.ts +3 -1
  82. package/dist/server/app-page-boundary-render.js +31 -16
  83. package/dist/server/app-page-cache-render.d.ts +53 -0
  84. package/dist/server/app-page-cache-render.js +91 -0
  85. package/dist/server/app-page-cache.d.ts +16 -2
  86. package/dist/server/app-page-cache.js +71 -8
  87. package/dist/server/app-page-dispatch.d.ts +34 -0
  88. package/dist/server/app-page-dispatch.js +167 -97
  89. package/dist/server/app-page-element-builder.d.ts +23 -2
  90. package/dist/server/app-page-element-builder.js +42 -10
  91. package/dist/server/app-page-execution.d.ts +7 -2
  92. package/dist/server/app-page-execution.js +53 -18
  93. package/dist/server/app-page-probe.d.ts +1 -0
  94. package/dist/server/app-page-probe.js +4 -0
  95. package/dist/server/app-page-render-observation.d.ts +3 -1
  96. package/dist/server/app-page-render-observation.js +17 -1
  97. package/dist/server/app-page-render.d.ts +13 -2
  98. package/dist/server/app-page-render.js +48 -17
  99. package/dist/server/app-page-request.d.ts +3 -0
  100. package/dist/server/app-page-request.js +5 -3
  101. package/dist/server/app-page-response.js +1 -1
  102. package/dist/server/app-page-route-wiring.d.ts +5 -1
  103. package/dist/server/app-page-route-wiring.js +21 -11
  104. package/dist/server/app-page-stream.d.ts +16 -9
  105. package/dist/server/app-page-stream.js +12 -9
  106. package/dist/server/app-pages-bridge.d.ts +18 -0
  107. package/dist/server/app-pages-bridge.js +22 -5
  108. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  109. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  110. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  111. package/dist/server/app-ppr-fallback-shell.js +8 -1
  112. package/dist/server/app-route-handler-dispatch.js +9 -2
  113. package/dist/server/app-route-handler-policy.d.ts +1 -0
  114. package/dist/server/app-route-handler-response.js +11 -10
  115. package/dist/server/app-route-handler-runtime.js +12 -1
  116. package/dist/server/app-router-entry.js +5 -0
  117. package/dist/server/app-rsc-cache-busting.js +2 -0
  118. package/dist/server/app-rsc-handler.d.ts +25 -0
  119. package/dist/server/app-rsc-handler.js +153 -53
  120. package/dist/server/app-rsc-response-finalizer.js +1 -1
  121. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  122. package/dist/server/app-rsc-route-matching.js +2 -0
  123. package/dist/server/app-segment-config.d.ts +9 -1
  124. package/dist/server/app-segment-config.js +12 -3
  125. package/dist/server/app-server-action-execution.d.ts +12 -0
  126. package/dist/server/app-server-action-execution.js +47 -15
  127. package/dist/server/app-ssr-entry.d.ts +2 -0
  128. package/dist/server/app-ssr-entry.js +81 -8
  129. package/dist/server/app-ssr-stream.js +9 -1
  130. package/dist/server/cache-control.js +4 -0
  131. package/dist/server/dev-lockfile.js +2 -1
  132. package/dist/server/dev-server.d.ts +2 -2
  133. package/dist/server/dev-server.js +287 -63
  134. package/dist/server/headers.d.ts +8 -1
  135. package/dist/server/headers.js +8 -1
  136. package/dist/server/hybrid-route-priority.d.ts +22 -0
  137. package/dist/server/hybrid-route-priority.js +33 -0
  138. package/dist/server/image-optimization.d.ts +18 -9
  139. package/dist/server/image-optimization.js +37 -23
  140. package/dist/server/implicit-tags.d.ts +2 -1
  141. package/dist/server/implicit-tags.js +4 -1
  142. package/dist/server/instrumentation-runtime.d.ts +6 -0
  143. package/dist/server/instrumentation-runtime.js +8 -0
  144. package/dist/server/isr-decision.d.ts +79 -0
  145. package/dist/server/isr-decision.js +70 -0
  146. package/dist/server/metadata-route-response.js +5 -3
  147. package/dist/server/middleware-runtime.d.ts +13 -0
  148. package/dist/server/middleware-runtime.js +11 -7
  149. package/dist/server/middleware.js +1 -0
  150. package/dist/server/navigation-planner.d.ts +186 -22
  151. package/dist/server/navigation-planner.js +302 -0
  152. package/dist/server/navigation-trace.d.ts +18 -1
  153. package/dist/server/navigation-trace.js +18 -1
  154. package/dist/server/normalize-path.d.ts +0 -8
  155. package/dist/server/normalize-path.js +3 -1
  156. package/dist/server/otel-tracer-extension.d.ts +45 -0
  157. package/dist/server/otel-tracer-extension.js +89 -0
  158. package/dist/server/pages-api-route.d.ts +20 -3
  159. package/dist/server/pages-api-route.js +19 -3
  160. package/dist/server/pages-asset-tags.d.ts +16 -4
  161. package/dist/server/pages-asset-tags.js +22 -12
  162. package/dist/server/pages-data-route.d.ts +8 -1
  163. package/dist/server/pages-data-route.js +16 -3
  164. package/dist/server/pages-get-initial-props.d.ts +54 -4
  165. package/dist/server/pages-get-initial-props.js +43 -1
  166. package/dist/server/pages-node-compat.d.ts +3 -11
  167. package/dist/server/pages-node-compat.js +175 -122
  168. package/dist/server/pages-page-data.d.ts +39 -2
  169. package/dist/server/pages-page-data.js +261 -46
  170. package/dist/server/pages-page-handler.d.ts +5 -2
  171. package/dist/server/pages-page-handler.js +78 -25
  172. package/dist/server/pages-page-response.d.ts +47 -2
  173. package/dist/server/pages-page-response.js +73 -9
  174. package/dist/server/pages-readiness.d.ts +1 -1
  175. package/dist/server/pages-request-pipeline.d.ts +16 -1
  176. package/dist/server/pages-request-pipeline.js +96 -38
  177. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  178. package/dist/server/pregenerated-concrete-paths.js +2 -19
  179. package/dist/server/prerender-manifest.d.ts +33 -0
  180. package/dist/server/prerender-manifest.js +54 -0
  181. package/dist/server/prerender-route-params.d.ts +1 -2
  182. package/dist/server/prod-server.d.ts +39 -1
  183. package/dist/server/prod-server.js +107 -37
  184. package/dist/server/request-pipeline.d.ts +3 -15
  185. package/dist/server/request-pipeline.js +58 -47
  186. package/dist/server/rsc-stream-hints.d.ts +5 -1
  187. package/dist/server/rsc-stream-hints.js +6 -1
  188. package/dist/server/seed-cache.js +10 -18
  189. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  190. package/dist/shims/app-router-scroll-state.js +14 -2
  191. package/dist/shims/app-router-scroll.d.ts +3 -0
  192. package/dist/shims/app-router-scroll.js +28 -18
  193. package/dist/shims/cache-runtime.js +12 -4
  194. package/dist/shims/cache.d.ts +1 -0
  195. package/dist/shims/cache.js +1 -1
  196. package/dist/shims/cdn-cache.d.ts +5 -5
  197. package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
  198. package/dist/shims/dynamic-preload-chunks.js +79 -0
  199. package/dist/shims/dynamic.d.ts +4 -0
  200. package/dist/shims/dynamic.js +4 -2
  201. package/dist/shims/error-boundary.d.ts +6 -4
  202. package/dist/shims/error-boundary.js +7 -0
  203. package/dist/shims/error.js +38 -11
  204. package/dist/shims/error.react-server.d.ts +9 -0
  205. package/dist/shims/error.react-server.js +6 -0
  206. package/dist/shims/fetch-cache.d.ts +11 -1
  207. package/dist/shims/fetch-cache.js +55 -20
  208. package/dist/shims/hash-scroll.js +6 -1
  209. package/dist/shims/head.js +6 -1
  210. package/dist/shims/headers.d.ts +16 -2
  211. package/dist/shims/headers.js +66 -5
  212. package/dist/shims/image-config.js +7 -1
  213. package/dist/shims/internal/als-registry.js +28 -1
  214. package/dist/shims/internal/app-route-detection.d.ts +6 -3
  215. package/dist/shims/internal/app-route-detection.js +18 -23
  216. package/dist/shims/internal/app-router-context.d.ts +5 -0
  217. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  218. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  219. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  220. package/dist/shims/internal/navigation-untracked.js +55 -0
  221. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  222. package/dist/shims/internal/pages-data-target.js +17 -8
  223. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  224. package/dist/shims/internal/pages-router-accessor.js +13 -0
  225. package/dist/shims/internal/router-context.d.ts +2 -1
  226. package/dist/shims/internal/router-context.js +3 -1
  227. package/dist/shims/link.js +12 -5
  228. package/dist/shims/metadata.d.ts +6 -2
  229. package/dist/shims/metadata.js +32 -14
  230. package/dist/shims/navigation.d.ts +14 -17
  231. package/dist/shims/navigation.js +93 -46
  232. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  233. package/dist/shims/ppr-fallback-shell.js +28 -7
  234. package/dist/shims/router.d.ts +13 -2
  235. package/dist/shims/router.js +434 -116
  236. package/dist/shims/script-nonce-context.d.ts +1 -1
  237. package/dist/shims/script-nonce-context.js +11 -3
  238. package/dist/shims/server.d.ts +33 -2
  239. package/dist/shims/server.js +75 -18
  240. package/dist/shims/slot.js +1 -1
  241. package/dist/shims/unified-request-context.js +2 -0
  242. package/dist/typegen.js +1 -0
  243. package/dist/utils/built-asset-url.d.ts +4 -0
  244. package/dist/utils/built-asset-url.js +11 -0
  245. package/dist/utils/client-build-manifest.js +15 -5
  246. package/dist/utils/client-runtime-metadata.d.ts +45 -0
  247. package/dist/utils/client-runtime-metadata.js +63 -0
  248. package/dist/utils/commonjs-loader.d.ts +16 -0
  249. package/dist/utils/commonjs-loader.js +100 -0
  250. package/dist/utils/deployment-id.d.ts +8 -0
  251. package/dist/utils/deployment-id.js +22 -0
  252. package/dist/utils/hash.d.ts +17 -1
  253. package/dist/utils/hash.js +36 -1
  254. package/dist/utils/html-limited-bots.d.ts +18 -1
  255. package/dist/utils/html-limited-bots.js +23 -1
  256. package/dist/utils/lazy-chunks.d.ts +27 -1
  257. package/dist/utils/lazy-chunks.js +65 -1
  258. package/dist/utils/manifest-paths.d.ts +20 -2
  259. package/dist/utils/manifest-paths.js +38 -3
  260. package/dist/utils/parse-cookie.d.ts +13 -0
  261. package/dist/utils/parse-cookie.js +52 -0
  262. package/dist/utils/path.d.ts +8 -1
  263. package/dist/utils/path.js +13 -1
  264. package/package.json +2 -2
  265. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  266. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -1,16 +1,20 @@
1
1
  import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { patternToNextFormat } from "../routing/route-validation.js";
3
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
+ import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
4
5
  import { reportRequestError } from "./instrumentation.js";
6
+ import { NEVER_CACHE_CONTROL } from "./cache-control.js";
7
+ import "./isr-decision.js";
5
8
  import { PRERENDER_REVALIDATE_HEADER, isOnDemandRevalidateRequest, isrCacheKey, isrGet, isrSet, triggerBackgroundRegeneration } from "./isr-cache.js";
6
9
  import { ensureFetchPatch } from "../shims/fetch-cache.js";
10
+ import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
7
11
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
8
12
  import { getScriptNonceFromHeaderSources } from "./csp.js";
9
13
  import { resolvePagesI18nRequest } from "./pages-i18n.js";
10
14
  import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
11
15
  import { buildPagesReadinessNextData } from "./pages-readiness.js";
12
16
  import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
13
- import { buildNextDataJsonResponse, buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
17
+ import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
14
18
  import { createPagesReqRes } from "./pages-node-compat.js";
15
19
  import { collectAssetTags, resolveClientModuleUrl } from "./pages-asset-tags.js";
16
20
  import { renderPagesPageResponse } from "./pages-page-response.js";
@@ -45,19 +49,38 @@ function createPagesPageHandler(opts) {
45
49
  }
46
50
  async function renderPage(request, url, manifest, middlewareHeaders, options) {
47
51
  let isDataReq = !!(options && options.isDataReq);
52
+ const requestUrl = new URL(request.url);
53
+ const rawOriginalUrl = options && typeof options.originalUrl === "string" ? options.originalUrl : requestUrl.pathname + requestUrl.search;
54
+ const originalRequestUrl = new URL(rawOriginalUrl, requestUrl);
55
+ const originalRequestPathAndSearch = originalRequestUrl.pathname + originalRequestUrl.search;
56
+ let dataRequestPathname = null;
57
+ let dataRequestSearch = "";
58
+ const initialDataNorm = normalizePagesDataRequest(request, buildId);
48
59
  if (!isDataReq) {
49
- const dataNorm = normalizePagesDataRequest(request, buildId);
50
- if (dataNorm.notFoundResponse) return dataNorm.notFoundResponse;
51
- if (dataNorm.isDataReq) {
60
+ if (initialDataNorm.notFoundResponse) return initialDataNorm.notFoundResponse;
61
+ if (initialDataNorm.isDataReq) {
52
62
  isDataReq = true;
63
+ dataRequestPathname = initialDataNorm.normalizedPathname;
64
+ dataRequestSearch = initialDataNorm.search;
53
65
  if (url && url.startsWith("/_next/data/")) {
54
66
  const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
55
- url = dataNorm.normalizedPathname + qs;
67
+ url = initialDataNorm.normalizedPathname + qs;
56
68
  }
57
69
  }
70
+ } else if (initialDataNorm.isDataReq) {
71
+ dataRequestPathname = initialDataNorm.normalizedPathname;
72
+ dataRequestSearch = initialDataNorm.search;
73
+ }
74
+ if (isDataReq && dataRequestPathname === null && buildId) {
75
+ const originalDataMatch = parseNextDataPathname(originalRequestUrl.pathname, buildId);
76
+ if (originalDataMatch) {
77
+ dataRequestPathname = originalDataMatch.pagePathname;
78
+ dataRequestSearch = originalRequestUrl.search;
79
+ }
58
80
  }
59
81
  const statusCode = options && typeof options.statusCode === "number" ? options.statusCode : void 0;
60
- const asPath = options && typeof options.asPath === "string" ? options.asPath : void 0;
82
+ const defaultAsPath = isDataReq && dataRequestPathname ? dataRequestPathname + dataRequestSearch : originalRequestPathAndSearch;
83
+ const asPath = options && typeof options.asPath === "string" ? options.asPath : defaultAsPath;
61
84
  const renderErrorPageOnMiss = !(options && options.renderErrorPageOnMiss === false);
62
85
  const isInternalErrorRender = !!(options && options.__isInternalErrorRender);
63
86
  const err = options && options.err;
@@ -140,8 +163,8 @@ function createPagesPageHandler(opts) {
140
163
  });
141
164
  if (methodResponse) return methodResponse;
142
165
  }
143
- const pageModuleUrl = resolveClientModuleUrl(manifest, route.filePath);
144
- const appModuleUrl = resolveClientModuleUrl(manifest, appAssetPath);
166
+ const pageModuleUrl = resolveClientModuleUrl(manifest, route.filePath, vinextConfig.basePath, vinextConfig.assetPrefix, process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID);
167
+ const appModuleUrl = resolveClientModuleUrl(manifest, appAssetPath, vinextConfig.basePath, vinextConfig.assetPrefix, process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID);
145
168
  const serializedPagesNextData = {
146
169
  ...pagesNextData,
147
170
  __vinext: {
@@ -156,23 +179,30 @@ function createPagesPageHandler(opts) {
156
179
  let allFontPreloads = [];
157
180
  try {
158
181
  allFontPreloads = getFontPreloads();
159
- if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + p.href + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
182
+ if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + appendAssetDeploymentIdQuery(p.href) + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
160
183
  } catch {}
184
+ const pagesResolvedUrl = (new URL(routeUrl, originalRequestUrl).pathname || "/") + originalRequestUrl.search;
161
185
  const pageDataResult = await resolvePagesPageData({
162
186
  isDataReq,
163
187
  err,
164
188
  applyRequestContexts: applySSRContext,
165
189
  buildId,
190
+ deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID,
191
+ htmlLimitedBots: vinextConfig.htmlLimitedBots,
166
192
  createGsspReqRes() {
167
193
  return createPagesReqRes({
168
194
  body: void 0,
169
195
  query,
170
196
  request,
171
- url: routeUrl
197
+ url: originalRequestPathAndSearch
172
198
  });
173
199
  },
174
- createPageElement(currentPageProps) {
175
- const el = createPageElement(PageComponent, AppComponent, currentPageProps);
200
+ createAppTree(appTreeProps) {
201
+ const el = createPageElement(PageComponent, AppComponent, appTreeProps);
202
+ return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
203
+ },
204
+ createPageElement(currentProps) {
205
+ const el = createPageElement(PageComponent, AppComponent, currentProps);
176
206
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
177
207
  },
178
208
  fontLinkHeader,
@@ -184,15 +214,17 @@ function createPagesPageHandler(opts) {
184
214
  isBuildTimePrerendering: typeof process !== "undefined" && process.env && process.env.VINEXT_PRERENDER === "1",
185
215
  isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER)),
186
216
  pageModule,
217
+ AppComponent,
187
218
  params,
188
219
  query,
189
220
  asPath: renderAsPath ?? routeUrl,
221
+ resolvedUrl: pagesResolvedUrl,
190
222
  renderIsrPassToStringAsync,
191
223
  route: { isDynamic: route.isDynamic },
192
224
  routePattern,
193
225
  routeUrl,
194
226
  runInFreshUnifiedContext(callback) {
195
- return runWithRequestContext(createRequestContext({ executionContext: getRequestExecutionContext() }), async () => {
227
+ return runWithRequestContext(createRequestContext({ executionContext: null }), async () => {
196
228
  ensureFetchPatch();
197
229
  return callback();
198
230
  });
@@ -203,7 +235,10 @@ function createPagesPageHandler(opts) {
203
235
  statusCode: renderStatusCode,
204
236
  triggerBackgroundRegeneration,
205
237
  vinext: serializedPagesNextData.__vinext,
206
- nextData: serializedPagesNextData
238
+ nextData: serializedPagesNextData,
239
+ userAgent: request.headers.get("user-agent") ?? void 0,
240
+ ifNoneMatch: request.headers.get("if-none-match") ?? void 0,
241
+ requestCacheControl: request.headers.get("cache-control") ?? void 0
207
242
  });
208
243
  if (pageDataResult.kind === "notFound") {
209
244
  const notFoundRoute = findNotFoundRoute();
@@ -217,10 +252,17 @@ function createPagesPageHandler(opts) {
217
252
  }
218
253
  if (pageDataResult.kind === "response") return pageDataResult.response;
219
254
  let pageProps = pageDataResult.pageProps;
220
- if (routePattern === "/_error" && typeof renderStatusCode === "number") pageProps = {
221
- ...pageProps,
222
- statusCode: renderStatusCode
223
- };
255
+ let renderProps = pageDataResult.props;
256
+ if (routePattern === "/_error" && typeof renderStatusCode === "number") {
257
+ pageProps = {
258
+ ...pageProps,
259
+ statusCode: renderStatusCode
260
+ };
261
+ renderProps = {
262
+ ...renderProps,
263
+ pageProps
264
+ };
265
+ }
224
266
  const gsspRes = pageDataResult.gsspRes;
225
267
  const isrRevalidateSeconds = pageDataResult.isrRevalidateSeconds;
226
268
  const isFallbackRender = pageDataResult.isFallback === true;
@@ -251,9 +293,13 @@ function createPagesPageHandler(opts) {
251
293
  hasUserCacheControl = true;
252
294
  break;
253
295
  }
254
- if (!hasUserCacheControl) init.headers["Cache-Control"] = "private, no-cache, no-store, max-age=0, must-revalidate";
296
+ if (!hasUserCacheControl) init.headers["Cache-Control"] = NEVER_CACHE_CONTROL;
297
+ }
298
+ if (routePattern !== "/_error" && routePattern !== "/500") {
299
+ const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
300
+ if (deploymentId) init.headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
255
301
  }
256
- return buildNextDataJsonResponse(pageProps, safeJsonStringify, init);
302
+ return buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, init);
257
303
  }
258
304
  const pageModuleIds = [];
259
305
  if (route.filePath) pageModuleIds.push(route.filePath);
@@ -263,18 +309,21 @@ function createPagesPageHandler(opts) {
263
309
  manifest,
264
310
  moduleIds: pageModuleIds,
265
311
  scriptNonce,
266
- disableOptimizedLoading: vinextConfig.disableOptimizedLoading
312
+ disableOptimizedLoading: vinextConfig.disableOptimizedLoading,
313
+ basePath: vinextConfig.basePath,
314
+ assetPrefix: vinextConfig.assetPrefix,
315
+ deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID
267
316
  }),
268
317
  buildId,
269
318
  clearSsrContext() {
270
319
  if (typeof setSSRContext === "function") setSSRContext(null);
271
320
  },
272
- createPageElement(currentPageProps) {
273
- const el = createPageElement(PageComponent, AppComponent, currentPageProps);
321
+ createPageElement(currentProps) {
322
+ const el = createPageElement(PageComponent, AppComponent, currentProps);
274
323
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
275
324
  },
276
325
  enhancePageElement(renderPageOpts) {
277
- const el = enhancePageElement(PageComponent, AppComponent, pageProps, renderPageOpts);
326
+ const el = enhancePageElement(PageComponent, AppComponent, renderProps, renderPageOpts);
278
327
  return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
279
328
  },
280
329
  DocumentComponent,
@@ -293,6 +342,7 @@ function createPagesPageHandler(opts) {
293
342
  i18n: buildI18nRenderContext(i18nConfig, locale, currentDefaultLocale, domainLocales),
294
343
  isFallback: isFallbackRender,
295
344
  pageProps,
345
+ props: renderProps,
296
346
  params,
297
347
  renderDocumentToString(element) {
298
348
  return renderToStringAsync(element);
@@ -305,7 +355,10 @@ function createPagesPageHandler(opts) {
305
355
  safeJsonStringify,
306
356
  scriptNonce,
307
357
  statusCode: renderStatusCode,
308
- nextData: serializedPagesNextData
358
+ nextData: serializedPagesNextData,
359
+ userAgent: request.headers.get("user-agent") ?? void 0,
360
+ ifNoneMatch: request.headers.get("if-none-match") ?? void 0,
361
+ requestCacheControl: request.headers.get("cache-control") ?? void 0
309
362
  });
310
363
  } catch (e) {
311
364
  console.error("[vinext] SSR error:", e);
@@ -4,6 +4,28 @@ import { RenderPageEnhancers } from "./pages-document-initial-props.js";
4
4
  import { ComponentType, ReactNode } from "react";
5
5
 
6
6
  //#region src/server/pages-page-response.d.ts
7
+ /**
8
+ * Returns true when the User-Agent belongs to a bot or crawler that cannot
9
+ * reliably consume a streamed HTML response.
10
+ */
11
+ declare function isPagesStreamingBot(userAgent: string): boolean;
12
+ declare function generatePagesETag(payload: string): string;
13
+ /**
14
+ * Mirrors Next.js `sendEtagResponse` semantics (weak/strong comparison).
15
+ *
16
+ * A weak ETag `W/"..."` matches both `W/"..."` and `"..."` in `If-None-Match`.
17
+ * A strong ETag `"..."` only matches the same strong token.
18
+ * `*` always matches.
19
+ */
20
+ declare function etagMatches(etag: string, ifNoneMatch: string): boolean;
21
+ /**
22
+ * Returns true when a request `Cache-Control` header asks to bypass the 304
23
+ * short-circuit. Mirrors the `fresh` package's check used by Next.js's
24
+ * `sendEtagResponse` (`/(?:^|,)\s*?no-cache\s*?(?:,|$)/`). Shared by the
25
+ * fresh-MISS bot path here and the ISR HIT/STALE paths in
26
+ * `pages-page-data.ts` so the two cannot drift.
27
+ */
28
+ declare function requestsNoCache(cacheControl: string | undefined): boolean;
7
29
  type PagesFontPreload = {
8
30
  href: string;
9
31
  type: string;
@@ -71,6 +93,7 @@ type RenderPagesPageResponseOptions = {
71
93
  */
72
94
  isFallback?: boolean;
73
95
  pageProps: Record<string, unknown>;
96
+ props?: Record<string, unknown>;
74
97
  params: Record<string, unknown>;
75
98
  renderDocumentToString: (element: ReactNode) => Promise<string>;
76
99
  renderToReadableStream: (element: ReactNode) => Promise<ReadableStream<Uint8Array>>;
@@ -82,10 +105,32 @@ type RenderPagesPageResponseOptions = {
82
105
  statusCode?: number;
83
106
  vinext?: VinextNextData["__vinext"];
84
107
  nextData?: PagesNextDataExtras;
108
+ /**
109
+ * The request's User-Agent string (from `request.headers.get('user-agent')`).
110
+ * When this matches a known crawler / bot pattern, the response is fully
111
+ * buffered before sending so bots receive a single complete HTML chunk with
112
+ * an ETag header. Omitting this field disables bot-detection (streaming as
113
+ * normal), which is the correct behaviour for non-HTML requests and tests.
114
+ */
115
+ userAgent?: string;
116
+ /**
117
+ * The incoming request's `If-None-Match` header value. When set and the
118
+ * computed ETag matches (weak-ETag semantics, mirroring Next.js's
119
+ * `sendEtagResponse`), a `304 Not Modified` is returned with an empty body.
120
+ * Only evaluated on bot/buffered responses that carry an ETag.
121
+ */
122
+ ifNoneMatch?: string;
123
+ /**
124
+ * The incoming request's `Cache-Control` header value. When the value
125
+ * contains `no-cache`, the 304 short-circuit is skipped and a full 200
126
+ * response is always returned — mirroring the `fresh` package used by
127
+ * Next.js's `sendEtagResponse`.
128
+ */
129
+ requestCacheControl?: string;
85
130
  };
86
- declare function buildPagesNextDataScript(options: Pick<RenderPagesPageResponseOptions, "buildId" | "i18n" | "isFallback" | "pageProps" | "params" | "routePattern" | "safeJsonStringify" | "scriptNonce" | "nextData"> & {
131
+ declare function buildPagesNextDataScript(options: Pick<RenderPagesPageResponseOptions, "buildId" | "i18n" | "isFallback" | "pageProps" | "props" | "params" | "routePattern" | "safeJsonStringify" | "scriptNonce" | "nextData"> & {
87
132
  vinext?: VinextNextData["__vinext"];
88
133
  }): string;
89
134
  declare function renderPagesPageResponse(options: RenderPagesPageResponseOptions): Promise<Response>;
90
135
  //#endregion
91
- export { PagesGsspResponse, PagesI18nRenderContext, PagesNextDataExtras, buildPagesNextDataScript, renderPagesPageResponse };
136
+ export { PagesGsspResponse, PagesI18nRenderContext, PagesNextDataExtras, buildPagesNextDataScript, etagMatches, generatePagesETag, isPagesStreamingBot, renderPagesPageResponse, requestsNoCache };
@@ -1,27 +1,76 @@
1
1
  import { getRequestExecutionContext } from "../shims/request-context.js";
2
2
  import { reportRequestError } from "./instrumentation.js";
3
3
  import { setCacheStateHeaders } from "./cache-headers.js";
4
+ import { fnv1a52 } from "../utils/hash.js";
4
5
  import { encodeCacheTag } from "../utils/encode-cache-tag.js";
6
+ import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
7
+ import { buildMissIsrCacheControl } from "./isr-decision.js";
8
+ import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
5
9
  import { withScriptNonce } from "../shims/script-nonce-context.js";
6
10
  import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from "./html.js";
7
11
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
8
12
  import { readStreamAsText } from "../utils/text-stream.js";
9
13
  import { loadUserDocumentInitialProps, runDocumentRenderPage } from "./pages-document-initial-props.js";
10
14
  import { callDocumentGetInitialProps } from "./document-initial-head.js";
11
- import { applyCdnResponseHeaders, buildRevalidateCacheControl } from "./cache-control.js";
12
15
  import React from "react";
13
16
  //#region src/server/pages-page-response.ts
17
+ /**
18
+ * Crawlers that cannot handle streamed HTML: they read metadata only from
19
+ * the first network chunk, so streaming would give them an incomplete <head>.
20
+ * Pattern sourced from Next.js html-bots.ts (updated to match the canary).
21
+ */
22
+ const HTML_LIMITED_BOT_UA_RE = /[\w-]+-Google|Google-[\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight/i;
23
+ /**
24
+ * Googlebot (the main search crawler) executes JavaScript via a headless
25
+ * browser, so it too cannot safely handle mid-stream HTML mutations.
26
+ * Matches "Googlebot" but NOT suffixed variants like "Googlebot-Image".
27
+ */
28
+ const HEADLESS_BROWSER_BOT_UA_RE = /Googlebot(?!-)|Googlebot$/i;
29
+ /**
30
+ * Returns true when the User-Agent belongs to a bot or crawler that cannot
31
+ * reliably consume a streamed HTML response.
32
+ */
33
+ function isPagesStreamingBot(userAgent) {
34
+ return HEADLESS_BROWSER_BOT_UA_RE.test(userAgent) || HTML_LIMITED_BOT_UA_RE.test(userAgent);
35
+ }
36
+ function generatePagesETag(payload) {
37
+ return "\"" + fnv1a52(payload).toString(36) + payload.length.toString(36) + "\"";
38
+ }
39
+ /**
40
+ * Mirrors Next.js `sendEtagResponse` semantics (weak/strong comparison).
41
+ *
42
+ * A weak ETag `W/"..."` matches both `W/"..."` and `"..."` in `If-None-Match`.
43
+ * A strong ETag `"..."` only matches the same strong token.
44
+ * `*` always matches.
45
+ */
46
+ function etagMatches(etag, ifNoneMatch) {
47
+ if (ifNoneMatch === "*") return true;
48
+ const normalize = (t) => t.replace(/^W\//, "");
49
+ const etagNorm = normalize(etag.trim());
50
+ for (const token of ifNoneMatch.split(",")) if (normalize(token.trim()) === etagNorm) return true;
51
+ return false;
52
+ }
53
+ /**
54
+ * Returns true when a request `Cache-Control` header asks to bypass the 304
55
+ * short-circuit. Mirrors the `fresh` package's check used by Next.js's
56
+ * `sendEtagResponse` (`/(?:^|,)\s*?no-cache\s*?(?:,|$)/`). Shared by the
57
+ * fresh-MISS bot path here and the ISR HIT/STALE paths in
58
+ * `pages-page-data.ts` so the two cannot drift.
59
+ */
60
+ function requestsNoCache(cacheControl) {
61
+ return /(?:^|,)\s*no-cache\s*(?:,|$)/.test(cacheControl ?? "");
62
+ }
14
63
  function buildPagesFontHeadHtml(fontLinks, fontPreloads, fontStyles, scriptNonce) {
15
64
  let html = "";
16
65
  const nonceAttr = createNonceAttribute(scriptNonce);
17
- for (const link of fontLinks) html += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(link)}" />\n `;
18
- for (const preload of fontPreloads) html += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(preload.href)}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n `;
66
+ for (const link of fontLinks) html += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(link))}" />\n `;
67
+ for (const preload of fontPreloads) html += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(preload.href))}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n `;
19
68
  if (fontStyles.length > 0) html += `<style data-vinext-fonts${nonceAttr}>${fontStyles.join("\n")}</style>\n `;
20
69
  return html;
21
70
  }
22
71
  function buildPagesNextDataScript(options) {
23
72
  const nextDataPayload = {
24
- props: { pageProps: options.pageProps },
73
+ props: options.props ?? { pageProps: options.pageProps },
25
74
  page: options.routePattern,
26
75
  query: options.params,
27
76
  buildId: options.buildId,
@@ -123,6 +172,7 @@ function applyGsspHeaders(headers, gsspRes, statusCode) {
123
172
  return statusCode ?? gsspRes.statusCode;
124
173
  }
125
174
  async function renderPagesPageResponse(options) {
175
+ const renderProps = options.props ?? { pageProps: options.pageProps };
126
176
  options.resetSSRHead?.();
127
177
  await options.flushPreloads?.();
128
178
  const fontHeadHTML = buildPagesFontHeadHtml(options.getFontLinks(), options.fontPreloads, options.getFontStyles(), options.scriptNonce);
@@ -131,6 +181,7 @@ async function renderPagesPageResponse(options) {
131
181
  i18n: options.i18n,
132
182
  isFallback: options.isFallback,
133
183
  pageProps: options.pageProps,
184
+ props: renderProps,
134
185
  params: options.params,
135
186
  routePattern: options.routePattern,
136
187
  safeJsonStringify: options.safeJsonStringify,
@@ -157,7 +208,7 @@ async function renderPagesPageResponse(options) {
157
208
  controller.close();
158
209
  } });
159
210
  else {
160
- const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(options.pageProps)), options.scriptNonce);
211
+ const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(renderProps)), options.scriptNonce);
161
212
  bodyStream = await options.renderToReadableStream(pageElement);
162
213
  }
163
214
  if (documentRenderPage.status === "skipped") await callDocumentGetInitialProps(options.DocumentComponent, options.setDocumentInitialHead);
@@ -201,21 +252,34 @@ async function renderPagesPageResponse(options) {
201
252
  }
202
253
  const compositeStream = await buildPagesCompositeStream(responseBodyStream, shellPrefix, shellSuffix);
203
254
  const userSetCacheControl = responseHeaders.has("Cache-Control");
204
- if (options.scriptNonce) responseHeaders.set("Cache-Control", "no-store, must-revalidate");
255
+ if (options.scriptNonce) responseHeaders.set("Cache-Control", NO_STORE_CACHE_CONTROL);
205
256
  else if (options.isrRevalidateSeconds) {
206
257
  const isrPathname = options.routeUrl.split("?")[0];
207
258
  const stem = isrPathname.endsWith("/") ? isrPathname.slice(0, -1) : isrPathname;
208
259
  applyCdnResponseHeaders(responseHeaders, {
209
- cacheControl: buildRevalidateCacheControl(options.isrRevalidateSeconds, options.expireSeconds),
260
+ cacheControl: buildMissIsrCacheControl(options.isrRevalidateSeconds, options.expireSeconds),
210
261
  tags: [encodeCacheTag(`_N_T_${stem || "/"}`)]
211
262
  });
212
263
  setCacheStateHeaders(responseHeaders, "MISS");
213
- } else if (options.gsspRes && !userSetCacheControl) responseHeaders.set("Cache-Control", "private, no-cache, no-store, max-age=0, must-revalidate");
264
+ } else if (options.gsspRes && !userSetCacheControl) responseHeaders.set("Cache-Control", NEVER_CACHE_CONTROL);
214
265
  if (options.fontLinkHeader) responseHeaders.set("Link", options.fontLinkHeader);
266
+ if (options.userAgent && isPagesStreamingBot(options.userAgent)) {
267
+ const fullHtml = await readStreamAsText(compositeStream);
268
+ const etag = generatePagesETag(fullHtml);
269
+ responseHeaders.set("ETag", etag);
270
+ if (!requestsNoCache(options.requestCacheControl) && options.ifNoneMatch && etagMatches(etag, options.ifNoneMatch)) return new Response(null, {
271
+ status: 304,
272
+ headers: responseHeaders
273
+ });
274
+ return new Response(fullHtml, {
275
+ status: finalStatus,
276
+ headers: responseHeaders
277
+ });
278
+ }
215
279
  return Object.assign(new Response(compositeStream, {
216
280
  status: finalStatus,
217
281
  headers: responseHeaders
218
282
  }), { __vinextStreamedHtmlResponse: true });
219
283
  }
220
284
  //#endregion
221
- export { buildPagesNextDataScript, renderPagesPageResponse };
285
+ export { buildPagesNextDataScript, etagMatches, generatePagesETag, isPagesStreamingBot, renderPagesPageResponse, requestsNoCache };
@@ -33,4 +33,4 @@ declare function buildPagesReadinessNextData(options: {
33
33
  hasRewrites: boolean;
34
34
  }): PagesReadinessNextData;
35
35
  //#endregion
36
- export { PagesReadinessNextData, buildPagesReadinessNextData };
36
+ export { buildPagesReadinessNextData };
@@ -5,6 +5,7 @@ import { HeaderRecord } from "./request-pipeline.js";
5
5
  type PagesRenderOptions = {
6
6
  isDataReq?: boolean;
7
7
  renderErrorPageOnMiss?: boolean;
8
+ originalUrl?: string;
8
9
  };
9
10
  type MiddlewareResult = {
10
11
  continue: boolean;
@@ -62,6 +63,20 @@ type PagesPipelineDeps = {
62
63
  */
63
64
  serveStaticFile?: ((requestPathname: string, stagedHeaders: HeaderRecord) => Promise<boolean>) | null;
64
65
  };
66
+ /**
67
+ * Wrap an adapter's `runMiddleware` callback so middleware receives the original
68
+ * (pre-basePath-stripping) URL. Adapters strip the basePath before handing the
69
+ * request to `runPagesRequest`, but Next.js passes the un-stripped URL to the
70
+ * middleware adapter so `request.nextUrl.basePath` reflects whether the URL
71
+ * actually had the basePath prefix. Requests outside the basePath
72
+ * (`hadBasePath === false`) are passed through untouched so middleware sees
73
+ * `nextUrl.basePath === ""` and can redirect them into the basePath
74
+ * (see the middleware-base-path e2e test / #1830).
75
+ *
76
+ * Shared by the Node prod server (prod-server.ts) and the generated Pages
77
+ * Router worker entry (deploy.ts) to keep the two adapters in sync.
78
+ */
79
+ declare function wrapMiddlewareWithBasePath(runMiddleware: NonNullable<PagesPipelineDeps["runMiddleware"]>, basePath: string, hadBasePath: boolean): NonNullable<PagesPipelineDeps["runMiddleware"]>;
65
80
  type PagesPipelineResult = {
66
81
  type: "response";
67
82
  response: Response;
@@ -96,4 +111,4 @@ type PagesPipelineResult = {
96
111
  */
97
112
  declare function runPagesRequest(request: Request, deps: PagesPipelineDeps): Promise<PagesPipelineResult>;
98
113
  //#endregion
99
- export { MiddlewareResult, PagesPipelineDeps, PagesPipelineResult, PagesRenderOptions, runPagesRequest };
114
+ export { MiddlewareResult, PagesPipelineDeps, PagesPipelineResult, PagesRenderOptions, runPagesRequest, wrapMiddlewareWithBasePath };