vinext 1.4.2 → 1.4.4

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 (116) hide show
  1. package/README.md +4 -1
  2. package/dist/build/prerender-paths.d.ts +11 -1
  3. package/dist/build/prerender-paths.js +41 -11
  4. package/dist/cli.js +1 -1
  5. package/dist/client/dev-error-overlay.d.ts +2 -1
  6. package/dist/client/dev-error-overlay.js +8 -3
  7. package/dist/config/config-matchers.js +6 -2
  8. package/dist/config/next-config.d.ts +9 -0
  9. package/dist/entries/app-rsc-entry.js +24 -12
  10. package/dist/entries/pages-server-entry.js +17 -4
  11. package/dist/index.js +48 -39
  12. package/dist/init-platform.js +2 -2
  13. package/dist/init.js +42 -5
  14. package/dist/server/api-handler.js +8 -5
  15. package/dist/server/app-browser-entry.js +26 -47
  16. package/dist/server/app-browser-error.d.ts +1 -1
  17. package/dist/server/app-browser-error.js +13 -4
  18. package/dist/server/app-browser-navigation-controller.js +2 -2
  19. package/dist/server/app-browser-server-action-client.js +2 -2
  20. package/dist/server/app-browser-state.js +2 -2
  21. package/dist/server/app-browser-supplemental-refresh.d.ts +13 -0
  22. package/dist/server/app-browser-supplemental-refresh.js +36 -4
  23. package/dist/server/app-browser-visible-commit.js +1 -1
  24. package/dist/server/app-history-state.js +1 -1
  25. package/dist/server/app-middleware.d.ts +2 -0
  26. package/dist/server/app-middleware.js +1 -0
  27. package/dist/server/app-page-boundary-render.js +4 -2
  28. package/dist/server/app-page-dispatch.d.ts +1 -0
  29. package/dist/server/app-page-dispatch.js +5 -1
  30. package/dist/server/app-page-element-builder.d.ts +2 -0
  31. package/dist/server/app-page-element-builder.js +6 -5
  32. package/dist/server/app-page-render.js +1 -1
  33. package/dist/server/app-page-route-wiring.d.ts +7 -5
  34. package/dist/server/app-page-route-wiring.js +11 -9
  35. package/dist/server/app-pages-bridge.d.ts +6 -0
  36. package/dist/server/app-pages-bridge.js +8 -3
  37. package/dist/server/app-request-context.js +1 -1
  38. package/dist/server/app-request-stage-independent-entry.js +2 -3
  39. package/dist/server/app-route-handler-dispatch.js +1 -1
  40. package/dist/server/app-route-handler-execution.js +1 -1
  41. package/dist/server/app-route-handler-response.d.ts +1 -0
  42. package/dist/server/app-route-handler-response.js +27 -2
  43. package/dist/server/app-router-entry.js +2 -3
  44. package/dist/server/app-rsc-cache-busting.d.ts +8 -0
  45. package/dist/server/app-rsc-cache-busting.js +13 -1
  46. package/dist/server/app-rsc-combined-handler.js +2 -1
  47. package/dist/server/app-rsc-handler.d.ts +4 -0
  48. package/dist/server/app-rsc-handler.js +41 -24
  49. package/dist/server/app-rsc-response-finalizer.d.ts +15 -3
  50. package/dist/server/app-rsc-response-finalizer.js +51 -7
  51. package/dist/server/app-rsc-response-stage.js +1 -1
  52. package/dist/server/app-server-action-execution.js +1 -1
  53. package/dist/server/app-ssr-entry.js +18 -10
  54. package/dist/server/config-headers.d.ts +7 -0
  55. package/dist/server/config-headers.js +20 -1
  56. package/dist/server/edge-api-runtime.d.ts +6 -2
  57. package/dist/server/edge-api-runtime.js +21 -4
  58. package/dist/server/image-animation.d.ts +9 -0
  59. package/dist/server/image-animation.js +118 -0
  60. package/dist/server/image-optimization.d.ts +25 -5
  61. package/dist/server/image-optimization.js +305 -21
  62. package/dist/server/image-source-reader.d.ts +34 -0
  63. package/dist/server/image-source-reader.js +126 -0
  64. package/dist/server/metadata-route-response.d.ts +6 -1
  65. package/dist/server/metadata-route-response.js +24 -6
  66. package/dist/server/middleware-matcher.d.ts +1 -0
  67. package/dist/server/middleware-matcher.js +1 -1
  68. package/dist/server/middleware-runtime.d.ts +5 -0
  69. package/dist/server/middleware-runtime.js +48 -15
  70. package/dist/server/middleware.d.ts +1 -1
  71. package/dist/server/middleware.js +2 -1
  72. package/dist/server/navigation-planner.js +14 -6
  73. package/dist/server/nitro-request-target-plugin.d.ts +17 -0
  74. package/dist/server/nitro-request-target-plugin.js +22 -0
  75. package/dist/server/open-redirect.d.ts +2 -1
  76. package/dist/server/open-redirect.js +2 -1
  77. package/dist/server/pages-client-assets.d.ts +1 -0
  78. package/dist/server/pages-i18n.d.ts +7 -0
  79. package/dist/server/pages-i18n.js +14 -1
  80. package/dist/server/pages-node-compat.js +7 -3
  81. package/dist/server/pages-page-handler.js +4 -4
  82. package/dist/server/pages-request-pipeline.d.ts +9 -0
  83. package/dist/server/pages-request-pipeline.js +29 -10
  84. package/dist/server/pages-request-stage-entry.js +7 -2
  85. package/dist/server/pages-router-entry.js +3 -0
  86. package/dist/server/prod-server.d.ts +1 -1
  87. package/dist/server/prod-server.js +48 -54
  88. package/dist/server/remove-request-headers.d.ts +16 -0
  89. package/dist/server/remove-request-headers.js +23 -0
  90. package/dist/server/srvx-middleware-origin.d.ts +13 -0
  91. package/dist/server/srvx-middleware-origin.js +19 -0
  92. package/dist/server/srvx-request-target.d.ts +12 -0
  93. package/dist/server/srvx-request-target.js +20 -0
  94. package/dist/server/static-file-cache.js +10 -22
  95. package/dist/server/worker-image-optimization.d.ts +8 -1
  96. package/dist/server/worker-image-optimization.js +25 -6
  97. package/dist/server/worker-revalidation-context.js +1 -0
  98. package/dist/shims/cache-runtime.js +1 -1
  99. package/dist/shims/cache.js +6 -3
  100. package/dist/shims/client-page-root.js +2 -2
  101. package/dist/shims/error-boundary.d.ts +6 -2
  102. package/dist/shims/error-boundary.js +6 -4
  103. package/dist/shims/internal/navigation-untracked.js +1 -1
  104. package/dist/shims/metadata.js +1 -1
  105. package/dist/shims/navigation-server.js +1 -1
  106. package/dist/shims/navigation.js +4 -4
  107. package/dist/shims/navigation.react-server.js +3 -3
  108. package/dist/shims/request-context.d.ts +3 -1
  109. package/dist/shims/root-params.js +16 -2
  110. package/dist/shims/slot.js +3 -3
  111. package/dist/shims/url-utils.js +6 -1
  112. package/dist/utils/client-entry-manifest.d.ts +5 -0
  113. package/dist/utils/client-entry-manifest.js +1 -0
  114. package/dist/utils/client-runtime-metadata.d.ts +5 -0
  115. package/dist/utils/client-runtime-metadata.js +33 -7
  116. package/package.json +1 -1
package/README.md CHANGED
@@ -137,10 +137,13 @@ files to `.cjs`) when an unambiguous default Vite config requires the ESM migrat
137
137
  `"type": "commonjs"` is never changed. Direct `vite dev` and `vite build` do not perform these
138
138
  wrapper compatibility steps.
139
139
 
140
- `@vinext/cloudflare deploy` options: `--preview`, `--env <name>`, `--name <name>`, `--vite-config <path>`, `--skip-build`, `--dry-run`, `--warm-cache`, `--traffic-aware-warm-cache`.
140
+ `@vinext/cloudflare deploy` options: `--preview`, `--env <name>`, `--name <name>` (Wrangler config projects only), `--vite-config <path>`, `--skip-build`, `--dry-run`, `--warm-cache`, `--traffic-aware-warm-cache`.
141
141
 
142
142
  `vinext init` prompts for a deployment target, defaulting to Cloudflare. Agents must ask the
143
143
  user which target they want, then pass `--platform=cloudflare` or `--platform=node`.
144
+ For Cloudflare, agents and CI must also pass `--cdn-cache`, `--data-cache`, and
145
+ `--image-optimization`; see
146
+ [Run init without prompts](https://vinext.dev/docs/deploying/cloudflare#run-init-without-prompts).
144
147
 
145
148
  Other options: `--port <port>` (default: 3001), `--skip-check`, `--force`.
146
149
 
@@ -91,7 +91,17 @@ type PrerenderPathDiscoveryOptions = {
91
91
  };
92
92
  };
93
93
  /** @internal Match the pathname forms and locale provenance used by middleware runtime. */
94
- export declare function matchesMiddlewareWarmPath(pathname: string, matcher: MatcherConfig | undefined, i18n: ResolvedNextConfig["i18n"]): boolean;
94
+ export declare function matchesMiddlewareWarmPath(pathname: string, matcher: MatcherConfig | undefined, i18n: ResolvedNextConfig["i18n"], options?: {
95
+ basePath?: string;
96
+ /**
97
+ * Whether the path's Pages data request reaches middleware slashed
98
+ * (`shouldAddTrailingSlashToPagesDataPath`). Omit for a path without a
99
+ * Pages data target.
100
+ */
101
+ pagesDataTrailingSlash?: boolean;
102
+ skipProxyUrlNormalize?: boolean;
103
+ trailingSlash?: boolean;
104
+ }): boolean;
95
105
  export declare function discoverPrerenderPathManifest(options: PrerenderPathDiscoveryOptions): Promise<PrerenderPathManifest | null>;
96
106
  export declare function emitPrerenderPathManifest(options: PrerenderPathDiscoveryOptions): Promise<PrerenderPathManifest | null>;
97
107
  //#endregion
@@ -10,6 +10,7 @@ import { appRouteHasMainTreeLoadingBoundary, appRouter, matchAppRoute } from "..
10
10
  import { apiRouter, matchRoute, pagesRouter } from "../routing/pages-router.js";
11
11
  import { matchesMiddlewarePathname } from "../server/middleware-matcher.js";
12
12
  import { extractLocaleFromUrl, normalizeDefaultLocalePathname, shouldRestoreLocaleRootTrailingSlash } from "../server/pages-i18n.js";
13
+ import { normalizeNextDataPagePathname, shouldAddTrailingSlashToPagesDataPath } from "../server/pages-data-route.js";
13
14
  import { classifyAppRoute, classifyAppRouteHandler, classifyPagesRoute, extractExportConstString, extractMiddlewareMatcherConfig, getAppRouteRenderEntryPath } from "./report.js";
14
15
  import { normalizeStaticPathname, normalizeStaticPathsEntry } from "../routing/route-pattern.js";
15
16
  import { buildPagesDataHref } from "../shims/internal/pages-data-url.js";
@@ -17,6 +18,7 @@ import { normalizePathTrailingSlash } from "../shims/url-utils.js";
17
18
  import { resolveAppPageDynamicConfig } from "../server/app-segment-config.js";
18
19
  import { classifyAppPageRouteStaticEligibility } from "./app-page-static-eligibility.js";
19
20
  import { pagesRouteHasPriorityOverAppRoute } from "../server/hybrid-route-priority.js";
21
+ import { tryRealpathSync } from "./ssr-manifest.js";
20
22
  import { readPrerenderSecret } from "./server-manifest.js";
21
23
  import { loadMdxEsmReader } from "../utils/mdx-scan.js";
22
24
  import { startProdServer } from "../server/prod-server.js";
@@ -673,10 +675,13 @@ function configuredRulesAffectWarmPath(pathname, rules, config) {
673
675
  function configuredRewritesCanReplaceWarmPath(pathname, rewrites, hasNonDynamicRoute, config, include) {
674
676
  return configuredRulesAffectWarmPath(pathname, [...rewrites.beforeFiles.filter(include), ...hasNonDynamicRoute ? [] : rewrites.afterFiles.filter(include)], config);
675
677
  }
678
+ function canonicalDir(dir) {
679
+ return toSlash(tryRealpathSync(dir) ?? dir);
680
+ }
676
681
  function findMiddlewareConventionFile(root, appDir, pagesDir, pageExtensions) {
677
682
  const routeDir = appDir ?? pagesDir;
678
683
  const routeRoot = routeDir ? path.dirname(routeDir) : root;
679
- const conventionDir = routeRoot === path.join(root, "src") ? routeRoot : root;
684
+ const conventionDir = canonicalDir(routeRoot) === canonicalDir(path.join(root, "src")) ? routeRoot : root;
680
685
  for (const name of ["proxy", "middleware"]) for (const extension of pageExtensions) {
681
686
  const filePath = path.join(conventionDir, `${name}.${extension}`);
682
687
  if (fs.existsSync(filePath)) return filePath;
@@ -684,19 +689,37 @@ function findMiddlewareConventionFile(root, appDir, pagesDir, pageExtensions) {
684
689
  return null;
685
690
  }
686
691
  /** @internal Match the pathname forms and locale provenance used by middleware runtime. */
687
- function matchesMiddlewareWarmPath(pathname, matcher, i18n) {
692
+ function matchesMiddlewareWarmPath(pathname, matcher, i18n, options = {}) {
688
693
  const encodedPathname = new URL(pathname, "https://vinext.invalid").pathname;
694
+ const trailingSlash = options.trailingSlash ?? false;
695
+ const htmlRequestPathname = normalizePathTrailingSlash(options.basePath ? `${options.basePath}${encodedPathname === "/" ? "" : encodedPathname}` : encodedPathname, trailingSlash);
689
696
  const firstSegment = encodedPathname.split("/", 3)[1]?.toLowerCase();
690
697
  const localeContexts = i18n ? i18n.locales.some((locale) => locale.toLowerCase() === firstSegment) ? [{ kind: "literal" }] : Array.from(/* @__PURE__ */ new Set([i18n.defaultLocale, ...i18n.domains?.map((domain) => domain.defaultLocale) ?? []]), (defaultLocale) => ({
691
698
  defaultLocale,
692
699
  kind: "defaulted"
693
700
  })) : [void 0];
694
- const matchPathnames = [encodedPathname];
695
- try {
696
- const decodedPathname = decodeURIComponent(encodedPathname);
697
- if (decodedPathname !== encodedPathname) matchPathnames.push(decodedPathname);
698
- } catch {}
699
- return matchPathnames.some((matchPathname) => localeContexts.some((localeContext) => matchesMiddlewarePathname(matchPathname, matcher, i18n, localeContext)));
701
+ const requestSpellings = [{
702
+ localeContexts: shouldRestoreLocaleRootTrailingSlash(htmlRequestPathname, options) ? localeContexts.map((localeContext) => localeContext?.kind === "defaulted" ? {
703
+ ...localeContext,
704
+ restoreRootTrailingSlash: true
705
+ } : localeContext) : localeContexts,
706
+ pathname: normalizePathTrailingSlash(encodedPathname, trailingSlash)
707
+ }];
708
+ if (options.pagesDataTrailingSlash !== void 0) {
709
+ const dataLocaleContexts = [i18n ? { kind: "literal" } : void 0];
710
+ requestSpellings.push({
711
+ localeContexts: dataLocaleContexts,
712
+ pathname: normalizeNextDataPagePathname(localizePagesDataPath(encodedPathname, i18n), options.pagesDataTrailingSlash)
713
+ });
714
+ }
715
+ return requestSpellings.some((spelling) => {
716
+ const matchPathnames = [spelling.pathname];
717
+ try {
718
+ const decodedPathname = decodeURIComponent(spelling.pathname);
719
+ if (decodedPathname !== spelling.pathname) matchPathnames.push(decodedPathname);
720
+ } catch {}
721
+ return matchPathnames.some((matchPathname) => spelling.localeContexts.some((localeContext) => matchesMiddlewarePathname(matchPathname, matcher, i18n, localeContext)));
722
+ });
700
723
  }
701
724
  async function startPathDiscoveryServer(options) {
702
725
  return startProdServer({
@@ -822,10 +845,7 @@ async function discoverPrerenderPathManifest(options) {
822
845
  const hasStagedRequestRouting = options.requestRouting === "uncached-stage";
823
846
  const middlewarePath = hasStagedRequestRouting ? findMiddlewareConventionFile(root, appDir, pagesDir, config.pageExtensions) : null;
824
847
  const configuredMatcher = middlewarePath ? extractMiddlewareMatcherConfig(middlewarePath) : void 0;
825
- const middlewareMayRouteWarmPath = (pathname) => middlewarePath !== null && matchesMiddlewareWarmPath(pathname, configuredMatcher, config.i18n);
826
848
  const routedWarmPaths = [...paths, ...discoveredRouteHandlerPaths];
827
- const routeMayResolveWarmPathSet = new Set(hasStagedRequestRouting ? routedWarmPaths.filter((pathname) => middlewareMayRouteWarmPath(pathname) || configuredRewritesCanReplaceWarmPath(pathname, config.rewrites, discoveredNonDynamicPathSet.has(pathname), config, (rewrite) => !isExternalUrl(rewrite.destination))) : []);
828
- const requestStageMayTerminateWarmPathSet = new Set(hasStagedRequestRouting ? routedWarmPaths.filter((pathname) => middlewareMayRouteWarmPath(pathname) || configuredRulesAffectWarmPath(pathname, config.redirects, config) || configuredRewritesCanReplaceWarmPath(pathname, config.rewrites, discoveredNonDynamicPathSet.has(pathname), config, (rewrite) => isExternalUrl(rewrite.destination))) : []);
829
849
  const excludedWarmPathSet = new Set(options.responseVary && !hasStagedRequestRouting ? routedWarmPaths.filter((pathname) => configuredRulesAffectWarmPath(pathname, config.redirects, config) || configuredRewritesCanReplaceWarmPath(pathname, config.rewrites, discoveredNonDynamicPathSet.has(pathname), config, () => true)) : []);
830
850
  const configuredPagesWarmPaths = discoveredPagesPaths.filter((pathname) => !excludedWarmPathSet.has(pathname));
831
851
  const resolvedPagesWarmPaths = !appDir && pagesDir ? await excludePagesApiWarmPaths({
@@ -864,6 +884,16 @@ async function discoverPrerenderPathManifest(options) {
864
884
  routePatterns: pagesWarmMetadata.routePatterns,
865
885
  rscPaths: []
866
886
  };
887
+ const pagesDataRequestsGetTrailingSlash = shouldAddTrailingSlashToPagesDataPath(true, config.trailingSlash, config.skipProxyUrlNormalize);
888
+ const pagesOwnedPathSet = appDir ? new Set(appOwnedWarmPaths.pagesPaths) : null;
889
+ const middlewareMatchesWarmPath = (pathname) => middlewarePath !== null && matchesMiddlewareWarmPath(pathname, configuredMatcher, config.i18n, {
890
+ basePath: config.basePath,
891
+ pagesDataTrailingSlash: discoveredPagesDataPathSet.has(pathname) && (pagesOwnedPathSet?.has(pathname) ?? true) ? pagesDataRequestsGetTrailingSlash : void 0,
892
+ skipProxyUrlNormalize: config.skipProxyUrlNormalize,
893
+ trailingSlash: config.trailingSlash
894
+ });
895
+ const routeMayResolveWarmPathSet = new Set(hasStagedRequestRouting ? routedWarmPaths.filter((pathname) => middlewareMatchesWarmPath(pathname) || configuredRewritesCanReplaceWarmPath(pathname, config.rewrites, discoveredNonDynamicPathSet.has(pathname), config, (rewrite) => !isExternalUrl(rewrite.destination))) : []);
896
+ const requestStageMayTerminateWarmPathSet = new Set(hasStagedRequestRouting ? routedWarmPaths.filter((pathname) => middlewareMatchesWarmPath(pathname) || configuredRulesAffectWarmPath(pathname, config.redirects, config) || configuredRewritesCanReplaceWarmPath(pathname, config.rewrites, discoveredNonDynamicPathSet.has(pathname), config, (rewrite) => isExternalUrl(rewrite.destination))) : []);
867
897
  for (const pathname of configuredCandidatePaths) {
868
898
  if (appOwnedWarmPaths.routePatterns[pathname] || !routeMayResolveWarmPathSet.has(pathname) && !requestStageMayTerminateWarmPathSet.has(pathname)) continue;
869
899
  appOwnedWarmPaths.htmlPaths.push(pathname);
package/dist/cli.js CHANGED
@@ -281,7 +281,7 @@ function printHelp(cmd) {
281
281
  --prerender Configure Vite builds to pre-render static routes
282
282
  (Cloudflare deploy won't serve them unless using Static Assets)
283
283
  --warm-cache Add cache warming to the Cloudflare deploy script
284
- (Response Store or Workers Cache, default: prompt with No)
284
+ (requires a --cdn-cache other than none, default: prompt with No)
285
285
  --legacy-wrangler-cloudflare-init
286
286
  Use the legacy Wrangler setup instead of cf
287
287
  --ignore-wrangler-config
@@ -5,7 +5,8 @@ export declare const DEV_ERROR_OVERLAY_HOST_ID = "__vinext_dev_error_overlay_roo
5
5
  export declare const DEV_ERROR_OVERLAY_MOUNT_ID = "__vinext_dev_error_overlay_mount";
6
6
  export declare function installDevErrorOverlay(): void;
7
7
  export declare function installReactRefreshErrorRecovery(): void;
8
- export declare function selectUnreportedInitialDevServerErrors(payloads: readonly InitialDevServerErrorPayload[], reported: readonly ReportedError[]): InitialDevServerErrorPayload[];
8
+ export declare function reportRootErrorBoundaryCatch(): void;
9
+ export declare function selectUnreportedInitialDevServerErrors(payloads: readonly InitialDevServerErrorPayload[], reported: readonly ReportedError[], rootBoundaryCaught?: boolean): InitialDevServerErrorPayload[];
9
10
  export declare function reportInitialDevServerErrors(): void;
10
11
  type ViteHmrErrorPayload = {
11
12
  err?: ViteHmrError;
@@ -82,7 +82,12 @@ function tryInstallReactRefreshErrorRecovery() {
82
82
  });
83
83
  return true;
84
84
  }
85
- function selectUnreportedInitialDevServerErrors(payloads, reported) {
85
+ let rootErrorBoundaryCaught = false;
86
+ function reportRootErrorBoundaryCatch() {
87
+ rootErrorBoundaryCaught = true;
88
+ }
89
+ function selectUnreportedInitialDevServerErrors(payloads, reported, rootBoundaryCaught = false) {
90
+ if (rootBoundaryCaught) return [];
86
91
  const rethrownErrors = reported.filter((error) => error.source === "caught" || error.source === "uncaught" || error.source === "window-error");
87
92
  return payloads.filter((payload) => {
88
93
  const rethrownIndex = rethrownErrors.findIndex((error) => error.message === payload.message && (error.name || "Error") === (payload.name || "Error"));
@@ -96,7 +101,7 @@ function reportInitialDevServerErrors() {
96
101
  const errors = window.__VINEXT_INITIAL_DEV_ERRORS__;
97
102
  if (!errors || errors.length === 0) return;
98
103
  window.__VINEXT_INITIAL_DEV_ERRORS__ = [];
99
- for (const payload of selectUnreportedInitialDevServerErrors(errors, getOverlaySnapshot().errors)) {
104
+ for (const payload of selectUnreportedInitialDevServerErrors(errors, getOverlaySnapshot().errors, rootErrorBoundaryCaught)) {
100
105
  const error = new Error(payload.message);
101
106
  if (payload.name) error.name = payload.name;
102
107
  if (payload.stack) error.stack = payload.stack;
@@ -1358,4 +1363,4 @@ const componentStackStyle = {
1358
1363
  color: "var(--vinext-overlay-muted)"
1359
1364
  };
1360
1365
  //#endregion
1361
- export { DEV_ERROR_OVERLAY_HOST_ID, DEV_ERROR_OVERLAY_MOUNT_ID, createDevErrorOverlayMountNode, createViteOpenInEditorUrl, devOnCaughtError, devOnUncaughtError, dismissOverlay, formatErrorInfoForClipboard, formatOverlayDisplayFile, formatViteOpenInEditorFile, installDevErrorOverlay, installReactRefreshErrorRecovery, installViteHmrErrorHandler, normalizeViteHmrError, reportInitialDevServerErrors, selectUnreportedInitialDevServerErrors };
1366
+ export { DEV_ERROR_OVERLAY_HOST_ID, DEV_ERROR_OVERLAY_MOUNT_ID, createDevErrorOverlayMountNode, createViteOpenInEditorUrl, devOnCaughtError, devOnUncaughtError, dismissOverlay, formatErrorInfoForClipboard, formatOverlayDisplayFile, formatViteOpenInEditorFile, installDevErrorOverlay, installReactRefreshErrorRecovery, installViteHmrErrorHandler, normalizeViteHmrError, reportInitialDevServerErrors, reportRootErrorBoundaryCatch, selectUnreportedInitialDevServerErrors };
@@ -179,10 +179,14 @@ const REQUEST_HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
179
179
  "transfer-encoding",
180
180
  "upgrade"
181
181
  ]);
182
+ /**
183
+ * Strip the fixed request hop-by-hop list. Fields the client nominates in
184
+ * `Connection` are forwarded, like Next.js: the headers here already include
185
+ * middleware's request overrides, so honouring the client's list would let it
186
+ * drop headers middleware set.
187
+ */
182
188
  function stripHopByHopRequestHeaders(headers) {
183
- const connectionTokens = (headers.get("connection") || "").split(",").map((value) => value.trim().toLowerCase()).filter(Boolean);
184
189
  for (const header of REQUEST_HOP_BY_HOP_HEADERS) headers.delete(header);
185
- for (const token of connectionTokens) headers.delete(token);
186
190
  }
187
191
  /**
188
192
  * Compile a regex from next.config, or return null when it is invalid.
@@ -213,6 +213,15 @@ export type NextConfig = {
213
213
  contentDispositionType?: "inline" | "attachment";
214
214
  /** Content-Security-Policy header for image responses. Defaults to "script-src 'none'; frame-src 'none'; sandbox;" */
215
215
  contentSecurityPolicy?: string;
216
+ /** Least max-age, in seconds, of an image the endpoint serves as-is. Defaults to 14400. */
217
+ minimumCacheTTL?: number;
218
+ /**
219
+ * Most bytes the endpoint reads of a GIF, PNG or WebP source bound for an
220
+ * image optimizer (while detecting animation and while streaming to the
221
+ * optimizer) before answering 413. Other sources stream unbounded.
222
+ * Defaults to 50000000.
223
+ */
224
+ maximumResponseBody?: number;
216
225
  };
217
226
  /**
218
227
  * Enable React Strict Mode. When `true`, the client root is wrapped in
@@ -122,8 +122,7 @@ function buildAppDecodedPathnamePatterns(routes, config) {
122
122
  };
123
123
  return routes.filter((route) => !route.isDynamic && !route.routePath && getAppRouteRenderEntryPath(route) !== null && isPrerenderedPage(route)).map((route) => route.pattern);
124
124
  }
125
- function createForcesDynamicReader() {
126
- const readSource = createSegmentSourceReader();
125
+ function createForcesDynamicReader(readSource = createSegmentSourceReader()) {
127
126
  return (filePath) => {
128
127
  const source = readSource(filePath);
129
128
  return source !== null && extractExportConstString(source, "dynamic") === "force-dynamic";
@@ -134,7 +133,13 @@ function directRequestForcesDynamic(route, forcesDynamic) {
134
133
  return route.routePath ? forcesDynamic(route.routePath) : appPageSegmentConfigPaths(route).some(forcesDynamic);
135
134
  }
136
135
  function buildAppRequestRouteMetadata(routes) {
137
- const forcesDynamic = createForcesDynamicReader();
136
+ const readSource = createSegmentSourceReader();
137
+ const forcesDynamic = createForcesDynamicReader(readSource);
138
+ const routeHandlerMetadata = (filePath) => {
139
+ const source = readSource(filePath);
140
+ const runtime = source === null ? null : extractExportConstString(source, "runtime");
141
+ return runtime ? { runtime } : true;
142
+ };
138
143
  return routes.map((route) => ({
139
144
  canUseCanonicalLoadingShell: appRouteHasMainTreeLoadingBoundary(route),
140
145
  forceDynamic: directRequestForcesDynamic(route, forcesDynamic) || [...route.parallelSlots.flatMap((slot) => slot.interceptingRoutes.flatMap((intercept) => [...intercept.layoutPaths, intercept.pagePath])), ...route.siblingIntercepts.flatMap((intercept) => [...intercept.layoutPaths, intercept.pagePath])].some(forcesDynamic),
@@ -145,7 +150,7 @@ function buildAppRequestRouteMetadata(routes) {
145
150
  params: route.params,
146
151
  rootParamNames: route.rootParamNames ?? [],
147
152
  page: route.pagePath ? true : null,
148
- routeHandler: route.routePath ? true : null,
153
+ routeHandler: route.routePath ? routeHandlerMetadata(route.routePath) : null,
149
154
  routeSegments: route.routeSegments,
150
155
  layouts: [],
151
156
  layoutTreePositions: [],
@@ -292,7 +297,9 @@ export const __imageConfig = ${JSON.stringify({
292
297
  dangerouslyAllowSVG: config?.imageConfig?.dangerouslyAllowSVG,
293
298
  dangerouslyAllowLocalIP: config?.imageConfig?.dangerouslyAllowLocalIP,
294
299
  contentDispositionType: config?.imageConfig?.contentDispositionType,
295
- contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy
300
+ contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy,
301
+ minimumCacheTTL: config?.imageConfig?.minimumCacheTTL,
302
+ maximumResponseBody: config?.imageConfig?.maximumResponseBody
296
303
  })};
297
304
  export const __clientBuildFiles = __pagesClientAssets.clientBuildFiles ?? [];
298
305
  // The matcher reads recorded prerenders, and this stage can run without the
@@ -385,7 +392,7 @@ const __requestHandler = createAppRscRequestHandler({
385
392
  params: pickParams(route, intercept.sourceMatchedParams),
386
393
  };
387
394
  },
388
- ${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, validateExternalRewriteRequest }) {
395
+ ${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, restoreLocaleRootTrailingSlash, validateExternalRewriteRequest }) {
389
396
  return __applyAppMiddleware({
390
397
  basePath: __basePath,
391
398
  cleanPathname,
@@ -399,6 +406,7 @@ const __requestHandler = createAppRscRequestHandler({
399
406
  middlewareRequest,
400
407
  module: middlewareModule,
401
408
  request,
409
+ restoreLocaleRootTrailingSlash,
402
410
  skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
403
411
  trailingSlash: __trailingSlash,
404
412
  validateExternalRewriteRequest,
@@ -407,9 +415,9 @@ const __requestHandler = createAppRscRequestHandler({
407
415
  publicFiles: new Set(${JSON.stringify(config?.publicFiles ?? [])}),
408
416
  registerCacheAdapters: __registerConfiguredCacheAdapters,
409
417
  renderNotFound: async () => null,
410
- ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, dispatchPagesResponseStage, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, sharedAcrossHosts, url }) {
418
+ ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, dispatchPagesResponseStage, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, requestBasePath, sharedAcrossHosts, url }) {
411
419
  return __renderPagesFallback(
412
- { allowRscDocumentFallback, appRouteMatch, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, sharedAcrossHosts, url },
420
+ { allowRscDocumentFallback, appRouteMatch, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, requestBasePath, sharedAcrossHosts, url },
413
421
  {
414
422
  async loadPagesEntry() {
415
423
  if (!dispatchPagesResponseStage) {
@@ -504,7 +512,9 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
504
512
  dangerouslyAllowSVG: config?.imageConfig?.dangerouslyAllowSVG,
505
513
  dangerouslyAllowLocalIP: config?.imageConfig?.dangerouslyAllowLocalIP,
506
514
  contentDispositionType: config?.imageConfig?.contentDispositionType,
507
- contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy
515
+ contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy,
516
+ minimumCacheTTL: config?.imageConfig?.minimumCacheTTL,
517
+ maximumResponseBody: config?.imageConfig?.maximumResponseBody
508
518
  };
509
519
  const { imports, importInitializers, routeEntries, metaRouteEntries, generateStaticParamsEntries, rootParamNameEntries, rootNotFoundVar, rootForbiddenVar, rootUnauthorizedVar, rootLayoutVars, globalErrorVar, globalNotFoundImportSpecifier } = buildAppRscManifestCode({
510
520
  deferEagerImports: Boolean(instrumentationPath),
@@ -1143,6 +1153,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1143
1153
  observePageSearchParamsAccess: buildOptions?.observePageSearchParamsAccess === true,
1144
1154
  isForceStatic: buildOptions?.isForceStatic === true,
1145
1155
  isUncacheableRender: buildOptions?.isUncacheableRender === true,
1156
+ routeTreeOnlyPrefetchShell: buildOptions?.routeTreeOnlyPrefetchShell === true,
1146
1157
  mountedLayouts: buildOptions?.mountedLayouts ?? null,
1147
1158
  serveStreamingMetadata: buildOptions?.serveStreamingMetadata,
1148
1159
  placeStreamedMetadataInHead: buildOptions?.placeStreamedMetadataInHead === true,
@@ -1671,7 +1682,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1671
1682
  params: pickParams(route, intercept.sourceMatchedParams),
1672
1683
  };
1673
1684
  },
1674
- ${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, validateExternalRewriteRequest }) {
1685
+ ${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, restoreLocaleRootTrailingSlash, validateExternalRewriteRequest }) {
1675
1686
  return __applyAppMiddleware({
1676
1687
  basePath: __basePath,
1677
1688
  cleanPathname,
@@ -1685,6 +1696,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1685
1696
  middlewareRequest,
1686
1697
  module: middlewareModule,
1687
1698
  request,
1699
+ restoreLocaleRootTrailingSlash,
1688
1700
  skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
1689
1701
  trailingSlash: __trailingSlash,
1690
1702
  validateExternalRewriteRequest,
@@ -1695,9 +1707,9 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1695
1707
  const __isEdge = route ? __isEdgeRuntime(__resolveRouteRuntime(route)) : false;
1696
1708
  return __fallbackRenderer.renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, { isEdgeRuntime: __isEdge });
1697
1709
  },
1698
- ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, dispatchPagesResponseStage, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, sharedAcrossHosts, url }) {
1710
+ ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, dispatchPagesResponseStage, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, requestBasePath, sharedAcrossHosts, url }) {
1699
1711
  return __renderPagesFallback(
1700
- { allowRscDocumentFallback, appRouteMatch, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, sharedAcrossHosts, url },
1712
+ { allowRscDocumentFallback, appRouteMatch, initialResponseHeaders, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, requestBasePath, sharedAcrossHosts, url },
1701
1713
  {
1702
1714
  async loadPagesEntry() {
1703
1715
  const __pagesEntry = await __ensureHybridPagesApplication();
@@ -108,7 +108,9 @@ async function generatePagesRequestEntry(pagesDir, nextConfig, fileMatcher, midd
108
108
  dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
109
109
  dangerouslyAllowLocalIP: nextConfig?.images?.dangerouslyAllowLocalIP,
110
110
  contentDispositionType: nextConfig?.images?.contentDispositionType,
111
- contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy
111
+ contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy,
112
+ minimumCacheTTL: nextConfig?.images?.minimumCacheTTL,
113
+ maximumResponseBody: nextConfig?.images?.maximumResponseBody
112
114
  }
113
115
  });
114
116
  const instrumentationImportCode = instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(instrumentationPath)};
@@ -135,6 +137,7 @@ export function __ensureInstrumentation(ctx) {
135
137
  isProxy: ${JSON.stringify(isProxyFile(middlewarePath))},
136
138
  module: middlewareModule,
137
139
  request,
140
+ restoreLocaleRootTrailingSlash: options?.restoreLocaleRootTrailingSlash === true,
138
141
  skipTrailingSlashRedirect: vinextConfig.skipTrailingSlashRedirect,
139
142
  trailingSlash: vinextConfig.trailingSlash,
140
143
  });
@@ -165,11 +168,14 @@ export const vinextConfig = ${vinextConfigJson};
165
168
  export const publicFiles = new Set(${JSON.stringify(publicFiles)});
166
169
  export const clientBuildFiles = new Set(__pagesClientAssets.clientBuildFiles ?? []);
167
170
 
171
+ // The Worker request stage strips basePath before calling this, so the data
172
+ // path must not lose it again: with basePath "/docs", "/docs/docs/_next/data/..."
173
+ // is the page path "/docs/_next/data/...", not a data request.
168
174
  export function normalizeDataRequest(request) {
169
175
  return __normalizePagesDataRequest(
170
176
  request,
171
177
  buildId,
172
- vinextConfig.basePath,
178
+ "",
173
179
  __shouldAddTrailingSlashToPagesDataPath(
174
180
  hasMiddleware,
175
181
  vinextConfig.trailingSlash,
@@ -286,7 +292,9 @@ async function generateServerEntry(pagesDir, nextConfig, fileMatcher, middleware
286
292
  dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
287
293
  dangerouslyAllowLocalIP: nextConfig?.images?.dangerouslyAllowLocalIP,
288
294
  contentDispositionType: nextConfig?.images?.contentDispositionType,
289
- contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy
295
+ contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy,
296
+ minimumCacheTTL: nextConfig?.images?.minimumCacheTTL,
297
+ maximumResponseBody: nextConfig?.images?.maximumResponseBody
290
298
  }
291
299
  });
292
300
  const instrumentationImportCode = instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(instrumentationPath)};
@@ -333,6 +341,7 @@ export async function runMiddleware(request, ctx, options) {
333
341
  isProxy: ${JSON.stringify(isProxyFile(middlewarePath))},
334
342
  module: middlewareModule,
335
343
  request,
344
+ restoreLocaleRootTrailingSlash: options?.restoreLocaleRootTrailingSlash === true,
336
345
  skipTrailingSlashRedirect: vinextConfig.skipTrailingSlashRedirect,
337
346
  trailingSlash: vinextConfig.trailingSlash,
338
347
  });
@@ -400,11 +409,14 @@ export const buildId = ${buildIdJson};
400
409
  // Per-build capability used by Worker entries to authorize remote path
401
410
  // discovery. It is never included in responses or exposed to user modules.
402
411
  export const prerenderSecret = ${JSON.stringify(prerenderSecret ?? null)};
412
+ // The Worker request stage strips basePath before calling this, so the data
413
+ // path must not lose it again: with basePath "/docs", "/docs/docs/_next/data/..."
414
+ // is the page path "/docs/_next/data/...", not a data request.
403
415
  export function normalizeDataRequest(request) {
404
416
  return __normalizePagesDataRequest(
405
417
  request,
406
418
  buildId,
407
- vinextConfig.basePath,
419
+ "",
408
420
  __shouldAddTrailingSlashToPagesDataPath(
409
421
  hasMiddleware,
410
422
  vinextConfig.trailingSlash,
@@ -439,6 +451,7 @@ export const pageRoutes = [
439
451
  ${pageRouteEntries.join(",\n")}
440
452
  ];
441
453
  export const publicFiles = new Set(${JSON.stringify(publicFiles)});
454
+ export const clientBuildFiles = new Set(__pagesClientAssets.clientBuildFiles ?? []);
442
455
  const _pageRouteTrie = _buildRouteTrie(pageRoutes);
443
456
  const _errorPageRoute = {
444
457
  pattern: "/_error",