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/dist/index.js CHANGED
@@ -18,8 +18,8 @@ import { hasBasePath, restoreBasePath, stripBasePath } from "./utils/base-path.j
18
18
  import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_TIMING_HEADER } from "./server/headers.js";
19
19
  import { methodNotAllowedResponse, notFoundStaticAssetResponse } from "./server/http-error-responses.js";
20
20
  import { isOpenRedirectShaped, sendRepeatedSlashRedirect } from "./server/open-redirect.js";
21
- import { canonicalizeRequestUrlPathname, filterInternalHeaders, normalizeTrailingSlash } from "./server/request-pipeline.js";
22
- import { matchesRewriteSource, proxyExternalRequest } from "./config/config-matchers.js";
21
+ import { canonicalizeRequestUrlPathname, normalizeTrailingSlash } from "./server/request-pipeline.js";
22
+ import { proxyExternalRequest } from "./config/config-matchers.js";
23
23
  import { omitUnusedBuildSourcemap } from "./plugins/transform-result.js";
24
24
  import { assetPrefixPathname, isNextStaticPath, resolveAssetsDir } from "./utils/asset-prefix.js";
25
25
  import { RESOLVED_VIRTUAL_GOOGLE_FONTS, VIRTUAL_GOOGLE_FONTS, createGoogleFontsPlugin, createLocalFontsPlugin, generateGoogleFontsVirtualModule, parseStaticObjectLiteral } from "./plugins/fonts.js";
@@ -31,7 +31,7 @@ import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./rout
31
31
  import { resolveRuntimeEntryModule } from "./entries/runtime-entry-module.js";
32
32
  import { normalizePath as normalizePath$1 } from "./server/normalize-path.js";
33
33
  import { validateMiddlewareMatcherPatterns } from "./server/middleware-matcher-pattern.js";
34
- import { resolvePagesI18nRequest, shouldRestoreLocaleRootTrailingSlash, stripI18nLocaleForApiRoute } from "./server/pages-i18n.js";
34
+ import { resolvePagesI18nRequest, shouldRestoreLocaleRootTrailingSlash } from "./server/pages-i18n.js";
35
35
  import { encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath } from "./server/pages-data-route.js";
36
36
  import { findInstrumentationClientFile, findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
37
37
  import { findMiddlewareFile, isProxyFile, runMiddleware } from "./server/middleware.js";
@@ -64,6 +64,7 @@ import { generateBrowserEntry, generateBrowserRouteManifestModule, toHashedRoute
64
64
  import { createRscScanGlobImportsPlugin, isRscScanGlobImportsAffected } from "./plugins/rsc-scan-glob-imports.js";
65
65
  import { loadOrGenerateServerActionsEncryptionKey } from "./build/server-actions-encryption-key.js";
66
66
  import { findOpenTelemetryPackages, mergeServerExternalPackages } from "./config/server-external-packages.js";
67
+ import { removeRequestHeaders } from "./server/remove-request-headers.js";
67
68
  import { precompressAssets } from "./build/precompress.js";
68
69
  import { VINEXT_PRERENDER_CONFIG_PLUGIN_PROPERTY, VINEXT_ROUTE_ROOT_CONFIG_PLUGIN_PROPERTY, normalizeVinextPrerenderConfig } from "./config/prerender.js";
69
70
  import { VINEXT_CLIENT_ENTRY_MANIFEST, VINEXT_CLIENT_REFERENCE_SOURCES } from "./utils/client-entry-manifest.js";
@@ -78,6 +79,7 @@ import { readTrustedRevalidationHostname } from "./server/revalidation-host.js";
78
79
  import { sealForwardedMiddlewareContext } from "./server/forwarded-middleware-context.js";
79
80
  import { installDevStackSourcemapMiddleware } from "./server/dev-stack-sourcemap.js";
80
81
  import { traceFrameworkRequest } from "./server/request-tracing.js";
82
+ import { publicFileRouteKey } from "./utils/public-file-path.js";
81
83
  import { runPagesRequest } from "./server/pages-request-pipeline.js";
82
84
  import { pagesRouteHasPriorityOverAppRoute, validateHybridRouteConflicts } from "./server/hybrid-route-priority.js";
83
85
  import { hasReactCompilerPlugin, isReactCompilerPlugin, isReactCompilerRequested, reactCompilerUnsupportedMessage } from "./utils/react-compiler-support.js";
@@ -134,7 +136,6 @@ import { createExtensionlessDynamicImportPlugin } from "./plugins/extensionless-
134
136
  import { createWasmModuleImportPlugin } from "./plugins/wasm-module-import.js";
135
137
  import { consumerEnvironmentConditionFilter, getTypeofWindowReplacement, mayFoldChangeScannedImports, replaceConsumerEnvironmentConditions } from "./plugins/typeof-window.js";
136
138
  import { hasMdxFiles, loadMdxEsmReader, pageExtensionsIncludeMdx } from "./utils/mdx-scan.js";
137
- import { publicFileRouteKey } from "./utils/public-file-path.js";
138
139
  import { scanPublicFileRoutes, scanPublicFiles } from "./utils/public-routes.js";
139
140
  import { createIgnoreDynamicRequestsPlugin } from "./plugins/ignore-dynamic-requests.js";
140
141
  import { assertPluginRscVersion, needsAppReactServerDom } from "./utils/plugin-rsc-version.js";
@@ -182,10 +183,10 @@ const RSC_ENVIRONMENTS = /* @__PURE__ */ new Set([
182
183
  "client"
183
184
  ]);
184
185
  const VINEXT_GENERATED_DIR_RE = /(?:^|[/\\])\.vinext(?:[/\\]|$)/;
186
+ const FORWARDED_MIDDLEWARE_CONTEXT_HEADERS = /* @__PURE__ */ new Set([VINEXT_MW_CTX_HEADER]);
187
+ const STRIPPED_INTERNAL_REQUEST_HEADERS = /* @__PURE__ */ new Set([...INTERNAL_HEADERS, ...VINEXT_INTERNAL_HEADERS]);
185
188
  function removeForwardedMiddlewareContext(req) {
186
- delete req.headers[VINEXT_MW_CTX_HEADER];
187
- const rawHeaders = req.rawHeaders;
188
- for (let i = rawHeaders.length - 2; i >= 0; i -= 2) if (rawHeaders[i].toLowerCase() === "x-vinext-mw-ctx") rawHeaders.splice(i, 2);
189
+ removeRequestHeaders(req, FORWARDED_MIDDLEWARE_CONTEXT_HEADERS);
189
190
  }
190
191
  function setForwardedMiddlewareContext(req, key, context) {
191
192
  removeForwardedMiddlewareContext(req);
@@ -844,6 +845,7 @@ const PAGES_REQUEST_STAGE_ENTRY = resolveRuntimeEntryModule("pages-request-stage
844
845
  const PAGES_RESPONSE_STAGE_ENTRY = resolveRuntimeEntryModule("pages-response-stage-entry");
845
846
  const NITRO_PUBLIC_FILES_ENTRY = resolveRuntimeEntryModule("nitro-public-files");
846
847
  const NITRO_PUBLIC_FILES_PLUGIN = resolveRuntimeEntryModule("nitro-public-files-plugin");
848
+ const SRVX_MIDDLEWARE_ORIGIN_ENTRY = resolveRuntimeEntryModule("srvx-middleware-origin");
847
849
  const WORKER_ROUTER_ENTRIES = /* @__PURE__ */ new Set([resolveRuntimeEntryModule("app-router-entry"), resolveRuntimeEntryModule("pages-router-entry")]);
848
850
  /** Virtual module that registers config-driven cache adapters (see VinextOptions.cache). */
849
851
  const RESOLVED_CACHE_ADAPTERS = "\0" + VIRTUAL_CACHE_ADAPTERS;
@@ -939,6 +941,20 @@ function getLeadingReactDirective(code) {
939
941
  function hasReactDirective(code) {
940
942
  return getLeadingReactDirective(code) !== null;
941
943
  }
944
+ /**
945
+ * Resolve a project directory through symlinks the way Vite resolves
946
+ * `config.root` (and Next.js its project dir), so route files, `server.config.root`
947
+ * and module ids all share one path. Windows uses the JS realpath, as Vite
948
+ * does, to keep mapped network drives.
949
+ */
950
+ function resolveProjectDir(dir, preserveSymlinks) {
951
+ if (preserveSymlinks) return toSlash(dir);
952
+ try {
953
+ return toSlash(process.platform === "win32" ? fs.realpathSync(dir) : fs.realpathSync.native(dir));
954
+ } catch {
955
+ return toSlash(dir);
956
+ }
957
+ }
942
958
  function generateRootParamsModule(rootParamNames) {
943
959
  const names = Array.from(new Set(rootParamNames)).filter(isValidExportIdentifier).sort();
944
960
  if (names.length === 0) return "export {};\n";
@@ -1488,7 +1504,7 @@ function vinext(options = {}) {
1488
1504
  buildEmptyOutDir = typeof config.build?.emptyOutDir === "boolean" ? config.build.emptyOutDir : void 0;
1489
1505
  isServeCommand = env.command === "serve";
1490
1506
  const ipaddrSsrExternal = env.command === "serve" ? ["ipaddr.js"] : [];
1491
- root = path.resolve(toSlash(process.cwd()), config.root ?? ".");
1507
+ root = resolveProjectDir(path.resolve(toSlash(process.cwd()), config.root ?? "."), config.resolve?.preserveSymlinks);
1492
1508
  if (env.command === "build") assertClientOutDirIsSeparate(root, options);
1493
1509
  const devCliLifecycleEnabled = env.command === "serve" && env.isPreview !== true && claimViteCliDevInvocation(root, config["__vinextDevRestart"] === true, reservedDevCliInvocation && config.configFile === false);
1494
1510
  buildLifecycleInvocation = config[VINEXT_BUILD_LIFECYCLE_CONFIG];
@@ -1500,7 +1516,7 @@ function vinext(options = {}) {
1500
1516
  const swcHelpersAlias = resolveSwcHelpersAlias(root);
1501
1517
  const mode = env?.mode ?? "development";
1502
1518
  const envDir = config.envDir === false ? void 0 : config.envDir ? path.resolve(root, config.envDir) : root;
1503
- if (earlyDotenv && envDir !== earlyDotenv.dir) {
1519
+ if (earlyDotenv && (envDir === void 0 || resolveProjectDir(envDir, config.resolve?.preserveSymlinks) !== resolveProjectDir(earlyDotenv.dir, config.resolve?.preserveSymlinks))) {
1504
1520
  for (const [key, value] of Object.entries(earlyDotenv.env)) if (process.env[key] === value) Reflect.deleteProperty(process.env, key);
1505
1521
  earlyDotenv = void 0;
1506
1522
  }
@@ -1519,10 +1535,8 @@ function vinext(options = {}) {
1519
1535
  }
1520
1536
  draftModeSecret = previewBuildCredentials?.id ?? getPagesPreviewModeId();
1521
1537
  let baseDir;
1522
- if (options.appDir) {
1523
- const dir = path.isAbsolute(options.appDir) ? options.appDir : path.resolve(root, options.appDir);
1524
- baseDir = toSlash(dir);
1525
- } else {
1538
+ if (options.appDir) baseDir = resolveProjectDir(path.isAbsolute(options.appDir) ? options.appDir : path.resolve(root, options.appDir), config.resolve?.preserveSymlinks);
1539
+ else {
1526
1540
  const hasRootApp = fs.existsSync(path.join(root, "app"));
1527
1541
  const hasRootPages = fs.existsSync(path.join(root, "pages"));
1528
1542
  const hasSrcApp = fs.existsSync(path.join(root, "src", "app"));
@@ -1757,6 +1771,7 @@ function vinext(options = {}) {
1757
1771
  delete config.resolve.alias;
1758
1772
  }
1759
1773
  const viteConfig = {
1774
+ root,
1760
1775
  appType: "custom",
1761
1776
  ...devCliLifecycleEnabled ? { [VINEXT_DEV_CLI_LIFECYCLE]: true } : {},
1762
1777
  ...hasAppDir && hasNitroPlugin ? { rsc: { serverHandler: false } } : {},
@@ -2359,9 +2374,14 @@ function vinext(options = {}) {
2359
2374
  const entry = hasAppDir ? "vinext/server/app-router-entry" : "vinext/server/pages-router-entry";
2360
2375
  if (!hasAppDir && hasNitroPlugin) return [
2361
2376
  `import pagesWorker from ${JSON.stringify(entry)};`,
2377
+ `import { resolveSrvxMiddlewareOrigin } from ${JSON.stringify(SRVX_MIDDLEWARE_ORIGIN_ENTRY)};`,
2362
2378
  ...nitroPublicFiles ? [`import { withNitroPagesPublicFiles } from ${JSON.stringify(NITRO_PUBLIC_FILES_ENTRY)};`, "const worker = withNitroPagesPublicFiles(pagesWorker);"] : ["const worker = pagesWorker;"],
2363
2379
  "export default { fetch(request, env, ctx) {",
2364
- ` return worker.fetch(request, env, { ...ctx, hostRuntime: ${JSON.stringify(nitroHostRuntime)} });`,
2380
+ " return worker.fetch(request, env, {",
2381
+ " ...ctx,",
2382
+ ` hostRuntime: ${JSON.stringify(nitroHostRuntime)},`,
2383
+ " middlewareOrigin: resolveSrvxMiddlewareOrigin(request),",
2384
+ " });",
2365
2385
  "} };"
2366
2386
  ].join("\n");
2367
2387
  return `export { default } from ${JSON.stringify(entry)};`;
@@ -2453,7 +2473,9 @@ function vinext(options = {}) {
2453
2473
  dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
2454
2474
  dangerouslyAllowLocalIP: nextConfig?.images?.dangerouslyAllowLocalIP,
2455
2475
  contentDispositionType: nextConfig?.images?.contentDispositionType,
2456
- contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy
2476
+ contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy,
2477
+ minimumCacheTTL: nextConfig?.images?.minimumCacheTTL,
2478
+ maximumResponseBody: nextConfig?.images?.maximumResponseBody
2457
2479
  },
2458
2480
  hasPagesDir,
2459
2481
  publicFiles: isServeCommand && devPublicFileRoutes ? [...devPublicFileRoutes].sort() : scanPublicFileRoutes(root, this.environment.config.publicDir === "" ? false : this.environment.config.publicDir),
@@ -2734,9 +2756,11 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
2734
2756
  handler(_options, bundle) {
2735
2757
  if (this.environment?.name !== "client") return;
2736
2758
  const manifest = {};
2759
+ const appBrowserRuntimeModule = toSlash(resolveRuntimeEntryModule("app-browser-entry"));
2737
2760
  for (const chunk of Object.values(bundle)) {
2738
2761
  if (chunk.type !== "chunk") continue;
2739
2762
  if (chunk.isDynamicEntry && isVirtualEntryFacade(chunk.facadeModuleId, VIRTUAL_APP_ROUTE_MANIFEST)) manifest.appRouteManifest = chunk.fileName;
2763
+ if (chunk.moduleIds.some((id) => toSlash(id) === appBrowserRuntimeModule)) manifest.appBrowserRuntime = chunk.fileName;
2740
2764
  if (!chunk.isEntry) continue;
2741
2765
  if (isVirtualEntryFacade(chunk.facadeModuleId, VIRTUAL_CLIENT_ENTRY)) manifest.pagesClientEntry = chunk.fileName;
2742
2766
  else if (isVirtualEntryFacade(chunk.facadeModuleId, VIRTUAL_APP_BROWSER_ENTRY)) manifest.appBrowserEntry = chunk.fileName;
@@ -3332,6 +3356,7 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
3332
3356
  }
3333
3357
  revalidationHostname = readTrustedRevalidationHostname(revalidationHeaders, nextConfig?.i18n);
3334
3358
  }
3359
+ removeRequestHeaders(req, STRIPPED_INTERNAL_REQUEST_HEADERS);
3335
3360
  const requestHost = revalidationHostname ?? ((Array.isArray(req.headers.host) ? req.headers.host[0] : req.headers.host) || "localhost");
3336
3361
  const requestOrigin = `http://${requestHost}`;
3337
3362
  const getUrlHostname = (requestUrl) => new URL(requestUrl).hostname;
@@ -3441,31 +3466,9 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
3441
3466
  });
3442
3467
  }
3443
3468
  }
3444
- const filePathMatchesRewrite = [
3445
- ...nextConfig?.rewrites.beforeFiles ?? [],
3446
- ...nextConfig?.rewrites.afterFiles ?? [],
3447
- ...nextConfig?.rewrites.fallback ?? []
3448
- ].some((rewrite) => matchesRewriteSource(pathname, rewrite, {
3449
- basePath: bp,
3450
- hadBasePath: true
3451
- }));
3452
- const isFilePathRequest = pathname.includes(".") && !pathname.endsWith(".html");
3453
- const isExistingPublicMutation = req.method !== "GET" && req.method !== "HEAD" && isExistingDevPublicFile(pathname);
3454
- let filePathMatchesPagesRoute = false;
3455
- const requestHostname = getUrlHostname(requestOrigin);
3456
- if (isFilePathRequest && !filePathMatchesRewrite && !isDataReq) {
3457
- const [pageRoutes, apiRoutes] = await Promise.all([pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher), apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher)]);
3458
- const pageRouteUrl = nextConfig?.i18n ? resolvePagesI18nRequest(pathname, nextConfig.i18n, req.headers, requestHostname, bp, nextConfig.trailingSlash ?? false).url : pathname;
3459
- const apiRouteUrl = stripI18nLocaleForApiRoute(pathname, nextConfig?.i18n ?? null);
3460
- filePathMatchesPagesRoute = matchRoute(pageRouteUrl, pageRoutes) !== null || matchRoute(apiRouteUrl, apiRoutes) !== null;
3461
- }
3462
- if (isFilePathRequest && !isDataReq && !filePathMatchesRewrite && !filePathMatchesPagesRoute && !isNextStaticPath(pathname, "", assetPrefixPathname(nextConfig?.assetPrefix ?? "")) && !isExistingPublicMutation) return next();
3463
- const rawHeaders = new Headers(Object.fromEntries(Object.entries(req.headers).filter(([k, v]) => v !== void 0 && !k.startsWith(":")).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
3469
+ const nodeRequestHeaders = new Headers(Object.fromEntries(Object.entries(req.headers).filter(([k, v]) => v !== void 0 && !k.startsWith(":")).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
3464
3470
  const isDataRequest = isDataReq;
3465
- const nodeRequestHeaders = filterInternalHeaders(rawHeaders);
3466
3471
  if (revalidationHostname) nodeRequestHeaders.set("host", revalidationHostname);
3467
- for (const header of INTERNAL_HEADERS) delete req.headers[header];
3468
- for (const header of VINEXT_INTERNAL_HEADERS) delete req.headers[header];
3469
3472
  const method = req.method ?? "GET";
3470
3473
  const webRequest = new Request(new URL(routeUrl, requestOrigin), {
3471
3474
  method,
@@ -3489,7 +3492,7 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
3489
3492
  headers: nodeRequestHeaders,
3490
3493
  signal: webRequest.signal
3491
3494
  });
3492
- const result = await runMiddleware(getPagesRunner(), capturedMiddlewarePath, middlewareRequest, nextConfig?.i18n, nextConfig?.basePath, nextConfig?.trailingSlash, opts.isDataRequest, pathname, opts.isStaleDataRequest, nextConfig?.skipTrailingSlashRedirect);
3495
+ const result = await runMiddleware(getPagesRunner(), capturedMiddlewarePath, middlewareRequest, nextConfig?.i18n, nextConfig?.basePath, nextConfig?.trailingSlash, opts.isDataRequest, pathname, opts.isStaleDataRequest, nextConfig?.skipTrailingSlashRedirect, opts.restoreLocaleRootTrailingSlash);
3493
3496
  if (hasAppDir && result.continue) {
3494
3497
  const mwCtxEntries = [];
3495
3498
  if (result.responseHeaders) {
@@ -4120,6 +4123,11 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
4120
4123
  nitroHostRuntime = nitro.options.exportConditions?.includes("workerd") ? "worker" : "node";
4121
4124
  if (!nextConfig) return;
4122
4125
  if (!hasAppDir && !hasPagesDir) return;
4126
+ if (!nitro.options.dev) {
4127
+ const requestTargetPlugin = resolveRuntimeEntryModule("nitro-request-target-plugin");
4128
+ nitro.options.plugins ??= [];
4129
+ if (!nitro.options.plugins.includes(requestTargetPlugin)) nitro.options.plugins.push(requestTargetPlugin);
4130
+ }
4123
4131
  nitroPublicFiles = registerNitroPublicFiles(nitro.options, NITRO_PUBLIC_FILES_PLUGIN, () => scanPublicFiles(root, nitroPublicDir));
4124
4132
  if (resolvedServerExternalPackages.length > 0) nitro.options.traceDeps = [.../* @__PURE__ */ new Set([...nitro.options.traceDeps ?? [], ...resolvedServerExternalPackages])];
4125
4133
  } }
@@ -4266,6 +4274,7 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
4266
4274
  pagesClientAssetsModule = buildPagesClientAssetsModule({
4267
4275
  clientEntry: runtimeMetadata.clientEntryFile ?? void 0,
4268
4276
  appBootstrapPreinitModules: runtimeMetadata.appBootstrapPreinitModules,
4277
+ appBootstrapPreloadModules: runtimeMetadata.appBootstrapPreloadModules,
4269
4278
  appRouteManifestModule: runtimeMetadata.appRouteManifestModule,
4270
4279
  appClientReferenceChunks: runtimeMetadata.appClientReferenceChunks,
4271
4280
  ssrManifest,
@@ -148,9 +148,9 @@ async function resolveInitOptions(args, options = {}) {
148
148
  if (name && platform !== "cloudflare") throw new Error("--name requires --platform=cloudflare.");
149
149
  const explicitPrerender = parsePrerenderArg(args);
150
150
  if (platform === "cloudflare" && platformOptions?.cdnCache === "static-assets" && explicitPrerender === false) throw new Error("--no-prerender cannot be used with --cdn-cache=static-assets, which requires build-time prerendering.");
151
- const supportsWarmCdnCache = platformOptions?.cdnCache === "response-store" || platformOptions?.cdnCache === "workers-cache";
151
+ const supportsWarmCdnCache = platformOptions?.cdnCache !== void 0 && platformOptions.cdnCache !== "none";
152
152
  if (platform === "cloudflare" && !supportsWarmCdnCache) {
153
- if (explicitWarmCdnCache === true) throw new Error("--warm-cache requires --cdn-cache=response-store or workers-cache.");
153
+ if (explicitWarmCdnCache === true) throw new Error("--warm-cache requires a cache: pass --cdn-cache=response-store, workers-cache, data-cache, or static-assets.");
154
154
  }
155
155
  const prerender = platform === "cloudflare" && platformOptions?.cdnCache === "static-assets" ? false : explicitPrerender ?? await resolveInitPrerender(args, options, platform);
156
156
  const warmCdnCache = platform === "cloudflare" && supportsWarmCdnCache ? await resolveInitWarmCdnCache(args, options) : false;
package/dist/init.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import path, { toSlash } from "./deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { detectPackageManager, detectPackageManagerName, detectProject, ensureESModule, findViteConfigPath, hasViteConfig, renameCJSConfigs } from "./utils/project.js";
3
3
  import { compactResourceName, cssModulesConfigSource, findConfigKeepingWorkerName, setupCloudflarePlatform, updateViteConfigForCssModules, usesCommonJsViteConfig, validateCloudflarePlatformSetup } from "./init-cloudflare.js";
4
- import { getReactUpgradeDeps } from "./utils/react-version.js";
4
+ import { findPackageVersion, getReactUpgradeDeps } from "./utils/react-version.js";
5
5
  import { getPluginReactUpgradeDeps } from "./utils/plugin-react-version.js";
6
+ import { createRequire } from "node:module";
6
7
  import fs from "node:fs";
7
8
  import { spawn, spawnSync } from "node:child_process";
8
9
  //#region src/init.ts
@@ -297,6 +298,26 @@ function addDependencyEntries(root, deps, { dev }) {
297
298
  if (added.length > 0) fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
298
299
  return added;
299
300
  }
301
+ /** The spec in the manifest sections `isDepInstalled` reads. */
302
+ function readDeclaredDependency(root, name) {
303
+ try {
304
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
305
+ return pkg.dependencies?.[name] ?? pkg.devDependencies?.[name] ?? pkg.peerDependencies?.[name];
306
+ } catch {
307
+ return;
308
+ }
309
+ }
310
+ /** The declared spec, or the installed version of a package hoisted from elsewhere. */
311
+ function readCurrentDependencyVersion(root, name) {
312
+ const declared = readDeclaredDependency(root, name);
313
+ if (declared !== void 0) return declared;
314
+ try {
315
+ const resolved = createRequire(path.join(root, "package.json")).resolve(name);
316
+ return findPackageVersion(resolved, name) ?? void 0;
317
+ } catch {
318
+ return;
319
+ }
320
+ }
300
321
  /**
301
322
  * Check if react/react-dom need upgrading for react-server-dom-webpack compatibility.
302
323
  *
@@ -578,12 +599,20 @@ async function init(options) {
578
599
  let dependencyInstallNeedsApproval = false;
579
600
  const dependencyEntriesAdded = [];
580
601
  const devDependencyEntriesAdded = [];
602
+ const upgradedFrom = /* @__PURE__ */ new Map();
603
+ const recordUpgrades = (deps) => {
604
+ for (const dep of deps) {
605
+ const { name } = parseDependencySpecifier(dep);
606
+ upgradedFrom.set(name, readCurrentDependencyVersion(root, name));
607
+ }
608
+ };
581
609
  if (isApp) {
582
610
  const reactUpgrade = shouldInstall ? [.../* @__PURE__ */ new Set([...getReactUpgradeDeps(root), ...getReactUpgradeDeps(root, {
583
611
  fromManifest: true,
584
612
  installing: true
585
613
  })])] : getReactUpgradeDeps(root, { fromManifest: true });
586
614
  if (reactUpgrade.length > 0) {
615
+ recordUpgrades(reactUpgrade);
587
616
  console.log(` ${terminalStyle.cyan(terminalStyle.bold("Upgrading dependencies:"))}`);
588
617
  console.log(formatList(reactUpgrade.map((dep) => dep.replace(/@latest$/, "")), " "));
589
618
  try {
@@ -601,6 +630,7 @@ async function init(options) {
601
630
  }
602
631
  const pluginReactUpgrade = getPluginReactUpgradeDeps(root);
603
632
  if (pluginReactUpgrade.length > 0) {
633
+ recordUpgrades(pluginReactUpgrade);
604
634
  console.log(` ${terminalStyle.cyan(terminalStyle.bold("Upgrading devDependencies:"))}`);
605
635
  console.log(formatList(pluginReactUpgrade.map((dep) => dep.replace(/@latest$/, "")), " "));
606
636
  try {
@@ -654,13 +684,20 @@ async function init(options) {
654
684
  if (pmName === "pnpm" && shouldInstall && !dependencyInstallNeedsApproval && !options._exec && hasAutomaticallyIgnoredBuilds(inspectPnpmIgnoredBuilds(root))) dependencyInstallNeedsApproval = true;
655
685
  else if (pmName === "pnpm" && shouldInstall && !dependencyInstallNeedsApproval && options._inspectPnpmIgnoredBuilds && hasAutomaticallyIgnoredBuilds(options._inspectPnpmIgnoredBuilds(root))) dependencyInstallNeedsApproval = true;
656
686
  console.log(` ${terminalStyle.green(terminalStyle.bold("vinext init complete!"))}\n`);
657
- if (dependencyEntriesAdded.length > 0) {
687
+ const addedDependencies = dependencyEntriesAdded.filter((name) => !upgradedFrom.has(name));
688
+ const addedDevDependencies = devDependencyEntriesAdded.filter((name) => !upgradedFrom.has(name));
689
+ if (addedDependencies.length > 0) {
658
690
  console.log(` ${terminalStyle.green("✓")} Added dependencies to dependencies:`);
659
- console.log(formatList(dependencyEntriesAdded, " "));
691
+ console.log(formatList(addedDependencies, " "));
660
692
  }
661
- if (devDependencyEntriesAdded.length > 0) {
693
+ if (addedDevDependencies.length > 0) {
662
694
  console.log(` ${terminalStyle.green("✓")} Added dependencies to devDependencies:`);
663
- console.log(formatList(devDependencyEntriesAdded, " "));
695
+ console.log(formatList(addedDevDependencies, " "));
696
+ }
697
+ for (const [name, from] of upgradedFrom) {
698
+ const to = readDeclaredDependency(root, name);
699
+ if (to === void 0 || to === from) continue;
700
+ console.log(` ${terminalStyle.green("✓")} Upgraded ${name} ${from ?? "(not installed)"} \u2192 ${to}`);
664
701
  }
665
702
  if (dependencyInstallNeedsApproval) console.log(` ${terminalStyle.yellow("!")} Dependency installation is waiting for build-script approval`);
666
703
  if (addedTypeModule) console.log(` ${terminalStyle.green("✓")} Added "type": "module" to package.json`);
@@ -186,10 +186,14 @@ function enhanceApiObjects(req, res, query, body, trustedRevalidateOrigin, allow
186
186
  return this;
187
187
  },
188
188
  json(data) {
189
- this.setHeader("Content-Type", "application/json");
189
+ this.setHeader("Content-Type", "application/json; charset=utf-8");
190
190
  this.end(JSON.stringify(data));
191
191
  },
192
192
  send(data) {
193
+ if (data === null || data === void 0) {
194
+ this.end();
195
+ return;
196
+ }
193
197
  if (this.statusCode === 204 || this.statusCode === 304) {
194
198
  this.removeHeader("Content-Type");
195
199
  this.removeHeader("Content-Length");
@@ -208,8 +212,8 @@ function enhanceApiObjects(req, res, query, body, trustedRevalidateOrigin, allow
208
212
  this.end(data);
209
213
  return;
210
214
  }
211
- if (typeof data === "object" && data !== null) {
212
- this.setHeader("Content-Type", "application/json");
215
+ if (typeof data === "object" || typeof data === "number" || typeof data === "boolean") {
216
+ this.setHeader("Content-Type", "application/json; charset=utf-8");
213
217
  this.end(JSON.stringify(data));
214
218
  } else {
215
219
  if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "text/plain");
@@ -259,11 +263,10 @@ async function handleApiRoute(runner, req, res, url, apiRoutes, nextConfig) {
259
263
  const response = finalizeEdgeApiResponse(handlerResponse, "node");
260
264
  res.statusCode = response.status;
261
265
  res.statusMessage = response.statusText;
262
- const setCookieHeaders = response.headers.getSetCookie();
263
266
  response.headers.forEach((value, name) => {
264
267
  if (name !== "set-cookie") res.setHeader(name, value);
265
268
  });
266
- if (setCookieHeaders.length) res.setHeader("set-cookie", setCookieHeaders);
269
+ for (const cookie of response.headers.getSetCookie()) res.appendHeader("set-cookie", cookie);
267
270
  await writeEdgeApiResponseBody(res, response.body, nextRequest.signal);
268
271
  return true;
269
272
  }
@@ -1,8 +1,5 @@
1
- import { addBasePathToPathname, stripBasePath } from "../utils/base-path.js";
2
1
  import { VINEXT_MOUNTED_LAYOUTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER } from "./headers.js";
3
- import { splitPathnameForRouteMatch } from "../routing/utils.js";
4
2
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
5
- import { matchRoutePattern } from "../routing/route-pattern.js";
6
3
  import { installWindowNext, setWindowNextInternalSourcePage } from "../client/window-next.js";
7
4
  import { retryScrollTo, scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
8
5
  import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, formatRscRequestPath, isRscCompatibilityIdCompatible } from "./app-rsc-cache-busting.js";
@@ -10,36 +7,36 @@ import { clearAppNavigationFailureTarget, installAppNavigationFailureListeners }
10
7
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
11
8
  import "../client/instrumentation-client.js";
12
9
  import { createNavigationRuntimeRouteManifestLoader, getNavigationRuntime, loadNavigationRuntimeRouteManifest, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
10
+ import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
11
+ import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
12
+ import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
13
+ import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
13
14
  import { AppElementsWire } from "./app-elements-wire.js";
14
15
  import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
15
- import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
16
- import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, resolveServerActionOperationLane } from "./app-browser-action-result.js";
17
16
  import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
18
17
  import { isExternalHistoryState, readHistoryStateActiveRoutePaths, readHistoryStatePreviousNextUrl, resolveActiveRoutePaths } from "./app-history-state.js";
19
18
  import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
20
19
  import { stripRscCompletionMetadataResponse } from "./rsc-completion-metadata.js";
21
20
  import { blockDangerousStreamedRscRedirect } from "./app-browser-rsc-redirect.js";
22
21
  import { navigationPlanner } from "./navigation-planner.js";
23
- import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
24
- import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
25
- import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
26
22
  import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, activateNavigationSnapshot, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidateDynamicPrefetchCache, invalidatePrefetchCache, invalidateVisitedResponsePrefetches, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, trackAppRouterNavigationInFlight, useRouter } from "../shims/navigation.js";
27
- import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
23
+ import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, isBfcacheIdentityRetained, setAppElementsRenderedSearch } from "../shims/slot.js";
24
+ import DefaultGlobalError from "../shims/default-global-error.js";
25
+ import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../shims/error-boundary.js";
26
+ import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
27
+ import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, resolveServerActionOperationLane } from "./app-browser-action-result.js";
28
28
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
29
29
  import { createMountedLayoutsHeader, holdsSkippedLayouts } from "./app-mounted-layouts.js";
30
- import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, isBfcacheIdentityRetained, setAppElementsRenderedSearch } from "../shims/slot.js";
31
30
  import { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl } from "./app-browser-state.js";
32
31
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, navigateDocumentDirectly } from "./app-browser-navigation-controller.js";
33
32
  import { createAppRouteTree } from "./app-route-tree.js";
34
33
  import { shouldRecoverSamePathSearchCommitOnResponseCompletion } from "./app-browser-navigation-response.js";
35
- import { createSupplementalRefreshCoordinator, mergeRefreshedParallelSlot, requireCompleteSupplementalRefresh, resolvePersistedSourcePageRefreshes, resolveServerActionSupplementalRefresh, resolveSupplementalRefreshes } from "./app-browser-supplemental-refresh.js";
34
+ import { createSupplementalRefreshCoordinator, mergeRefreshedParallelSlot, requireCompleteSupplementalRefresh, resolvePersistedRefreshInterceptions, resolvePersistedSourcePageRefreshes, resolveServerActionSupplementalRefresh, resolveSupplementalRefreshes } from "./app-browser-supplemental-refresh.js";
36
35
  import { createAppBrowserNavigationAbortCoordinator } from "./app-browser-navigation-abort.js";
37
36
  import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition, resolveFetchedHydrationLocation } from "./app-browser-hydration.js";
38
37
  import { AppBrowserHistoryController } from "./app-browser-history-controller.js";
39
38
  import { createVisitedResponseCacheEntry, deleteAllVisitedResponseCacheEntries, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, findVisitedResponseForFullPrefetch, hasNavigationResponseHistoryLifetime, isVisitedResponseCacheEntryFresh, revokeHistoryRestoreNavigationReuse } from "./app-visited-response-cache.js";
40
39
  import { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition, shouldCommitPopstateUrlWithoutNavigation } from "./app-browser-popstate.js";
41
- import DefaultGlobalError from "../shims/default-global-error.js";
42
- import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../shims/error-boundary.js";
43
40
  import { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, createProdOnRecoverableError } from "./app-browser-error.js";
44
41
  import { createHydrationCachePublication } from "./app-hydration-cache-publication.js";
45
42
  import { peekSettledPrefetchResponseForNavigation, prepareConsumedPrefetchResponseForPublication, preserveCommittedPrefetchExpiry, resolvePrefetchNavigationResponseUrl } from "./app-browser-prefetch-response.js";
@@ -47,8 +44,8 @@ import { canCommitOptimisticRouteTemplate, createOptimisticRouteTemplate, create
47
44
  import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
48
45
  import { Fragment, createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
49
46
  import { createRoot, hydrateRoot } from "react-dom/client";
50
- import { createFromFetch, createFromReadableStream, setServerCallback } from "@vitejs/plugin-rsc/browser";
51
47
  import { flushSync } from "react-dom";
48
+ import { createFromFetch, createFromReadableStream, setServerCallback } from "@vitejs/plugin-rsc/browser";
52
49
  import { hasServerActions, loadServerActionClient } from "virtual:vinext-app-capabilities";
53
50
  //#region src/server/app-browser-entry.ts
54
51
  const HAS_CLIENT_REWRITES = process.env.__VINEXT_HAS_CLIENT_REWRITES !== "false";
@@ -278,36 +275,6 @@ function clearDynamicClientNavigationCaches() {
278
275
  optimisticRouteTemplates.clear();
279
276
  historyController.invalidateRestorableClientState();
280
277
  }
281
- function getMatchedUrlPathname(matchedUrl) {
282
- return new URL(matchedUrl, "https://vinext.local").pathname;
283
- }
284
- function resolvePersistedRefreshInterceptions(state, routeManifest, refreshUrl, requestInterceptionContext) {
285
- if (routeManifest === null) return [];
286
- const refreshPathname = stripBasePath(refreshUrl.pathname, __basePath);
287
- const refreshPathParts = splitPathnameForRouteMatch(refreshPathname);
288
- const resolved = [];
289
- for (const binding of state.slotBindings) {
290
- if (binding.state !== "active" || !binding.activeRouteId) continue;
291
- if (!binding.interceptionId || !binding.interceptionSourceMatchedUrl) continue;
292
- const activeRoute = AppElementsWire.parseElementKey(binding.activeRouteId);
293
- if (activeRoute?.kind !== "route") continue;
294
- const match = routeManifest.segmentGraph.interceptions.get(binding.interceptionId);
295
- if (!match) continue;
296
- const retainedInterception = state.interception?.slotId === binding.slotId && matchRoutePattern(splitPathnameForRouteMatch(getMatchedUrlPathname(state.interception.targetMatchedUrl)), match.targetPatternParts) !== null ? state.interception : null;
297
- const targetPathname = retainedInterception?.targetMatchedUrl ?? activeRoute.path;
298
- const targetParts = splitPathnameForRouteMatch(getMatchedUrlPathname(targetPathname));
299
- if (requestInterceptionContext !== null && state.interception?.slotId === binding.slotId && matchRoutePattern(refreshPathParts, match.targetPatternParts) !== null && matchRoutePattern(targetParts, match.targetPatternParts) !== null) continue;
300
- const targetUrl = new URL(targetPathname, refreshUrl);
301
- targetUrl.pathname = addBasePathToPathname(targetUrl.pathname, __basePath);
302
- targetUrl.search = refreshUrl.search;
303
- resolved.push({
304
- interception: match,
305
- interceptionContext: retainedInterception?.sourceMatchedUrl ?? binding.interceptionSourceMatchedUrl,
306
- targetPathname: `${targetUrl.pathname}${targetUrl.search}`
307
- });
308
- }
309
- return resolved;
310
- }
311
278
  async function fetchPersistedInterceptedSlotRefresh(options) {
312
279
  const headers = createRscRequestHeaders({
313
280
  interceptionContext: options.interceptionContext,
@@ -482,7 +449,13 @@ async function commitSameUrlNavigatePayload(nextElements, actionInitiation, retu
482
449
  if (revalidation !== "none" && routeManifestLoaded) {
483
450
  const refreshUrl = new URL(actionInitiation.href);
484
451
  const requestInterceptionContext = resolveInterceptionContextFromPreviousNextUrl(actionInitiation.routerState.previousNextUrl, __basePath);
485
- const persistedInterceptions = resolvePersistedRefreshInterceptions(actionInitiation.routerState, getBrowserRouteManifest(), refreshUrl, requestInterceptionContext);
452
+ const persistedInterceptions = resolvePersistedRefreshInterceptions({
453
+ basePath: __basePath,
454
+ refreshUrl,
455
+ requestInterceptionContext,
456
+ routeManifest: getBrowserRouteManifest(),
457
+ state: actionInitiation.routerState
458
+ });
486
459
  const sourcePageRefreshes = resolvePersistedSourcePageRefreshes({
487
460
  basePath: __basePath,
488
461
  refreshUrl,
@@ -1094,7 +1067,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1094
1067
  const formState = consumeInitialFormState(getVinextBrowserGlobal());
1095
1068
  const hydrateRootOptions = import.meta.env.DEV && devErrorOverlay ? createVinextHydrateRootOptions({
1096
1069
  formState,
1097
- onCaughtError: invalidateOnCaughtError(createDevOnCaughtError(devErrorOverlay.devOnCaughtError, onUncaughtError)),
1070
+ onCaughtError: invalidateOnCaughtError(createDevOnCaughtError(devErrorOverlay.devOnCaughtError, onUncaughtError, devErrorOverlay.reportRootErrorBoundaryCatch)),
1098
1071
  onUncaughtError
1099
1072
  }) : createVinextHydrateRootOptions({
1100
1073
  formState,
@@ -1195,7 +1168,13 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1195
1168
  const requestInterceptionContext = requestState.interceptionContext;
1196
1169
  const requestPreviousNextUrl = requestState.previousNextUrl;
1197
1170
  const shouldSupplementVisibleBranches = navigationKind === "refresh" || navigationKind === "traverse" && !reuseCurrentBfcacheIds;
1198
- const persistedRefreshInterceptions = navigationKind === "refresh" ? resolvePersistedRefreshInterceptions(navigationInitiationState, getBrowserRouteManifest(), url, requestInterceptionContext) : [];
1171
+ const persistedRefreshInterceptions = navigationKind === "refresh" ? resolvePersistedRefreshInterceptions({
1172
+ basePath: __basePath,
1173
+ refreshUrl: url,
1174
+ requestInterceptionContext,
1175
+ routeManifest: getBrowserRouteManifest(),
1176
+ state: navigationInitiationState
1177
+ }) : [];
1199
1178
  const persistedSourcePageRefreshes = shouldSupplementVisibleBranches ? resolvePersistedSourcePageRefreshes({
1200
1179
  activeRoutePaths: navigationKind === "traverse" ? readHistoryStateActiveRoutePaths(activeTraversalIntent?.historyState) ?? [] : void 0,
1201
1180
  basePath: __basePath,
@@ -8,7 +8,7 @@ export declare function createOnUncaughtError(options?: {
8
8
  coerceToError?: boolean;
9
9
  }): HydrateRootErrorHandler;
10
10
  export declare function createProdOnCaughtError(onImplicitRootError: HydrateRootErrorHandler): HydrateRootErrorHandler;
11
- export declare function createDevOnCaughtError(onCaughtError: HydrateRootErrorHandler, onImplicitRootError: HydrateRootErrorHandler): HydrateRootErrorHandler;
11
+ export declare function createDevOnCaughtError(onCaughtError: HydrateRootErrorHandler, onImplicitRootError: HydrateRootErrorHandler, onRootErrorBoundaryCatch?: () => void): HydrateRootErrorHandler;
12
12
  export declare function createProdOnRecoverableError(onReportedError: () => void): (error: unknown) => void;
13
13
  //#endregion
14
14
  export {};
@@ -2,10 +2,18 @@ import { isUnknownRecord } from "../utils/record.js";
2
2
  import { isNavigationSignalError } from "../utils/navigation-signal.js";
3
3
  import { isBailoutToCSRError } from "../shims/navigation-errors.js";
4
4
  //#region src/server/app-browser-error.ts
5
- function isImplicitRootErrorBoundary(errorInfo) {
6
- if (!isUnknownRecord(errorInfo.errorBoundary)) return false;
5
+ function getErrorBoundaryProps(errorInfo) {
6
+ if (!isUnknownRecord(errorInfo.errorBoundary)) return {};
7
7
  const props = errorInfo.errorBoundary.props;
8
- return isUnknownRecord(props) && props.isImplicitRootErrorBoundary === true;
8
+ return isUnknownRecord(props) ? props : {};
9
+ }
10
+ function isImplicitRootErrorBoundary(errorInfo) {
11
+ return getErrorBoundaryProps(errorInfo).isImplicitRootErrorBoundary === true;
12
+ }
13
+ function isRootErrorBoundary(errorInfo) {
14
+ const props = getErrorBoundaryProps(errorInfo);
15
+ if (props.isGlobalErrorBoundary === true) return true;
16
+ return props.isImplicitRootErrorBoundary === true && props.wrapsGlobalErrorBoundary !== true;
9
17
  }
10
18
  function logCaughtError(error, errorInfo) {
11
19
  console.error(error);
@@ -38,8 +46,9 @@ function createProdOnCaughtError(onImplicitRootError) {
38
46
  logCaughtError(error, errorInfo);
39
47
  };
40
48
  }
41
- function createDevOnCaughtError(onCaughtError, onImplicitRootError) {
49
+ function createDevOnCaughtError(onCaughtError, onImplicitRootError, onRootErrorBoundaryCatch) {
42
50
  return (error, errorInfo) => {
51
+ if (!isNavigationSignalError(error) && isRootErrorBoundary(errorInfo)) onRootErrorBoundaryCatch?.();
43
52
  if (isImplicitRootErrorBoundary(errorInfo)) {
44
53
  onImplicitRootError(error, errorInfo);
45
54
  return;
@@ -1,10 +1,10 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { withBasePath } from "../shims/url-utils.js";
3
3
  import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
4
- import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
5
- import { resolveActiveRoutePaths } from "./app-history-state.js";
6
4
  import { claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
5
+ import { resolveActiveRoutePaths } from "./app-history-state.js";
7
6
  import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
7
+ import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
8
8
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit, createPendingNavigationCommitFromElements } from "./app-browser-state.js";
9
9
  import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
10
10
  import { startTransition, useInsertionEffect, useLayoutEffect } from "react";
@@ -2,11 +2,11 @@ import { hasBasePath } from "../utils/base-path.js";
2
2
  import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
3
3
  import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
4
4
  import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl, toPathAbsolutePathname } from "./app-rsc-cache-busting.js";
5
- import { throwOnServerActionNotFound } from "./server-action-not-found.js";
6
5
  import { AppElementsWire } from "./app-elements-wire.js";
7
6
  import "./app-elements.js";
8
- import { createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldSyncServerActionHttpFallbackHead } from "./app-browser-action-result.js";
9
7
  import { parseRenderedPathAndSearchHeader } from "../shims/navigation.js";
8
+ import { throwOnServerActionNotFound } from "./server-action-not-found.js";
9
+ import { createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldSyncServerActionHttpFallbackHead } from "./app-browser-action-result.js";
10
10
  import { resolveServerActionRequestState } from "./app-browser-state.js";
11
11
  import { applyServerActionResultDecision } from "./app-browser-server-action-navigation.js";
12
12
  import { createFromFetch, createTemporaryReferenceSet, encodeReply } from "@vitejs/plugin-rsc/browser";
@@ -6,15 +6,15 @@ import { normalizePath } from "./normalize-path.js";
6
6
  import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
7
7
  import { AppElementsWire } from "./app-elements-wire.js";
8
8
  import { getMountedSlotIds, getMountedSlotIdsHeader } from "./app-elements.js";
9
- import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
10
9
  import { createAppOwnedHistoryState, createExternalHistoryStatePreservingMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createHistoryStateWithTreeSnapshotId, isExternalHistoryState, isHistoryStateBfcacheVersionCurrent, readHistoryStateActiveRoutePaths, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveActiveRoutePaths, resolveHistoryTraversalIntent } from "./app-history-state.js";
11
10
  import { NavigationTraceReasonCodes, createNavigationLifecycleTraceFields, createNavigationTrace } from "./navigation-trace.js";
12
11
  import { verifyOperationTokenForCommit } from "./operation-token.js";
13
12
  import { navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts } from "./navigation-planner.js";
14
13
  import { createSnapshotPathAndSearch } from "../shims/navigation.js";
14
+ import { bindAppElementsRenderedSearch } from "../shims/slot.js";
15
+ import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
15
16
  import { holdsSkippedLayouts } from "./app-mounted-layouts.js";
16
17
  import { createCacheEntryReuseProof } from "./cache-proof.js";
17
- import { bindAppElementsRenderedSearch } from "../shims/slot.js";
18
18
  //#region src/server/app-browser-state.ts
19
19
  const COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "committed-cache" };
20
20
  const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "fresh" };