vinext 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/README.md +22 -10
  2. package/dist/build/client-build-config.d.ts +10 -0
  3. package/dist/build/client-build-config.js +18 -2
  4. package/dist/build/output-root-externals.d.ts +21 -0
  5. package/dist/build/output-root-externals.js +40 -0
  6. package/dist/build/pages-client-assets-module.d.ts +8 -0
  7. package/dist/build/pages-client-assets-module.js +21 -1
  8. package/dist/build/prerender-paths.js +6 -4
  9. package/dist/build/prerender.js +1 -1
  10. package/dist/build/run-prerender.js +1 -1
  11. package/dist/build/ssr-manifest.d.ts +2 -0
  12. package/dist/build/ssr-manifest.js +6 -2
  13. package/dist/check.js +12 -12
  14. package/dist/cli-dev-config.js +3 -3
  15. package/dist/cli.js +3 -2
  16. package/dist/client/client-redirect-matcher.d.ts +14 -0
  17. package/dist/client/client-redirect-matcher.js +37 -0
  18. package/dist/client/client-redirects.d.ts +27 -0
  19. package/dist/client/client-redirects.js +28 -0
  20. package/dist/client/client-rewrites.d.ts +2 -1
  21. package/dist/client/client-rewrites.js +1 -1
  22. package/dist/config/config-matchers.d.ts +26 -11
  23. package/dist/config/config-matchers.js +90 -88
  24. package/dist/config/destination-params.d.ts +47 -0
  25. package/dist/config/destination-params.js +116 -0
  26. package/dist/config/next-config.d.ts +7 -0
  27. package/dist/config/next-config.js +3 -0
  28. package/dist/entries/app-rsc-entry.d.ts +4 -0
  29. package/dist/entries/app-rsc-entry.js +20 -6
  30. package/dist/entries/pages-client-entry.js +3 -1
  31. package/dist/entries/pages-server-entry.js +13 -37
  32. package/dist/index.d.ts +3 -1
  33. package/dist/index.js +246 -136
  34. package/dist/init-cloudflare.d.ts +9 -0
  35. package/dist/init-cloudflare.js +107 -31
  36. package/dist/init-platform.d.ts +4 -0
  37. package/dist/init-platform.js +27 -2
  38. package/dist/init.d.ts +2 -1
  39. package/dist/init.js +153 -9
  40. package/dist/plugins/ast-scope.d.ts +7 -0
  41. package/dist/plugins/ast-scope.js +59 -3
  42. package/dist/plugins/ast-utils.d.ts +53 -2
  43. package/dist/plugins/ast-utils.js +90 -2
  44. package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
  45. package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
  46. package/dist/plugins/commonjs-esm-facade.js +2 -2
  47. package/dist/plugins/css-module-imports.js +13 -20
  48. package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
  49. package/dist/plugins/dynamic-preload-metadata.js +11 -11
  50. package/dist/plugins/extensionless-dynamic-import.js +2 -3
  51. package/dist/plugins/fonts.d.ts +1 -1
  52. package/dist/plugins/fonts.js +3 -3
  53. package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
  54. package/dist/plugins/ignore-dynamic-requests.js +5 -7
  55. package/dist/plugins/import-meta-url.js +3 -4
  56. package/dist/plugins/instrumentation-client.js +3 -2
  57. package/dist/plugins/middleware-export-validation.js +2 -3
  58. package/dist/plugins/middleware-server-only.d.ts +5 -4
  59. package/dist/plugins/middleware-server-only.js +8 -5
  60. package/dist/plugins/og-harfbuzz.js +2 -3
  61. package/dist/plugins/optimize-imports.js +3 -4
  62. package/dist/plugins/pages-node-externals.js +3 -4
  63. package/dist/plugins/remove-console.js +2 -18
  64. package/dist/plugins/require-condition-resolution.js +3 -3
  65. package/dist/plugins/require-context.js +2 -3
  66. package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
  67. package/dist/plugins/rsc-scan-glob-imports.js +50 -0
  68. package/dist/plugins/strip-server-exports.js +265 -102
  69. package/dist/plugins/styled-jsx.js +2 -3
  70. package/dist/plugins/transform-result.d.ts +9 -5
  71. package/dist/plugins/transitive-externals.js +1 -1
  72. package/dist/plugins/typeof-window.d.ts +2 -2
  73. package/dist/plugins/use-cache-callable.d.ts +21 -2
  74. package/dist/plugins/use-cache-callable.js +84 -35
  75. package/dist/plugins/worker-image-imports.js +30 -33
  76. package/dist/plugins/worker-server-only-imports.d.ts +20 -0
  77. package/dist/plugins/worker-server-only-imports.js +31 -0
  78. package/dist/plugins/worker-use-server.d.ts +25 -0
  79. package/dist/plugins/worker-use-server.js +153 -0
  80. package/dist/server/api-handler.d.ts +1 -0
  81. package/dist/server/api-handler.js +3 -2
  82. package/dist/server/app-action-forwarding.js +2 -2
  83. package/dist/server/app-browser-action-result.d.ts +1 -1
  84. package/dist/server/app-browser-action-result.js +9 -2
  85. package/dist/server/app-browser-entry.js +3 -3
  86. package/dist/server/app-browser-interception-context.js +1 -1
  87. package/dist/server/app-browser-navigation-controller.js +1 -1
  88. package/dist/server/app-browser-prefetch-response.js +2 -2
  89. package/dist/server/app-browser-server-action-client.js +1 -1
  90. package/dist/server/app-browser-state.js +1 -1
  91. package/dist/server/app-browser-supplemental-refresh.js +1 -1
  92. package/dist/server/app-middleware.d.ts +11 -0
  93. package/dist/server/app-middleware.js +17 -2
  94. package/dist/server/app-optimistic-routing.js +1 -1
  95. package/dist/server/app-page-cache.d.ts +1 -1
  96. package/dist/server/app-page-cache.js +1 -1
  97. package/dist/server/app-page-dispatch.d.ts +3 -1
  98. package/dist/server/app-page-dispatch.js +5 -4
  99. package/dist/server/app-page-ppr-runtime.js +1 -1
  100. package/dist/server/app-page-render-observation.js +1 -1
  101. package/dist/server/app-page-render.js +1 -1
  102. package/dist/server/app-page-request.js +53 -15
  103. package/dist/server/app-page-route-wiring.js +2 -2
  104. package/dist/server/app-pages-bridge.d.ts +1 -1
  105. package/dist/server/app-pages-bridge.js +3 -4
  106. package/dist/server/app-prerender-endpoints.js +9 -6
  107. package/dist/server/app-render-abort-error.d.ts +19 -0
  108. package/dist/server/app-render-abort-error.js +31 -1
  109. package/dist/server/app-request-stage-dispatch.js +6 -2
  110. package/dist/server/app-request-stage-independent-entry.js +29 -9
  111. package/dist/server/app-response-stage-entry.js +11 -3
  112. package/dist/server/app-route-handler-cache.d.ts +1 -0
  113. package/dist/server/app-route-handler-cache.js +1 -0
  114. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  115. package/dist/server/app-route-handler-dispatch.js +5 -2
  116. package/dist/server/app-route-handler-execution.d.ts +1 -0
  117. package/dist/server/app-route-handler-execution.js +1 -0
  118. package/dist/server/app-route-handler-runtime.d.ts +4 -1
  119. package/dist/server/app-route-handler-runtime.js +46 -25
  120. package/dist/server/app-router-entry.js +29 -10
  121. package/dist/server/app-rsc-cache-busting.d.ts +16 -0
  122. package/dist/server/app-rsc-cache-busting.js +30 -13
  123. package/dist/server/app-rsc-errors.js +20 -16
  124. package/dist/server/app-rsc-handler.d.ts +7 -0
  125. package/dist/server/app-rsc-handler.js +89 -39
  126. package/dist/server/app-rsc-request-normalization.js +3 -3
  127. package/dist/server/app-rsc-response-stage.js +5 -3
  128. package/dist/server/app-segment-config.d.ts +2 -1
  129. package/dist/server/app-server-action-execution.d.ts +2 -1
  130. package/dist/server/app-server-action-execution.js +62 -23
  131. package/dist/server/app-ssr-entry.js +7 -5
  132. package/dist/server/app-visited-response-cache.js +2 -2
  133. package/dist/server/app-worker-stages.d.ts +5 -0
  134. package/dist/server/app-worker-stages.js +1 -1
  135. package/dist/server/cacheability-request.js +2 -2
  136. package/dist/server/client-build-files.d.ts +16 -0
  137. package/dist/server/client-build-files.js +36 -0
  138. package/dist/server/client-reuse-manifest.js +1 -1
  139. package/dist/server/config-headers.js +1 -1
  140. package/dist/server/defer-until-stream-consumed.d.ts +2 -1
  141. package/dist/server/defer-until-stream-consumed.js +3 -1
  142. package/dist/server/dev-server.js +39 -28
  143. package/dist/server/dev-stack-sourcemap.js +18 -23
  144. package/dist/server/document-initial-head.d.ts +0 -11
  145. package/dist/server/document-initial-head.js +1 -1
  146. package/dist/server/forwarded-middleware-context.d.ts +5 -0
  147. package/dist/server/forwarded-middleware-context.js +22 -0
  148. package/dist/server/headers.d.ts +4 -1
  149. package/dist/server/headers.js +4 -1
  150. package/dist/server/http-conditional.d.ts +11 -0
  151. package/dist/server/http-conditional.js +10 -1
  152. package/dist/server/http-error-responses.d.ts +1 -1
  153. package/dist/server/image-optimization.d.ts +38 -0
  154. package/dist/server/image-optimization.js +94 -4
  155. package/dist/server/isr-cache.d.ts +10 -0
  156. package/dist/server/isr-cache.js +41 -6
  157. package/dist/server/metadata-route-response.js +11 -10
  158. package/dist/server/middleware-matcher.d.ts +2 -0
  159. package/dist/server/middleware-matcher.js +23 -2
  160. package/dist/server/middleware-path-to-regexp.js +1 -1
  161. package/dist/server/middleware-runtime.d.ts +13 -0
  162. package/dist/server/middleware-runtime.js +38 -25
  163. package/dist/server/middleware.d.ts +1 -1
  164. package/dist/server/middleware.js +3 -1
  165. package/dist/server/multi-stage.d.ts +11 -0
  166. package/dist/server/navigation-planner.js +1 -1
  167. package/dist/server/normalize-path.d.ts +0 -13
  168. package/dist/server/normalize-path.js +1 -34
  169. package/dist/server/open-redirect.d.ts +11 -4
  170. package/dist/server/open-redirect.js +11 -4
  171. package/dist/server/pages-api-route.d.ts +3 -2
  172. package/dist/server/pages-api-route.js +6 -5
  173. package/dist/server/pages-cache-tag.d.ts +12 -0
  174. package/dist/server/pages-cache-tag.js +19 -0
  175. package/dist/server/pages-client-assets.d.ts +2 -0
  176. package/dist/server/pages-data-route.d.ts +10 -0
  177. package/dist/server/pages-data-route.js +21 -3
  178. package/dist/server/pages-document-asset-props.d.ts +5 -1
  179. package/dist/server/pages-document-asset-props.js +13 -5
  180. package/dist/server/pages-document-splice.d.ts +19 -0
  181. package/dist/server/pages-document-splice.js +55 -0
  182. package/dist/server/pages-i18n.d.ts +12 -1
  183. package/dist/server/pages-i18n.js +18 -4
  184. package/dist/server/pages-node-compat.d.ts +16 -5
  185. package/dist/server/pages-node-compat.js +20 -12
  186. package/dist/server/pages-page-data.d.ts +32 -24
  187. package/dist/server/pages-page-data.js +51 -121
  188. package/dist/server/pages-page-handler.d.ts +0 -6
  189. package/dist/server/pages-page-handler.js +189 -127
  190. package/dist/server/pages-page-response.d.ts +12 -6
  191. package/dist/server/pages-page-response.js +42 -35
  192. package/dist/server/pages-request-pipeline.d.ts +10 -2
  193. package/dist/server/pages-request-pipeline.js +41 -22
  194. package/dist/server/pages-request-stage-entry.d.ts +6 -0
  195. package/dist/server/pages-request-stage-entry.js +75 -16
  196. package/dist/server/pages-response-stage-entry.js +4 -0
  197. package/dist/server/pages-revalidate.js +3 -3
  198. package/dist/server/pages-router-entry.js +5 -4
  199. package/dist/server/prerender-manifest.d.ts +3 -3
  200. package/dist/server/prerender-manifest.js +4 -3
  201. package/dist/server/prerender-work-unit-setup.js +4 -0
  202. package/dist/server/prod-server.d.ts +12 -0
  203. package/dist/server/prod-server.js +204 -74
  204. package/dist/server/proper-error.d.ts +4 -0
  205. package/dist/server/proper-error.js +31 -0
  206. package/dist/server/request-pipeline.d.ts +4 -1
  207. package/dist/server/request-pipeline.js +3 -2
  208. package/dist/server/revalidation-request.d.ts +1 -0
  209. package/dist/server/revalidation-request.js +1 -1
  210. package/dist/server/rsc-stream-hints.d.ts +1 -1
  211. package/dist/server/rsc-stream-hints.js +52 -5
  212. package/dist/server/seed-cache.d.ts +1 -0
  213. package/dist/server/seed-cache.js +5 -4
  214. package/dist/server/server-reference-loader.d.ts +4 -0
  215. package/dist/server/server-reference-loader.js +29 -0
  216. package/dist/server/socket-error-backstop.d.ts +9 -1
  217. package/dist/server/socket-error-backstop.js +46 -17
  218. package/dist/server/static-file-signal.d.ts +15 -4
  219. package/dist/server/static-file-signal.js +46 -12
  220. package/dist/server/worker-image-optimization.d.ts +34 -0
  221. package/dist/server/worker-image-optimization.js +99 -0
  222. package/dist/server/worker-stages.d.ts +1 -1
  223. package/dist/server/worker-stages.js +2 -2
  224. package/dist/server/worker-utils.d.ts +8 -3
  225. package/dist/server/worker-utils.js +12 -7
  226. package/dist/shims/app-router-scroll.js +4 -1
  227. package/dist/shims/app-router-tree-context.d.ts +5 -0
  228. package/dist/shims/app-router-tree-context.js +27 -0
  229. package/dist/shims/cache-callable-runtime.d.ts +4 -2
  230. package/dist/shims/cache-callable-runtime.js +21 -12
  231. package/dist/shims/cache-handler.js +1 -9
  232. package/dist/shims/cache-runtime.d.ts +6 -1
  233. package/dist/shims/cache-runtime.js +2 -1
  234. package/dist/shims/cache.d.ts +2 -2
  235. package/dist/shims/cache.js +40 -13
  236. package/dist/shims/cdn-cache.d.ts +8 -0
  237. package/dist/shims/cdn-cache.js +17 -1
  238. package/dist/shims/disable-smooth-scroll.d.ts +3 -0
  239. package/dist/shims/disable-smooth-scroll.js +36 -0
  240. package/dist/shims/document-placeholders.d.ts +19 -0
  241. package/dist/shims/document-placeholders.js +45 -0
  242. package/dist/shims/document.js +21 -5
  243. package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
  244. package/dist/shims/dynamic-preload-chunks.js +13 -9
  245. package/dist/shims/dynamic.d.ts +1 -1
  246. package/dist/shims/dynamic.js +60 -8
  247. package/dist/shims/fetch-cache-state.d.ts +66 -0
  248. package/dist/shims/fetch-cache-state.js +92 -0
  249. package/dist/shims/fetch-cache.d.ts +3 -67
  250. package/dist/shims/fetch-cache.js +160 -125
  251. package/dist/shims/head.d.ts +10 -6
  252. package/dist/shims/head.js +16 -14
  253. package/dist/shims/headers.js +2 -2
  254. package/dist/shims/image.js +2 -1
  255. package/dist/shims/internal/hybrid-client-route-owner-direct.js +1 -1
  256. package/dist/shims/internal/hybrid-client-route-owner.js +1 -0
  257. package/dist/shims/internal/work-store-scope.d.ts +5 -0
  258. package/dist/shims/internal/work-store-scope.js +24 -0
  259. package/dist/shims/link-prefetch.js +5 -4
  260. package/dist/shims/link.js +2 -2
  261. package/dist/shims/navigation.js +34 -9
  262. package/dist/shims/request-context.d.ts +2 -0
  263. package/dist/shims/request-state-types.d.ts +2 -1
  264. package/dist/shims/router.js +21 -32
  265. package/dist/shims/server.d.ts +27 -4
  266. package/dist/shims/server.js +65 -9
  267. package/dist/shims/unified-request-context.d.ts +1 -1
  268. package/dist/shims/url-utils.d.ts +9 -0
  269. package/dist/shims/url-utils.js +15 -4
  270. package/dist/utils/client-runtime-metadata.js +1 -1
  271. package/dist/utils/domain-locale.js +1 -1
  272. package/dist/utils/hash.d.ts +7 -0
  273. package/dist/utils/hash.js +11 -1
  274. package/dist/utils/package-name.d.ts +6 -0
  275. package/dist/utils/package-name.js +12 -1
  276. package/dist/utils/plugin-rsc-version.d.ts +6 -0
  277. package/dist/utils/plugin-rsc-version.js +41 -0
  278. package/dist/utils/prerender-output-paths.js +15 -4
  279. package/dist/utils/public-file-path.d.ts +10 -2
  280. package/dist/utils/public-file-path.js +13 -9
  281. package/dist/utils/public-routes.js +2 -2
  282. package/dist/utils/react-version.d.ts +10 -0
  283. package/dist/utils/react-version.js +39 -16
  284. package/package.json +11 -7
  285. package/dist/build/nitro-route-rules.d.ts +0 -47
  286. package/dist/build/nitro-route-rules.js +0 -79
  287. package/dist/plugins/cache-flight-codec.d.ts +0 -19
  288. package/dist/plugins/cache-flight-codec.js +0 -68
@@ -1,6 +1,6 @@
1
- import "./server-globals.js";
2
1
  import { notFoundResponse } from "./http-error-responses.js";
3
2
  import { isOpenRedirectShaped, repeatedSlashRedirectResponse } from "./open-redirect.js";
3
+ import "./server-globals.js";
4
4
  import { isPprFallbackShellAbortError } from "../shims/ppr-fallback-shell.js";
5
5
  import { onRenderDynamicLatched } from "../shims/internal/headers-state.js";
6
6
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
@@ -18,7 +18,7 @@ import DefaultGlobalError from "../shims/default-global-error.js";
18
18
  import { BfcacheIdentityMapContext, ElementsContext, Slot } from "../shims/slot.js";
19
19
  import { getNextErrorDigest } from "./next-error-digest.js";
20
20
  import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
21
- import { isAppRenderAbortError } from "./app-render-abort-error.js";
21
+ import { createRenderStreamCancellation, isAppRenderAbortError } from "./app-render-abort-error.js";
22
22
  import { RSC_FORM_STATE_GLOBAL } from "../client/browser-globals.js";
23
23
  import { createNavigationRuntimeRenderedSearchScript, createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, waitAtLeastOneReactRenderTask } from "./app-ssr-stream.js";
24
24
  import { createInitialBfcacheMaps } from "./app-bfcache-identity.js";
@@ -27,6 +27,7 @@ import { createClientPageSsrSearchParamsSource } from "./app-page-search-params-
27
27
  import { runWithRootParamsScope } from "../shims/root-params.js";
28
28
  import { runWithNavigationContext } from "../shims/navigation-state.js";
29
29
  import { startCandidateSearchParamsGate } from "./app-ssr-search-params-gate.js";
30
+ import { withAppRouterTree } from "../shims/app-router-tree-context.js";
30
31
  import { BeforeInteractiveContext } from "../shims/before-interactive-context.js";
31
32
  import { renderBeforeInteractiveInlineScripts } from "./before-interactive-head.js";
32
33
  import { createInitialDevServerErrorScript } from "./dev-initial-server-error.js";
@@ -246,10 +247,11 @@ async function handleSsr(rscStream, navContext, fontData, options) {
246
247
  beforeInteractiveInlineScripts.push(script);
247
248
  };
248
249
  const treeWithBeforeInteractive = createElement(BeforeInteractiveContext.Provider, { value: registerBeforeInteractiveInlineScript }, ssrTree);
249
- const ssrRoot = withScriptNonce(treeWithBeforeInteractive, options?.scriptNonce);
250
+ const ssrRoot = withScriptNonce(withAppRouterTree(treeWithBeforeInteractive), options?.scriptNonce);
250
251
  const bootstrapModuleUrl = extractBootstrapModuleUrl(await import.meta.viteRsc.loadBootstrapScriptContent("index"));
251
252
  const errorMetaRenderer = createSsrErrorMetaRenderer({ basePath: options?.basePath });
252
253
  const pprFallbackShellSignal = options?.pprFallbackShellSignal;
254
+ const htmlCancellation = createRenderStreamCancellation();
253
255
  let reactLinkHeader = "";
254
256
  const maxHeadersLength = options?.reactMaxHeadersLength ?? DEFAULT_REACT_MAX_HEADERS_LENGTH;
255
257
  const captureHeaders = maxHeadersLength > 0;
@@ -267,7 +269,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
267
269
  maxHeadersLength: captureHeaders ? maxHeadersLength : void 0,
268
270
  onError(error) {
269
271
  if (pprFallbackShellSignal && isPprFallbackShellAbortError(error)) return;
270
- if (isAppRenderAbortError(error)) return void 0;
272
+ if (isAppRenderAbortError(error) || htmlCancellation.isReason(error)) return;
271
273
  errorMetaRenderer.capture(error);
272
274
  const instrumentationDigest = options?.onSsrError?.(error);
273
275
  if (typeof instrumentationDigest === "string") return instrumentationDigest;
@@ -341,7 +343,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
341
343
  const getBeforeInteractiveHeadHTML = () => renderBeforeInteractiveInlineScripts(beforeInteractiveInlineScripts);
342
344
  if (shouldDelayInitialHtmlPull) await waitAtLeastOneReactRenderTask();
343
345
  return {
344
- htmlStream: deferUntilStreamConsumed(htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, getInsertedHTML, getBeforeInteractiveHeadHTML, inlineCssManifest, inlineCssFontStyles, inlineCssFontStyleFallbackHTML, options?.scriptNonce)), cleanup),
346
+ htmlStream: deferUntilStreamConsumed(htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, getInsertedHTML, getBeforeInteractiveHeadHTML, inlineCssManifest, inlineCssFontStyles, inlineCssFontStyleFallbackHTML, options?.scriptNonce)), cleanup, void 0, htmlCancellation.record),
345
347
  metadataReady: Promise.resolve(),
346
348
  renderComplete,
347
349
  capturedRscData: options?.capturedRscDataRef?.value ?? null,
@@ -1,6 +1,6 @@
1
1
  import { AppElementsWire } from "./app-elements-wire.js";
2
2
  import "./app-elements.js";
3
- import { stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
3
+ import { parseRscRequestPath, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
4
4
  import { resolveCachedRscResponseExpiresAt } from "../shims/navigation.js";
5
5
  //#region src/server/app-visited-response-cache.ts
6
6
  const VISITED_RESPONSE_CACHE_TTL = 3e5;
@@ -27,7 +27,7 @@ function isVisitedResponseCacheEntryFresh(entry, options) {
27
27
  }
28
28
  function normalizeVisitedResponseCacheLookupUrl(rscUrl) {
29
29
  try {
30
- const url = new URL(rscUrl, "http://vinext.local");
30
+ const url = parseRscRequestPath(rscUrl);
31
31
  stripRscCacheBustingSearchParam(url);
32
32
  return `${url.pathname}${url.search}`;
33
33
  } catch {
@@ -18,6 +18,11 @@ type AppWorkerResponseStageEnvelope = {
18
18
  };
19
19
  type AppFullRequestWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
20
20
  kind: "app-full-request";
21
+ /**
22
+ * The public request is HEAD. It is dispatched as GET so a transport that
23
+ * applies HEAD semantics cannot drop the static-file signal's body.
24
+ */
25
+ headRequest: boolean;
21
26
  prerenderDiscovery: boolean;
22
27
  staticFileSignalToken: string;
23
28
  trustedPrerenderState: TrustedPrerenderState | null;
@@ -81,7 +81,7 @@ function isAppWorkerResponseStageProps(value) {
81
81
  if (!value || typeof value !== "object") return false;
82
82
  const props = value;
83
83
  if (props.protocolVersion !== 11 || props.buildId !== null && typeof props.buildId !== "string" || !isResponseStageCacheability(props.cacheability) || props.draftModeCookie !== null && typeof props.draftModeCookie !== "string" || props.middlewareCookieOverlay !== null && typeof props.middlewareCookieOverlay !== "string" || !isCanonicalHttpOrigin(props.requestOrigin) || props.scriptNonce !== null && typeof props.scriptNonce !== "string") return false;
84
- if (props.kind === "app-full-request") return typeof props.prerenderDiscovery === "boolean" && typeof props.staticFileSignalToken === "string" && STATIC_FILE_SIGNAL_TOKEN_RE.test(props.staticFileSignalToken) && (props.trustedPrerenderState === null || isTrustedPrerenderState(props.trustedPrerenderState));
84
+ if (props.kind === "app-full-request") return typeof props.headRequest === "boolean" && typeof props.prerenderDiscovery === "boolean" && typeof props.staticFileSignalToken === "string" && STATIC_FILE_SIGNAL_TOKEN_RE.test(props.staticFileSignalToken) && (props.trustedPrerenderState === null || isTrustedPrerenderState(props.trustedPrerenderState));
85
85
  if (props.kind === "hybrid-pages") {
86
86
  const hybrid = props;
87
87
  const appRouteMatch = hybrid.appRouteMatch;
@@ -1,7 +1,7 @@
1
1
  import "../utils/protocol-headers.js";
2
2
  import { isVinextRscVaryField } from "./app-rsc-vary.js";
3
3
  import { VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
4
- import { isNonCacheableCacheControl } from "../shims/cdn-cache.js";
4
+ import { hasSharedCacheCredentials, isNonCacheableCacheControl } from "../shims/cdn-cache.js";
5
5
  import { CACHEABILITY_REQUEST_STATE, recordConfigCdnCachePolicyHeader } from "../shims/cacheability-classification.js";
6
6
  import { NO_STORE_CACHE_CONTROL, applyCdnResponseBuildIdentityHeaders, applyCdnResponseHeaders, hasExplicitNonCacheableResponsePolicy, isCdnResponsePolicyHeader, readCdnResponseCacheControl, readCdnResponsePolicyHeaderName } from "./cache-control.js";
7
7
  import { cacheabilityManifestPageState, cacheabilityManifestRouteState, cacheabilityRepresentationMatchesPageRoute, cacheabilityRequestIdentity, cacheabilityRoutePathname, findCacheabilityManifestRoute, parseCacheabilityManifest, resolveCacheabilityRepresentation } from "./cacheability-manifest.js";
@@ -70,7 +70,7 @@ function readBoundManifest(raw, buildId) {
70
70
  }
71
71
  function createWorkerCacheabilityAdmissionContext(base, request, rawManifest, buildId, requiresCompletedResponseAdmission = rawManifest != null, responseVary, resolvedRoutePathname, trustedRepresentation, options) {
72
72
  const identity = cacheabilityRequestIdentity(request, trustedRepresentation);
73
- const credentialedRequest = request.headers.has("authorization") || request.headers.has("cookie") || request.headers.has("proxy-authorization");
73
+ const credentialedRequest = hasSharedCacheCredentials(request.headers);
74
74
  const routePathname = identity ? cacheabilityRoutePathname(resolvedRoutePathname ?? new URL(request.url).pathname, identity.representation) : void 0;
75
75
  if (!rawManifest) {
76
76
  if (!requiresCompletedResponseAdmission) return base;
@@ -0,0 +1,16 @@
1
+ //#region src/server/client-build-files.d.ts
2
+ /**
3
+ * Return the URL pathname of the client build file a request pathname names,
4
+ * or null. Client build files are the files the client build emits outside
5
+ * `_next/static` (see `collectClientBuildFiles`). Workers Static Assets serves
6
+ * them before the Worker unless the Worker runs first, so servers handle them
7
+ * before middleware and routing.
8
+ *
9
+ * `pathname` is the raw request pathname. The list holds file names and
10
+ * `basePath` is the configured string, so each segment is decoded exactly once
11
+ * before matching; a segment that decodes to a `/` names no file. The result
12
+ * is the file's segment-encoded pathname below `basePath`, so a server that
13
+ * decodes it once gets the file name back.
14
+ */
15
+ export declare function resolveClientBuildFile(pathname: string, basePath: string, clientBuildFiles: ReadonlySet<string>): string | null;
16
+ //#endregion
@@ -0,0 +1,36 @@
1
+ //#region src/server/client-build-files.ts
2
+ /**
3
+ * Return the URL pathname of the client build file a request pathname names,
4
+ * or null. Client build files are the files the client build emits outside
5
+ * `_next/static` (see `collectClientBuildFiles`). Workers Static Assets serves
6
+ * them before the Worker unless the Worker runs first, so servers handle them
7
+ * before middleware and routing.
8
+ *
9
+ * `pathname` is the raw request pathname. The list holds file names and
10
+ * `basePath` is the configured string, so each segment is decoded exactly once
11
+ * before matching; a segment that decodes to a `/` names no file. The result
12
+ * is the file's segment-encoded pathname below `basePath`, so a server that
13
+ * decodes it once gets the file name back.
14
+ */
15
+ function resolveClientBuildFile(pathname, basePath, clientBuildFiles) {
16
+ if (clientBuildFiles.size === 0) return null;
17
+ let filePath = pathname;
18
+ if (filePath.includes("%")) {
19
+ let segments;
20
+ try {
21
+ segments = filePath.split("/").map(decodeURIComponent);
22
+ } catch {
23
+ return null;
24
+ }
25
+ if (segments.some((segment) => segment.includes("/"))) return null;
26
+ filePath = segments.join("/");
27
+ }
28
+ if (basePath) {
29
+ if (!filePath.startsWith(`${basePath}/`)) return null;
30
+ filePath = filePath.slice(basePath.length);
31
+ }
32
+ if (!clientBuildFiles.has(filePath)) return null;
33
+ return filePath.split("/").map(encodeURIComponent).join("/");
34
+ }
35
+ //#endregion
36
+ export { resolveClientBuildFile };
@@ -1,6 +1,6 @@
1
1
  import { isUnknownRecord } from "../utils/record.js";
2
- import { fnv1a64 } from "../utils/hash.js";
3
2
  import { parseAppElementsWireElementKey } from "./app-elements-wire-key.js";
3
+ import { fnv1a64 } from "../utils/hash.js";
4
4
  import { parseArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
5
5
  import { isNonNegativeSafeInteger } from "../utils/number.js";
6
6
  //#region src/server/client-reuse-manifest.ts
@@ -1,5 +1,5 @@
1
- import { matchHeaders } from "../config/config-matchers.js";
2
1
  import "./headers.js";
2
+ import { matchHeaders } from "../config/config-matchers.js";
3
3
  import { markRouteCacheabilityConfigCdnCachePolicy, markRouteCacheabilityDynamic, markRouteCacheabilityFinalResponseUncacheable } from "../shims/cacheability-classification.js";
4
4
  import { isCdnResponsePolicyHeader, isNonCacheableCdnResponsePolicy } from "./cache-control.js";
5
5
  import { mergeVaryHeader } from "./middleware-response-headers.js";
@@ -1,6 +1,7 @@
1
1
  //#region src/server/defer-until-stream-consumed.d.ts
2
2
  /**
3
3
  * Defers cleanup until the downstream consumer drains or cancels the stream.
4
+ * `onCancel` runs before the cancellation reaches the source stream.
4
5
  */
5
- export declare function deferUntilStreamConsumed(stream: ReadableStream<Uint8Array>, onFlush: () => void, onError?: (error: unknown) => void): ReadableStream<Uint8Array>;
6
+ export declare function deferUntilStreamConsumed(stream: ReadableStream<Uint8Array>, onFlush: () => void, onError?: (error: unknown) => void, onCancel?: (reason: unknown) => void): ReadableStream<Uint8Array>;
6
7
  //#endregion
@@ -1,8 +1,9 @@
1
1
  //#region src/server/defer-until-stream-consumed.ts
2
2
  /**
3
3
  * Defers cleanup until the downstream consumer drains or cancels the stream.
4
+ * `onCancel` runs before the cancellation reaches the source stream.
4
5
  */
5
- function deferUntilStreamConsumed(stream, onFlush, onError) {
6
+ function deferUntilStreamConsumed(stream, onFlush, onError, onCancel) {
6
7
  let called = false;
7
8
  const once = () => {
8
9
  if (!called) {
@@ -26,6 +27,7 @@ function deferUntilStreamConsumed(stream, onFlush, onError) {
26
27
  });
27
28
  },
28
29
  cancel(reason) {
30
+ onCancel?.(reason);
29
31
  once();
30
32
  return reader.cancel(reason);
31
33
  }
@@ -2,10 +2,10 @@ import { closeAfterResponse, createRequestContext, runWithRequestContext } from
2
2
  import { createValidFileMatcher, findFileWithExts } from "../routing/file-matcher.js";
3
3
  import { isBotUserAgent } from "../utils/html-limited-bots.js";
4
4
  import { PRERENDER_REVALIDATE_HEADER } from "../utils/protocol-headers.js";
5
+ import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
5
6
  import { sanitizeDestination } from "../config/config-matchers.js";
6
7
  import { patternToNextFormat } from "../routing/route-validation.js";
7
8
  import { matchRoute } from "../routing/pages-router.js";
8
- import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
9
9
  import { isDangerousScheme } from "../shims/url-safety.js";
10
10
  import { extractLocaleFromUrl as extractLocaleFromUrl$1, resolvePagesI18nRequest } from "./pages-i18n.js";
11
11
  import { importModule, reportRequestError } from "./instrumentation.js";
@@ -18,7 +18,9 @@ import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
18
18
  import "../shims/router-state.js";
19
19
  import { withScriptNonce } from "../shims/script-nonce-context.js";
20
20
  import { createInlineScriptTag, createNonceAttribute, safeJsonStringify } from "./html.js";
21
+ import { createDocumentPlaceholderToken, getDocumentHeadOpenMarker } from "../shims/document-placeholders.js";
21
22
  import { applyDocumentAssetProps, extractDocumentAssetProps, markDocumentAssetPropsProtectedTags, stripDocumentAssetPropsProtectionMarkers } from "./pages-document-asset-props.js";
23
+ import { spliceDocumentHeadClose, spliceDocumentHeadOpen, spliceDocumentScripts, splitDocumentAtMain } from "./pages-document-splice.js";
22
24
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
23
25
  import { getScriptNonceFromNodeHeaderSources } from "./csp.js";
24
26
  import { stripViteModuleQuery } from "../utils/path.js";
@@ -31,7 +33,7 @@ import { callDocumentGetInitialProps } from "./document-initial-head.js";
31
33
  import { hasPagesGetInitialProps, loadDevAppInitialProps, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
32
34
  import { isSerializableProps } from "./pages-serializable-props.js";
33
35
  import { traceFindPageComponents, tracePagesData, tracePagesDocument, tracePagesDocumentStream } from "./pages-execution-tracing.js";
34
- import { assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds } from "./pages-page-data.js";
36
+ import { assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds, resolvePagesStatusPageRenderPath } from "./pages-page-data.js";
35
37
  import { createPagesDevModuleUrl } from "./pages-dev-module-url.js";
36
38
  import { collectPagesDevInitialStylesheetHeadHTML } from "./pages-dev-stylesheets.js";
37
39
  import { createPagesDevHydrationScript } from "./pages-dev-hydration.js";
@@ -142,8 +144,6 @@ function writeGsspRedirect(res, redirect, isDataReq, props, options) {
142
144
  });
143
145
  res.end(location);
144
146
  }
145
- /** Body placeholder used to split the document shell for streaming. */
146
- const STREAM_BODY_MARKER = "<!--VINEXT_STREAM_BODY-->";
147
147
  function stripDevPagesNotFoundFramingHeaders(res) {
148
148
  res.removeHeader("Content-Length");
149
149
  res.removeHeader("Transfer-Encoding");
@@ -171,7 +171,7 @@ function toHtmlTransformPath(url) {
171
171
  * shell sooner).
172
172
  */
173
173
  async function streamPageToResponseImpl(routePattern, res, element, options) {
174
- const { url, server, fontHeadHTML, assetHeadHTML = "", scripts, DocumentComponent, statusCode, extraHeaders, getHeadHTML, getTailHeadHTML, enhancePageElement, scriptNonce, documentContext, setDocumentInitialHead, crossOrigin, bufferBodyBeforeHeaders = false, preserveExistingContentType = false, onDocumentBody } = options;
174
+ const { url, server, runner, fontHeadHTML, assetHeadHTML = "", scripts, DocumentComponent, statusCode, extraHeaders, getHeadHTML, getTailHeadHTML, enhancePageElement, scriptNonce, documentContext, setDocumentInitialHead, crossOrigin, bufferBodyBeforeHeaders = false, preserveExistingContentType = false, onDocumentBody } = options;
175
175
  const renderDocument = async () => {
176
176
  const documentRenderPage = await runDocumentRenderPage({
177
177
  DocumentComponent,
@@ -211,6 +211,8 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
211
211
  const ssrHeadMarkerId = randomUUID();
212
212
  const ssrHeadStartMarker = `<!--VINEXT_SSR_HEAD_START:${ssrHeadMarkerId}-->`;
213
213
  const ssrHeadEndMarker = `<!--VINEXT_SSR_HEAD_END:${ssrHeadMarkerId}-->`;
214
+ const streamBodyMarker = `<!--VINEXT_STREAM_BODY:${ssrHeadMarkerId}-->`;
215
+ const documentToken = createDocumentPlaceholderToken();
214
216
  let tailHeadHTML = getTailHeadHTML?.() ?? "";
215
217
  if (documentRenderPage.status === "rendered" && documentRenderPage.stylesHTML) {
216
218
  if (tailHeadHTML) tailHeadHTML += "\n ";
@@ -227,29 +229,29 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
227
229
  if (DocumentComponent) {
228
230
  const docProps = documentRenderPage.status === "skipped" ? await loadUserDocumentInitialProps(DocumentComponent) : documentRenderPage.docProps;
229
231
  const docElement = docProps ? React.createElement(DocumentComponent, docProps) : React.createElement(DocumentComponent);
230
- const renderedDocument = extractDocumentAssetProps(await renderToStringAsync(docElement));
232
+ const { withDocumentPlaceholders } = await runner.import("vinext/document-placeholders");
233
+ const renderedDocument = extractDocumentAssetProps(await renderToStringAsync(withDocumentPlaceholders(docElement, documentToken)), documentToken);
231
234
  documentAssetProps = renderedDocument.props;
232
235
  let docHtml = protectAssetTags(renderedDocument.html);
233
236
  const generatedScripts = applyGeneratedAssetProps(scripts, renderedDocument.props, "next-script");
234
237
  const generatedAssetHeadHTML = applyGeneratedAssetProps(assetHeadHTML, renderedDocument.props, "next-script");
235
- docHtml = docHtml.replace("__NEXT_MAIN__", STREAM_BODY_MARKER);
236
- if (headHTML || fontHeadHTML || generatedAssetHeadHTML || tailHeadHTML) docHtml = docHtml.replace("</head>", `${ssrHeadStartMarker}${protectAssetTags(headHTML)}${ssrHeadEndMarker} ${protectAssetTags(fontHeadHTML)}\n ${generatedAssetHeadHTML}\n ${protectAssetTags(tailHeadHTML)}\n</head>`);
237
- docHtml = docHtml.replace("<!-- __NEXT_SCRIPTS__ -->", generatedScripts);
238
- if (!docHtml.includes("__NEXT_DATA__")) docHtml = docHtml.replace("</body>", ` ${generatedScripts}\n</body>`);
239
- shellTemplate = docHtml;
238
+ docHtml = spliceDocumentHeadClose(docHtml, documentToken, headHTML || fontHeadHTML || generatedAssetHeadHTML || tailHeadHTML ? `${ssrHeadStartMarker}${protectAssetTags(headHTML)}${ssrHeadEndMarker} ${protectAssetTags(fontHeadHTML)}\n ${generatedAssetHeadHTML}\n ${protectAssetTags(tailHeadHTML)}\n` : "");
239
+ docHtml = spliceDocumentScripts(docHtml, documentToken, generatedScripts);
240
+ const main = splitDocumentAtMain(docHtml, documentToken);
241
+ shellTemplate = main.prefix + streamBodyMarker + main.suffix;
240
242
  } else {
241
243
  const generatedScripts = applyGeneratedAssetProps(scripts, {}, "next-script");
242
244
  const generatedAssetHeadHTML = applyGeneratedAssetProps(assetHeadHTML, {}, "next-script");
243
245
  shellTemplate = `<!DOCTYPE html>
244
246
  <html>
245
- <head>
247
+ <head${getDocumentHeadOpenMarker(documentToken)}>
246
248
  ${ssrHeadStartMarker}${protectAssetTags(headHTML)}${ssrHeadEndMarker}
247
249
  ${protectAssetTags(fontHeadHTML)}
248
250
  ${generatedAssetHeadHTML}
249
251
  ${protectAssetTags(tailHeadHTML)}
250
252
  </head>
251
253
  <body>
252
- <div id="__next">${STREAM_BODY_MARKER}</div>
254
+ <div id="__next">${streamBodyMarker}</div>
253
255
  ${generatedScripts}
254
256
  </body>
255
257
  </html>`;
@@ -262,14 +264,17 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
262
264
  }), protectedAssetMarker);
263
265
  const ssrHeadStart = transformedShell.indexOf(ssrHeadStartMarker);
264
266
  const ssrHeadEnd = transformedShell.indexOf(ssrHeadEndMarker);
267
+ let transformedHeadHTML = "";
265
268
  if (ssrHeadStart !== -1 && ssrHeadEnd > ssrHeadStart) {
266
- const transformedHeadHTML = transformedShell.slice(ssrHeadStart + ssrHeadStartMarker.length, ssrHeadEnd);
267
- transformedShell = transformedShell.slice(0, ssrHeadStart) + transformedShell.slice(ssrHeadEnd + ssrHeadEndMarker.length);
268
- transformedShell = transformedShell.replace(/<head(?:\s[^>]*)?>/i, (openingHead) => `${openingHead}${transformedHeadHTML}`);
269
+ const ssrHeadHTML = transformedShell.slice(ssrHeadStart + ssrHeadStartMarker.length, ssrHeadEnd);
270
+ const moveToHeadOpen = transformedShell.includes(getDocumentHeadOpenMarker(documentToken));
271
+ if (moveToHeadOpen) transformedHeadHTML = ssrHeadHTML;
272
+ transformedShell = transformedShell.slice(0, ssrHeadStart) + (moveToHeadOpen ? "" : ssrHeadHTML) + transformedShell.slice(ssrHeadEnd + ssrHeadEndMarker.length);
269
273
  }
270
- const markerIdx = transformedShell.indexOf(STREAM_BODY_MARKER);
274
+ transformedShell = spliceDocumentHeadOpen(transformedShell, documentToken, transformedHeadHTML);
275
+ const markerIdx = transformedShell.indexOf(streamBodyMarker);
271
276
  const prefix = transformedShell.slice(0, markerIdx);
272
- const suffix = transformedShell.slice(markerIdx + 25);
277
+ const suffix = transformedShell.slice(markerIdx + streamBodyMarker.length);
273
278
  const bufferedBody = bufferBodyBeforeHeaders ? await new Response(bodyStream).text() : null;
274
279
  const headers = { "Transfer-Encoding": "chunked" };
275
280
  if (!preserveExistingContentType || !res.hasHeader("Content-Type")) headers["Content-Type"] = "text/html; charset=utf-8";
@@ -384,7 +389,9 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
384
389
  locale: locale ?? currentDefaultLocale,
385
390
  locales: i18nConfig?.locales,
386
391
  defaultLocale: currentDefaultLocale,
387
- crossOrigin
392
+ crossOrigin,
393
+ trailingSlash,
394
+ requestPathname: new URL(originalUrl, "http://vinext.local").pathname
388
395
  };
389
396
  const match = matchRoute(localeStrippedUrl, routes);
390
397
  if (!match) {
@@ -452,7 +459,8 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
452
459
  isStaticPropsRender = typeof pageModule.getStaticProps === "function" && typeof pageModule.getServerSideProps !== "function";
453
460
  if (isStaticPropsRender) {
454
461
  query = mergeRouteParamsIntoQuery({}, params);
455
- requestAsPath = localeStrippedUrl.split("?")[0];
462
+ const routePattern = patternToNextFormat(route.pattern);
463
+ requestAsPath = routePattern === "/404" || routePattern === "/500" ? resolvePagesStatusPageRenderPath(routePattern, trailingSlash, errorPageContext.requestPathname) : localeStrippedUrl.split("?")[0];
456
464
  }
457
465
  const requestPreview = typeof pageModule.getStaticProps === "function" || typeof pageModule.getServerSideProps === "function" ? getPagesPreviewState(req.headers.cookie, { isOnDemandRevalidate: isOnDemandRevalidateRequest(req.headers[PRERENDER_REVALIDATE_HEADER]) }) : {
458
466
  data: false,
@@ -864,6 +872,7 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
864
872
  await streamPageToResponse(route.pattern, res, withScriptNonce(element, scriptNonce), {
865
873
  url,
866
874
  server,
875
+ runner,
867
876
  fontHeadHTML,
868
877
  assetHeadHTML,
869
878
  scripts: allScripts,
@@ -963,10 +972,11 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
963
972
  if (!ErrorComponent) continue;
964
973
  const createElement = React.createElement;
965
974
  res.statusCode = statusCode;
975
+ const renderUrl = errorPage !== "/_error" && typeof errorModule.getStaticProps === "function" ? resolvePagesStatusPageRenderPath(errorPage, context.trailingSlash === true, context.requestPathname ?? url.split("?")[0]) : url;
966
976
  const errorRouter = {
967
977
  pathname: errorPage,
968
- query: parseQueryString(url),
969
- asPath: url
978
+ query: parseQueryString(renderUrl),
979
+ asPath: renderUrl
970
980
  };
971
981
  try {
972
982
  errorRouterShim = await importModule(runner, "next/router");
@@ -983,7 +993,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
983
993
  err,
984
994
  pathname: errorPage,
985
995
  query: errorRouter.query,
986
- asPath: url
996
+ asPath: renderUrl
987
997
  });
988
998
  if (res.headersSent || res.writableEnded) return;
989
999
  let errorProps = {
@@ -1004,7 +1014,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
1004
1014
  writeGsspRedirect(res, staticResult.redirect, false, { pageProps: errorProps }, {
1005
1015
  basePath: context.basePath,
1006
1016
  method: "getStaticProps",
1007
- routeUrl: url
1017
+ routeUrl: renderUrl
1008
1018
  });
1009
1019
  return;
1010
1020
  }
@@ -1035,7 +1045,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
1035
1045
  err,
1036
1046
  pathname: errorPage,
1037
1047
  query: errorRouter.query,
1038
- asPath: url
1048
+ asPath: renderUrl
1039
1049
  }
1040
1050
  });
1041
1051
  if (res.headersSent || res.writableEnded) return;
@@ -1068,7 +1078,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
1068
1078
  const errorScripts = `${`<script id="__NEXT_DATA__" type="application/json"${nonceAttr}>${safeJsonStringify({
1069
1079
  props: renderProps,
1070
1080
  page: errorPage,
1071
- query: parseQueryString(url),
1081
+ query: parseQueryString(renderUrl),
1072
1082
  buildId: context.buildId ?? process.env.__VINEXT_BUILD_ID ?? "development",
1073
1083
  isFallback: false,
1074
1084
  locale: context.locale,
@@ -1095,6 +1105,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
1095
1105
  if (DocumentComponent) await streamPageToResponse(errorPage, res, element, {
1096
1106
  url,
1097
1107
  server,
1108
+ runner,
1098
1109
  fontHeadHTML: "",
1099
1110
  assetHeadHTML,
1100
1111
  scripts: errorScripts,
@@ -1103,8 +1114,8 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
1103
1114
  documentContext: {
1104
1115
  err,
1105
1116
  pathname: errorPage,
1106
- query: parseQueryString(url),
1107
- asPath: url,
1117
+ query: parseQueryString(renderUrl),
1118
+ asPath: renderUrl,
1108
1119
  req,
1109
1120
  res
1110
1121
  },
@@ -1,7 +1,7 @@
1
- import { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
1
+ import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { VINEXT_ORIGINAL_STACK_TRACE_ENDPOINT } from "../utils/dev-stack-sourcemap-endpoint.js";
3
- import { readFile } from "node:fs/promises";
4
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { isFileLoadingAllowed } from "vite";
5
5
  //#region src/server/dev-stack-sourcemap.ts
6
6
  const MAX_ORIGINAL_STACK_TRACE_BODY_BYTES = 1048576;
7
7
  const V8_PAREN_STACK_LINE = /^(\s*at\s+.*?\()(.+):(\d+):(\d+)(\)\s*)$/;
@@ -162,7 +162,7 @@ async function mapGeneratedFrame(server, file, line, column, methodName, request
162
162
  const original = traceOriginalPositionFor(sourceMap, generatedLine, generatedColumn);
163
163
  if (!original) return null;
164
164
  const originalFile = resolveSourceFile(original.source, sourceMap, generatedFrame.sourceMapBaseUrl);
165
- const codeFrame = await createStackCodeFrame({
165
+ const codeFrame = createStackCodeFrame({
166
166
  file: originalFile,
167
167
  line: original.line,
168
168
  column: original.column,
@@ -224,11 +224,12 @@ function getLocalSourcePath(server, file) {
224
224
  }
225
225
  localPath = stripQuery(localPath);
226
226
  if (!isAbsolutePath(localPath)) return null;
227
+ localPath = path.resolve(localPath);
227
228
  const localPathForCompare = normalizeLocalPathForCompare(localPath);
228
229
  if (localPathForCompare.includes("/node_modules/")) return null;
229
230
  const root = server.config?.root;
230
231
  if (!root) return null;
231
- const rootForCompare = normalizeLocalPathForCompare(root);
232
+ const rootForCompare = normalizeLocalPathForCompare(path.resolve(root));
232
233
  return localPathForCompare === rootForCompare || localPathForCompare.startsWith(`${rootForCompare}/`) ? localPath : null;
233
234
  }
234
235
  function isAbsolutePath(value) {
@@ -242,18 +243,18 @@ function normalizeLocalPathForCompare(value) {
242
243
  return /^[A-Za-z]:\//.test(normalized) ? normalized.toLowerCase() : normalized;
243
244
  }
244
245
  function normalizeIgnoreListPath(value) {
245
- let path = devirtualizeReactServerFrame(value);
246
- if (path.startsWith("file://")) try {
247
- path = fileURLToPath(path);
246
+ let normalized = devirtualizeReactServerFrame(value);
247
+ if (normalized.startsWith("file://")) try {
248
+ normalized = fileURLToPath(normalized);
248
249
  } catch {}
249
250
  else try {
250
- const url = new URL(path);
251
- if (url.protocol === "http:" || url.protocol === "https:") path = `${url.pathname}${url.search}`;
251
+ const url = new URL(normalized);
252
+ if (url.protocol === "http:" || url.protocol === "https:") normalized = `${url.pathname}${url.search}`;
252
253
  } catch {}
253
254
  try {
254
- path = decodeURIComponent(path);
255
+ normalized = decodeURIComponent(normalized);
255
256
  } catch {}
256
- return toSlash(path).toLowerCase();
257
+ return toSlash(normalized).toLowerCase();
257
258
  }
258
259
  function isExternalHttpFrame(file, requestHost) {
259
260
  if (!/^https?:\/\//i.test(file) || !requestHost) return false;
@@ -274,10 +275,9 @@ function isIgnoreListedOriginalFrame(file) {
274
275
  function isSourceMapIgnored(sourceMap, sourceIndex) {
275
276
  return sourceMap.ignoreList?.includes(sourceIndex) ?? false;
276
277
  }
277
- async function createStackCodeFrame({ file, line, column, methodName, sourceContent }) {
278
- const source = sourceContent ?? await readSourceFileForCodeFrame(file);
279
- if (!source) return null;
280
- const sourceLines = source.split(/\r\n|\r|\n/);
278
+ function createStackCodeFrame({ file, line, column, methodName, sourceContent }) {
279
+ if (!sourceContent) return null;
280
+ const sourceLines = sourceContent.split(/\r\n|\r|\n/);
281
281
  if (line < 1 || line > sourceLines.length) return null;
282
282
  const start = Math.max(1, line - 2);
283
283
  const end = Math.min(sourceLines.length, line + 3);
@@ -295,14 +295,6 @@ async function createStackCodeFrame({ file, line, column, methodName, sourceCont
295
295
  lines
296
296
  };
297
297
  }
298
- async function readSourceFileForCodeFrame(file) {
299
- if (!file.startsWith("file://")) return null;
300
- try {
301
- return await readFile(fileURLToPath(file), "utf8");
302
- } catch {
303
- return null;
304
- }
305
- }
306
298
  function getMappableClientGeneratedUrl(file, requestHost) {
307
299
  const isAbsoluteHttpUrl = /^https?:\/\//i.test(file);
308
300
  let url;
@@ -335,6 +327,9 @@ async function loadServerSourceMapForLocalPath(server, localPath) {
335
327
  const environment = server.environments[environmentName];
336
328
  if (!environment) continue;
337
329
  try {
330
+ const resolved = await environment.pluginContainer.resolveId(localPath);
331
+ if (!resolved || resolved.external || resolved.id.startsWith("\0")) continue;
332
+ if (!isFileLoadingAllowed(server.config, stripQuery(resolved.id))) continue;
338
333
  const sourceMap = normalizeSourceMapPayload((await environment.transformRequest(localPath))?.map);
339
334
  if (sourceMap) return sourceMap;
340
335
  } catch {}
@@ -1,15 +1,4 @@
1
1
  import React from "react";
2
2
  //#region src/server/document-initial-head.d.ts
3
- /**
4
- * True when `_document` supplies its own `getInitialProps`, rather than
5
- * exposing none or inheriting the shim's default. Comparing against the
6
- * captured `DEFAULT_GET_INITIAL_PROPS` reference is what distinguishes a user
7
- * override from the default — extending the shim's `Document` without
8
- * overriding inherits the same static function.
9
- *
10
- * Callers use this to decide whether the render pipeline owes `_document` the
11
- * full `getInitialProps` contract, since only an override can observe it.
12
- */
13
- export declare function hasUserDocumentGetInitialProps(DocumentComponent: React.ComponentType | null | undefined): boolean;
14
3
  export declare function callDocumentGetInitialProps(DocumentComponent: React.ComponentType | null | undefined, setDocumentInitialHead: ((head: React.ReactNode[]) => void) | undefined): Promise<void>;
15
4
  //#endregion
@@ -45,4 +45,4 @@ async function callDocumentGetInitialProps(DocumentComponent, setDocumentInitial
45
45
  }
46
46
  }
47
47
  //#endregion
48
- export { callDocumentGetInitialProps, hasUserDocumentGetInitialProps };
48
+ export { callDocumentGetInitialProps };
@@ -0,0 +1,5 @@
1
+ //#region src/server/forwarded-middleware-context.d.ts
2
+ export declare function sealForwardedMiddlewareContext(key: string, context: string): string;
3
+ /** Returns the forwarded context JSON, or null unless it carries `key`. */
4
+ export declare function openForwardedMiddlewareContext(value: string | null, key: string | null | undefined): string | null;
5
+ //#endregion
@@ -0,0 +1,22 @@
1
+ import { safeEqual } from "./revalidation-request.js";
2
+ //#region src/server/forwarded-middleware-context.ts
3
+ /**
4
+ * Hybrid app+pages dev runs middleware once in the Pages connect handler and
5
+ * forwards the result to the App Router in x-vinext-mw-ctx. The value is
6
+ * prefixed with a per-dev-server key that only vinext's generated RSC entry
7
+ * knows, so a client-supplied copy can never stand in for running middleware,
8
+ * whichever plugin builds the App Router request first.
9
+ */
10
+ const KEY_SEPARATOR = ".";
11
+ function sealForwardedMiddlewareContext(key, context) {
12
+ return key + KEY_SEPARATOR + context;
13
+ }
14
+ /** Returns the forwarded context JSON, or null unless it carries `key`. */
15
+ function openForwardedMiddlewareContext(value, key) {
16
+ if (value === null || !key) return null;
17
+ const separatorIndex = value.indexOf(KEY_SEPARATOR);
18
+ if (separatorIndex === -1 || !safeEqual(value.slice(0, separatorIndex), key)) return null;
19
+ return value.slice(separatorIndex + 1);
20
+ }
21
+ //#endregion
22
+ export { openForwardedMiddlewareContext, sealForwardedMiddlewareContext };
@@ -48,7 +48,10 @@ export declare const VINEXT_PRERENDER_READINESS_PATH = "/__vinext/prerender/read
48
48
  export declare const VINEXT_PRERENDER_READINESS_HEADER = "X-Vinext-Prerender-Readiness";
49
49
  /** TPR (Tailored Per-Request) revalidation interval in seconds. */
50
50
  export declare const VINEXT_REVALIDATE_HEADER = "x-vinext-revalidate";
51
- /** Actual Pages cache tag regenerated by an authenticated on-demand request. */
51
+ /**
52
+ * Actual Pages cache tag regenerated by an authenticated on-demand request.
53
+ * URI-encoded, because a decoded path can end in whitespace that Headers trims.
54
+ */
52
55
  export declare const VINEXT_REVALIDATED_CACHE_TAG_HEADER = "x-vinext-revalidated-cache-tag";
53
56
  /** Marker on cached ISR entries indicating RSC payload (value "1"). */
54
57
  export declare const VINEXT_RSC_MARKER_HEADER = "x-vinext-rsc";
@@ -48,7 +48,10 @@ const VINEXT_PRERENDER_READINESS_PATH = "/__vinext/prerender/readiness";
48
48
  const VINEXT_PRERENDER_READINESS_HEADER = "X-Vinext-Prerender-Readiness";
49
49
  /** TPR (Tailored Per-Request) revalidation interval in seconds. */
50
50
  const VINEXT_REVALIDATE_HEADER = "x-vinext-revalidate";
51
- /** Actual Pages cache tag regenerated by an authenticated on-demand request. */
51
+ /**
52
+ * Actual Pages cache tag regenerated by an authenticated on-demand request.
53
+ * URI-encoded, because a decoded path can end in whitespace that Headers trims.
54
+ */
52
55
  const VINEXT_REVALIDATED_CACHE_TAG_HEADER = "x-vinext-revalidated-cache-tag";
53
56
  /** Marker on cached ISR entries indicating RSC payload (value "1"). */
54
57
  const VINEXT_RSC_MARKER_HEADER = "x-vinext-rsc";
@@ -6,6 +6,17 @@
6
6
  * validator with the same opaque tag compare equal.
7
7
  */
8
8
  export declare function matchesIfNoneMatch(ifNoneMatch: string | undefined, etag: string): boolean;
9
+ /**
10
+ * Whether a page answers its request with a 304, as Next.js's
11
+ * `sendEtagResponse` does with `fresh(req.headers, { etag })`. Next.js gives a
12
+ * page no Last-Modified, so a request with If-Modified-Since gets the page, and
13
+ * a request `Cache-Control: no-cache` always does.
14
+ */
15
+ export declare function isPageNotModified(request: {
16
+ cacheControl?: string;
17
+ ifModifiedSince?: string;
18
+ ifNoneMatch?: string;
19
+ }, etag: string): boolean;
9
20
  /** Test an If-Match field using Next.js's weak/strong-equivalent comparison. */
10
21
  export declare function matchesIfMatch(ifMatch: string | undefined, etag: string | undefined): boolean;
11
22
  type StaticConditionalHeaders = {