vinext 0.0.41 → 0.0.42

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 (162) hide show
  1. package/README.md +0 -1
  2. package/dist/build/client-build-config.d.ts +119 -0
  3. package/dist/build/client-build-config.js +149 -0
  4. package/dist/build/client-build-config.js.map +1 -0
  5. package/dist/build/layout-classification-types.d.ts +62 -0
  6. package/dist/build/layout-classification-types.js +1 -0
  7. package/dist/build/layout-classification.d.ts +60 -0
  8. package/dist/build/layout-classification.js +98 -0
  9. package/dist/build/layout-classification.js.map +1 -0
  10. package/dist/build/report.d.ts +15 -1
  11. package/dist/build/report.js +50 -1
  12. package/dist/build/report.js.map +1 -1
  13. package/dist/build/route-classification-manifest.d.ts +53 -0
  14. package/dist/build/route-classification-manifest.js +145 -0
  15. package/dist/build/route-classification-manifest.js.map +1 -0
  16. package/dist/build/run-prerender.js +1 -1
  17. package/dist/build/ssr-manifest.d.ts +19 -0
  18. package/dist/build/ssr-manifest.js +71 -0
  19. package/dist/build/ssr-manifest.js.map +1 -0
  20. package/dist/check.js +2 -2
  21. package/dist/check.js.map +1 -1
  22. package/dist/cli.js +1 -1
  23. package/dist/client/entry.js +1 -1
  24. package/dist/config/config-matchers.js +1 -0
  25. package/dist/config/config-matchers.js.map +1 -1
  26. package/dist/entries/app-rsc-entry.js +287 -95
  27. package/dist/entries/app-rsc-entry.js.map +1 -1
  28. package/dist/index.d.ts +1 -169
  29. package/dist/index.js +112 -432
  30. package/dist/index.js.map +1 -1
  31. package/dist/plugins/fonts.d.ts +49 -1
  32. package/dist/plugins/fonts.js +96 -3
  33. package/dist/plugins/fonts.js.map +1 -1
  34. package/dist/plugins/postcss.d.ts +27 -0
  35. package/dist/plugins/postcss.js +94 -0
  36. package/dist/plugins/postcss.js.map +1 -0
  37. package/dist/plugins/strip-server-exports.d.ts +14 -0
  38. package/dist/plugins/strip-server-exports.js +73 -0
  39. package/dist/plugins/strip-server-exports.js.map +1 -0
  40. package/dist/routing/app-router.d.ts +6 -4
  41. package/dist/routing/app-router.js +21 -22
  42. package/dist/routing/app-router.js.map +1 -1
  43. package/dist/server/app-browser-entry.js +235 -97
  44. package/dist/server/app-browser-entry.js.map +1 -1
  45. package/dist/server/app-browser-error.d.ts +8 -0
  46. package/dist/server/app-browser-error.js +9 -0
  47. package/dist/server/app-browser-error.js.map +1 -0
  48. package/dist/server/app-browser-state.d.ts +93 -0
  49. package/dist/server/app-browser-state.js +132 -0
  50. package/dist/server/app-browser-state.js.map +1 -0
  51. package/dist/server/app-elements.d.ts +92 -0
  52. package/dist/server/app-elements.js +122 -0
  53. package/dist/server/app-elements.js.map +1 -0
  54. package/dist/server/app-page-boundary-render.d.ts +2 -1
  55. package/dist/server/app-page-boundary-render.js +40 -1
  56. package/dist/server/app-page-boundary-render.js.map +1 -1
  57. package/dist/server/app-page-cache.d.ts +6 -3
  58. package/dist/server/app-page-cache.js +14 -8
  59. package/dist/server/app-page-cache.js.map +1 -1
  60. package/dist/server/app-page-execution.d.ts +36 -3
  61. package/dist/server/app-page-execution.js +50 -10
  62. package/dist/server/app-page-execution.js.map +1 -1
  63. package/dist/server/app-page-probe.d.ts +10 -4
  64. package/dist/server/app-page-probe.js +24 -15
  65. package/dist/server/app-page-probe.js.map +1 -1
  66. package/dist/server/app-page-render.d.ts +7 -4
  67. package/dist/server/app-page-render.js +13 -4
  68. package/dist/server/app-page-render.js.map +1 -1
  69. package/dist/server/app-page-request.d.ts +52 -4
  70. package/dist/server/app-page-request.js +86 -16
  71. package/dist/server/app-page-request.js.map +1 -1
  72. package/dist/server/app-page-response.d.ts +1 -0
  73. package/dist/server/app-page-response.js +1 -0
  74. package/dist/server/app-page-response.js.map +1 -1
  75. package/dist/server/app-page-route-wiring.d.ts +22 -8
  76. package/dist/server/app-page-route-wiring.js +219 -83
  77. package/dist/server/app-page-route-wiring.js.map +1 -1
  78. package/dist/server/app-render-dependency.d.ts +13 -0
  79. package/dist/server/app-render-dependency.js +35 -0
  80. package/dist/server/app-render-dependency.js.map +1 -0
  81. package/dist/server/app-route-handler-execution.d.ts +1 -0
  82. package/dist/server/app-route-handler-execution.js +1 -0
  83. package/dist/server/app-route-handler-execution.js.map +1 -1
  84. package/dist/server/app-route-handler-runtime.d.ts +1 -0
  85. package/dist/server/app-route-handler-runtime.js +26 -1
  86. package/dist/server/app-route-handler-runtime.js.map +1 -1
  87. package/dist/server/app-ssr-entry.js +6 -2
  88. package/dist/server/app-ssr-entry.js.map +1 -1
  89. package/dist/server/dev-server.js +2 -4
  90. package/dist/server/dev-server.js.map +1 -1
  91. package/dist/server/middleware.js +1 -5
  92. package/dist/server/middleware.js.map +1 -1
  93. package/dist/server/prod-server.d.ts +3 -3
  94. package/dist/server/prod-server.js +1 -1
  95. package/dist/server/prod-server.js.map +1 -1
  96. package/dist/server/request-pipeline.d.ts +2 -1
  97. package/dist/server/request-pipeline.js +34 -5
  98. package/dist/server/request-pipeline.js.map +1 -1
  99. package/dist/shims/cache-runtime.d.ts +1 -0
  100. package/dist/shims/cache-runtime.js +0 -5
  101. package/dist/shims/cache-runtime.js.map +1 -1
  102. package/dist/shims/cache.d.ts +1 -0
  103. package/dist/shims/cache.js +1 -8
  104. package/dist/shims/cache.js.map +1 -1
  105. package/dist/shims/client-hook-error.d.ts +14 -0
  106. package/dist/shims/client-hook-error.js +19 -0
  107. package/dist/shims/client-hook-error.js.map +1 -0
  108. package/dist/shims/constants.d.ts +3 -3
  109. package/dist/shims/constants.js +3 -3
  110. package/dist/shims/constants.js.map +1 -1
  111. package/dist/shims/document.d.ts +6 -6
  112. package/dist/shims/error-boundary.d.ts +4 -4
  113. package/dist/shims/error-boundary.js +1 -1
  114. package/dist/shims/error-boundary.js.map +1 -1
  115. package/dist/shims/form.d.ts +3 -3
  116. package/dist/shims/head-state.d.ts +1 -0
  117. package/dist/shims/head-state.js +0 -5
  118. package/dist/shims/head-state.js.map +1 -1
  119. package/dist/shims/headers.d.ts +11 -0
  120. package/dist/shims/headers.js +13 -10
  121. package/dist/shims/headers.js.map +1 -1
  122. package/dist/shims/i18n-state.d.ts +1 -0
  123. package/dist/shims/i18n-state.js +0 -4
  124. package/dist/shims/i18n-state.js.map +1 -1
  125. package/dist/shims/internal/app-router-context.d.ts +6 -6
  126. package/dist/shims/internal/router-context.d.ts +2 -2
  127. package/dist/shims/layout-segment-context.d.ts +2 -2
  128. package/dist/shims/link.js +19 -11
  129. package/dist/shims/link.js.map +1 -1
  130. package/dist/shims/metadata.d.ts +3 -3
  131. package/dist/shims/navigation-state.d.ts +2 -0
  132. package/dist/shims/navigation-state.js +0 -13
  133. package/dist/shims/navigation-state.js.map +1 -1
  134. package/dist/shims/navigation.d.ts +55 -8
  135. package/dist/shims/navigation.js +97 -23
  136. package/dist/shims/navigation.js.map +1 -1
  137. package/dist/shims/navigation.react-server.d.ts +14 -0
  138. package/dist/shims/navigation.react-server.js +29 -0
  139. package/dist/shims/navigation.react-server.js.map +1 -0
  140. package/dist/shims/request-context.d.ts +1 -0
  141. package/dist/shims/request-context.js +0 -9
  142. package/dist/shims/request-context.js.map +1 -1
  143. package/dist/shims/request-state-types.d.ts +1 -1
  144. package/dist/shims/router-state.d.ts +1 -0
  145. package/dist/shims/router-state.js +0 -5
  146. package/dist/shims/router-state.js.map +1 -1
  147. package/dist/shims/slot.d.ts +11 -7
  148. package/dist/shims/slot.js +28 -19
  149. package/dist/shims/slot.js.map +1 -1
  150. package/dist/shims/unified-request-context.d.ts +2 -0
  151. package/dist/shims/unified-request-context.js +0 -14
  152. package/dist/shims/unified-request-context.js.map +1 -1
  153. package/dist/utils/mdx-scan.d.ts +10 -0
  154. package/dist/utils/mdx-scan.js +36 -0
  155. package/dist/utils/mdx-scan.js.map +1 -0
  156. package/dist/utils/public-routes.d.ts +5 -0
  157. package/dist/utils/public-routes.js +50 -0
  158. package/dist/utils/public-routes.js.map +1 -0
  159. package/package.json +3 -3
  160. package/dist/plugins/fix-use-server-closure-collision.d.ts +0 -29
  161. package/dist/plugins/fix-use-server-closure-collision.js +0 -204
  162. package/dist/plugins/fix-use-server-closure-collision.js.map +0 -1
@@ -15,6 +15,7 @@ import fs from "node:fs";
15
15
  */
16
16
  const configMatchersPath = resolveEntryPath("../config/config-matchers.js", import.meta.url);
17
17
  const requestPipelinePath = resolveEntryPath("../server/request-pipeline.js", import.meta.url);
18
+ const middlewareRequestHeadersPath = resolveEntryPath("../server/middleware-request-headers.js", import.meta.url);
18
19
  const requestContextShimPath = resolveEntryPath("../shims/request-context.js", import.meta.url);
19
20
  const normalizePathModulePath = resolveEntryPath("../server/normalize-path.js", import.meta.url);
20
21
  const appRouteHandlerRuntimePath = resolveEntryPath("../server/app-route-handler-runtime.js", import.meta.url);
@@ -24,6 +25,7 @@ const appRouteHandlerCachePath = resolveEntryPath("../server/app-route-handler-c
24
25
  const appPageCachePath = resolveEntryPath("../server/app-page-cache.js", import.meta.url);
25
26
  const appPageExecutionPath = resolveEntryPath("../server/app-page-execution.js", import.meta.url);
26
27
  const appPageBoundaryRenderPath = resolveEntryPath("../server/app-page-boundary-render.js", import.meta.url);
28
+ const appElementsPath = resolveEntryPath("../server/app-elements.js", import.meta.url);
27
29
  const appPageRouteWiringPath = resolveEntryPath("../server/app-page-route-wiring.js", import.meta.url);
28
30
  const appPageRenderPath = resolveEntryPath("../server/app-page-render.js", import.meta.url);
29
31
  const appPageResponsePath = resolveEntryPath("../server/app-page-response.js", import.meta.url);
@@ -69,7 +71,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
69
71
  if (route.pagePath) getImportVar(route.pagePath);
70
72
  if (route.routePath) getImportVar(route.routePath);
71
73
  for (const layout of route.layouts) getImportVar(layout);
72
- for (const tmpl of route.templates) if (tmpl) getImportVar(tmpl);
74
+ for (const tmpl of route.templates) getImportVar(tmpl);
73
75
  if (route.loadingPath) getImportVar(route.loadingPath);
74
76
  if (route.errorPath) getImportVar(route.errorPath);
75
77
  if (route.layoutErrorPaths) {
@@ -88,9 +90,9 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
88
90
  for (const ir of slot.interceptingRoutes) getImportVar(ir.pagePath);
89
91
  }
90
92
  }
91
- const routeEntries = routes.map((route) => {
93
+ const routeEntries = routes.map((route, routeIdx) => {
92
94
  const layoutVars = route.layouts.map((l) => getImportVar(l));
93
- const templateVars = route.templates.map((t) => t ? getImportVar(t) : "null");
95
+ const templateVars = route.templates.map((t) => getImportVar(t));
94
96
  const notFoundVars = (route.notFoundPaths || []).map((nf) => nf ? getImportVar(nf) : "null");
95
97
  const slotEntries = route.parallelSlots.map((slot) => {
96
98
  const interceptEntries = slot.interceptingRoutes.map((ir) => ` {
@@ -99,7 +101,8 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
99
101
  page: ${getImportVar(ir.pagePath)},
100
102
  params: ${JSON.stringify(ir.params)},
101
103
  }`);
102
- return ` ${JSON.stringify(slot.name)}: {
104
+ return ` ${JSON.stringify(slot.key)}: {
105
+ name: ${JSON.stringify(slot.name)},
103
106
  page: ${slot.pagePath ? getImportVar(slot.pagePath) : "null"},
104
107
  default: ${slot.defaultPath ? getImportVar(slot.defaultPath) : "null"},
105
108
  layout: ${slot.layoutPath ? getImportVar(slot.layoutPath) : "null"},
@@ -114,6 +117,8 @@ ${interceptEntries.join(",\n")}
114
117
  });
115
118
  const layoutErrorVars = (route.layoutErrorPaths || []).map((ep) => ep ? getImportVar(ep) : "null");
116
119
  return ` {
120
+ __buildTimeClassifications: __VINEXT_CLASS(${routeIdx}), // evaluated once at module load
121
+ __buildTimeReasons: __classDebug ? __VINEXT_CLASS_REASONS(${routeIdx}) : null,
117
122
  pattern: ${JSON.stringify(route.pattern)},
118
123
  patternParts: ${JSON.stringify(route.patternParts)},
119
124
  isDynamic: ${route.isDynamic},
@@ -122,6 +127,7 @@ ${interceptEntries.join(",\n")}
122
127
  routeHandler: ${route.routePath ? getImportVar(route.routePath) : "null"},
123
128
  layouts: [${layoutVars.join(", ")}],
124
129
  routeSegments: ${JSON.stringify(route.routeSegments)},
130
+ templateTreePositions: ${JSON.stringify(route.templateTreePositions)},
125
131
  layoutTreePositions: ${JSON.stringify(route.layoutTreePositions)},
126
132
  templates: [${templateVars.join(", ")}],
127
133
  errors: [${layoutErrorVars.join(", ")}],
@@ -219,6 +225,7 @@ ${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(inst
219
225
  ${effectiveMetaRoutes.length > 0 ? `import { sitemapToXml, robotsToText, manifestToJson } from ${JSON.stringify(metadataRoutesPath)};` : ""}
220
226
  import { requestContextFromRequest, normalizeHost, matchRedirect, matchRewrite, matchHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination } from ${JSON.stringify(configMatchersPath)};
221
227
  import { decodePathParams as __decodePathParams } from ${JSON.stringify(normalizePathModulePath)};
228
+ import { buildRequestHeadersFromMiddlewareResponse as __buildRequestHeadersFromMiddlewareResponse } from ${JSON.stringify(middlewareRequestHeadersPath)};
222
229
  import { validateCsrfOrigin, validateServerActionPayload, validateImageUrl, guardProtocolRelativeUrl, hasBasePath, stripBasePath, normalizeTrailingSlash, processMiddlewareHeaders } from ${JSON.stringify(requestPipelinePath)};
223
230
  import {
224
231
  isKnownDynamicAppRoute as __isKnownDynamicAppRoute,
@@ -246,7 +253,12 @@ import {
246
253
  renderAppPageHttpAccessFallback as __renderAppPageHttpAccessFallback,
247
254
  } from ${JSON.stringify(appPageBoundaryRenderPath)};
248
255
  import {
249
- buildAppPageRouteElement as __buildAppPageRouteElement,
256
+ APP_INTERCEPTION_CONTEXT_KEY as __APP_INTERCEPTION_CONTEXT_KEY,
257
+ createAppPayloadRouteId as __createAppPayloadRouteId,
258
+ } from ${JSON.stringify(appElementsPath)};
259
+ import {
260
+ buildAppPageElements as __buildAppPageElements,
261
+ createAppPageTreePath as __createAppPageTreePath,
250
262
  resolveAppPageChildSegments as __resolveAppPageChildSegments,
251
263
  } from ${JSON.stringify(appPageRouteWiringPath)};
252
264
  import {
@@ -257,6 +269,7 @@ import {
257
269
  } from ${JSON.stringify(appPageResponsePath)};
258
270
  import { getScriptNonceFromHeaderSources as __getScriptNonceFromHeaderSources } from ${JSON.stringify(cspPath)};
259
271
  import {
272
+ resolveAppPageActionRerenderTarget as __resolveAppPageActionRerenderTarget,
260
273
  buildAppPageElement as __buildAppPageElement,
261
274
  resolveAppPageIntercept as __resolveAppPageIntercept,
262
275
  validateAppPageDynamicParams as __validateAppPageDynamicParams,
@@ -397,7 +410,21 @@ function __isrCacheKey(pathname, suffix) {
397
410
  return prefix + ":__hash:" + __isrFnv1a64(normalized) + ":" + suffix;
398
411
  }
399
412
  function __isrHtmlKey(pathname) { return __isrCacheKey(pathname, "html"); }
400
- function __isrRscKey(pathname) { return __isrCacheKey(pathname, "rsc"); }
413
+ function __isrRscKey(pathname, mountedSlotsHeader) {
414
+ if (!mountedSlotsHeader) return __isrCacheKey(pathname, "rsc");
415
+ return __isrCacheKey(pathname, "rsc:" + __isrFnv1a64(mountedSlotsHeader));
416
+ }
417
+ function __normalizeMountedSlotsHeader(raw) {
418
+ if (!raw) return null;
419
+ const normalized = Array.from(
420
+ new Set(
421
+ raw
422
+ .split(/\\s+/)
423
+ .filter(Boolean),
424
+ ),
425
+ ).sort().join(" ");
426
+ return normalized || null;
427
+ }
401
428
  function __isrRouteKey(pathname) { return __isrCacheKey(pathname, "route"); }
402
429
  // Verbose cache logging — opt in with NEXT_PRIVATE_DEBUG_CACHE=1.
403
430
  // Matches the env var Next.js uses for its own cache debug output so operators
@@ -406,6 +433,16 @@ const __isrDebug = process.env.NEXT_PRIVATE_DEBUG_CACHE
406
433
  ? console.debug.bind(console, "[vinext] ISR:")
407
434
  : undefined;
408
435
 
436
+ // Classification debug — opt in with VINEXT_DEBUG_CLASSIFICATION=1. Gated on
437
+ // the env var so the hot path pays no overhead unless an operator is actively
438
+ // tracing why a layout was flagged static or dynamic. The reason payload is
439
+ // carried by __VINEXT_CLASS_REASONS and consumed inside probeAppPageLayouts.
440
+ const __classDebug = process.env.VINEXT_DEBUG_CLASSIFICATION
441
+ ? function(layoutId, reason) {
442
+ console.debug("[vinext] CLS:", layoutId, reason);
443
+ }
444
+ : undefined;
445
+
409
446
  // Normalize null-prototype objects from matchPattern() into thenable objects
410
447
  // that work both as Promises (for Next.js 15+ async params) and as plain
411
448
  // objects with synchronous property access (for pre-15 code like params.id).
@@ -574,6 +611,24 @@ async function __ensureInstrumentation() {
574
611
  return __instrumentationInitPromise;
575
612
  }` : ""}
576
613
 
614
+ // Build-time layout classification dispatch. Replaced in generateBundle
615
+ // with a switch statement that returns a pre-computed per-layout
616
+ // Map<layoutIndex, "static" | "dynamic"> for each route. Until the
617
+ // plugin patches this stub, every route falls back to the Layer 3
618
+ // runtime probe, which is the current (slow) behaviour.
619
+ function __VINEXT_CLASS(routeIdx) {
620
+ return null;
621
+ }
622
+
623
+ // Build-time layout classification reasons dispatch. Sibling of
624
+ // __VINEXT_CLASS, returning a per-route Map<layoutIndex, ClassificationReason>
625
+ // that feeds the debug channel when VINEXT_DEBUG_CLASSIFICATION is active.
626
+ // Replaced in generateBundle with a real dispatch table; the stub returns
627
+ // null so the hot path never allocates reason maps when debug is off.
628
+ function __VINEXT_CLASS_REASONS(routeIdx) {
629
+ return null;
630
+ }
631
+
577
632
  const routes = [
578
633
  ${routeEntries.join(",\n")}
579
634
  ];
@@ -731,17 +786,17 @@ function matchPattern(urlParts, patternParts) {
731
786
  }
732
787
 
733
788
  // Build a global intercepting route lookup for RSC navigation.
734
- // Maps target URL patterns to { sourceRouteIndex, slotName, interceptPage, params }.
789
+ // Maps target URL patterns to { sourceRouteIndex, slotKey, interceptPage, params }.
735
790
  const interceptLookup = [];
736
791
  for (let ri = 0; ri < routes.length; ri++) {
737
792
  const r = routes[ri];
738
793
  if (!r.slots) continue;
739
- for (const [slotName, slotMod] of Object.entries(r.slots)) {
794
+ for (const [slotKey, slotMod] of Object.entries(r.slots)) {
740
795
  if (!slotMod.intercepts) continue;
741
796
  for (const intercept of slotMod.intercepts) {
742
797
  interceptLookup.push({
743
798
  sourceRouteIndex: ri,
744
- slotName,
799
+ slotKey,
745
800
  targetPattern: intercept.targetPattern,
746
801
  targetPatternParts: intercept.targetPattern.split("/").filter(Boolean),
747
802
  page: intercept.page,
@@ -766,10 +821,31 @@ function findIntercept(pathname) {
766
821
  return null;
767
822
  }
768
823
 
769
- async function buildPageElement(route, params, opts, searchParams) {
824
+ async function buildPageElements(route, params, routePath, pageRequest) {
825
+ const {
826
+ opts,
827
+ searchParams,
828
+ isRscRequest,
829
+ request,
830
+ mountedSlotsHeader,
831
+ } = pageRequest;
770
832
  const PageComponent = route.page?.default;
771
833
  if (!PageComponent) {
772
- return createElement("div", null, "Page has no default export");
834
+ const _interceptionContext = opts?.interceptionContext ?? null;
835
+ const _noExportRouteId = __createAppPayloadRouteId(routePath, _interceptionContext);
836
+ let _noExportRootLayout = null;
837
+ if (route.layouts?.length > 0) {
838
+ // Compute the root layout tree path for this error payload using the
839
+ // canonical helper so it stays aligned with buildAppPageElements().
840
+ const _tp = route.layoutTreePositions?.[0] ?? 0;
841
+ _noExportRootLayout = __createAppPageTreePath(route.routeSegments, _tp);
842
+ }
843
+ return {
844
+ [__APP_INTERCEPTION_CONTEXT_KEY]: _interceptionContext,
845
+ __route: _noExportRouteId,
846
+ __rootLayout: _noExportRootLayout,
847
+ [_noExportRouteId]: createElement("div", null, "Page has no default export"),
848
+ };
773
849
  }
774
850
 
775
851
  // Resolve metadata and viewport from layouts and page.
@@ -798,6 +874,24 @@ async function buildPageElement(route, params, opts, searchParams) {
798
874
  // route it to the nearest error.tsx boundary (or global-error.tsx).
799
875
  const layoutMods = route.layouts.filter(Boolean);
800
876
 
877
+ // Convert URLSearchParams → plain object for page generateMetadata() and
878
+ // pageProps.searchParams. Built before the layout loop so the page metadata
879
+ // call (below) and pageProps can reference the same object.
880
+ // NOTE: Layouts do NOT receive searchParams in generateMetadata() — only
881
+ // pages do. This matches Next.js behavior (resolve-metadata.ts:777).
882
+ const spObj = Object.create(null);
883
+ let hasSearchParams = false;
884
+ if (searchParams && searchParams.forEach) {
885
+ searchParams.forEach(function(v, k) {
886
+ hasSearchParams = true;
887
+ if (k in spObj) {
888
+ spObj[k] = Array.isArray(spObj[k]) ? spObj[k].concat(v) : [spObj[k], v];
889
+ } else {
890
+ spObj[k] = v;
891
+ }
892
+ });
893
+ }
894
+
801
895
  // Build the parent promise chain and kick off metadata resolution in one pass.
802
896
  // Each layout module is called exactly once. layoutMetaPromises[i] is the
803
897
  // promise for layout[i]'s own metadata result.
@@ -820,22 +914,6 @@ async function buildPageElement(route, params, opts, searchParams) {
820
914
  // Page's parent is the fully-accumulated layout metadata.
821
915
  const pageParentPromise = accumulatedMetaPromise;
822
916
 
823
- // Convert URLSearchParams → plain object so we can pass it to
824
- // resolveModuleMetadata (which expects Record<string, string | string[]>).
825
- // This same object is reused for pageProps.searchParams below.
826
- const spObj = {};
827
- let hasSearchParams = false;
828
- if (searchParams && searchParams.forEach) {
829
- searchParams.forEach(function(v, k) {
830
- hasSearchParams = true;
831
- if (k in spObj) {
832
- spObj[k] = Array.isArray(spObj[k]) ? spObj[k].concat(v) : [spObj[k], v];
833
- } else {
834
- spObj[k] = v;
835
- }
836
- });
837
- }
838
-
839
917
  const [layoutMetaResults, layoutVpResults, pageMeta, pageVp] = await Promise.all([
840
918
  Promise.all(layoutMetaPromises),
841
919
  Promise.all(layoutMods.map((mod) => resolveModuleViewport(mod, params).catch((err) => { console.error("[vinext] Layout generateViewport() failed:", err); return null; }))),
@@ -867,19 +945,31 @@ async function buildPageElement(route, params, opts, searchParams) {
867
945
  // dynamic, and this avoids false positives from React internals.
868
946
  if (hasSearchParams) markDynamicUsage();
869
947
  }
870
- return __buildAppPageRouteElement({
948
+ // mountedSlotsHeader is threaded through from the handler scope so every
949
+ // call site shares one source of truth for request-derived values. Reading
950
+ // the same header in two places invites silent drift when a future refactor
951
+ // changes only one of them.
952
+ const mountedSlotIds = mountedSlotsHeader
953
+ ? new Set(mountedSlotsHeader.split(" "))
954
+ : null;
955
+
956
+ return __buildAppPageElements({
871
957
  element: createElement(PageComponent, pageProps),
872
958
  globalErrorModule: ${globalErrorVar ? globalErrorVar : "null"},
959
+ isRscRequest,
960
+ mountedSlotIds,
873
961
  makeThenableParams,
874
962
  matchedParams: params,
875
963
  resolvedMetadata,
876
964
  resolvedViewport,
965
+ interceptionContext: opts?.interceptionContext ?? null,
966
+ routePath,
877
967
  rootNotFoundModule: ${rootNotFoundVar ? rootNotFoundVar : "null"},
878
968
  route,
879
969
  slotOverrides:
880
- opts && opts.interceptSlot && opts.interceptPage
970
+ opts && opts.interceptSlotKey && opts.interceptPage
881
971
  ? {
882
- [opts.interceptSlot]: {
972
+ [opts.interceptSlotKey]: {
883
973
  pageModule: opts.interceptPage,
884
974
  params: opts.interceptParams || params,
885
975
  },
@@ -1034,7 +1124,7 @@ export default async function handler(request, ctx) {
1034
1124
  // Per-request container for middleware state. Passed into
1035
1125
  // _handleRequest which fills in .headers and .status;
1036
1126
  // avoids module-level variables that race on Workers.
1037
- const _mwCtx = { headers: null, status: null };
1127
+ const _mwCtx = { headers: null, requestHeaders: null, status: null };
1038
1128
  const response = await _handleRequest(request, __reqCtx, _mwCtx);
1039
1129
  // Apply custom headers from next.config.js to non-redirect responses.
1040
1130
  // Skip redirects (3xx) because Response.redirect() creates immutable headers,
@@ -1198,6 +1288,14 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1198
1288
  }
1199
1289
 
1200
1290
  const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("accept")?.includes("text/x-component");
1291
+ // Read mounted-slots header once at the handler scope and thread it through
1292
+ // every buildPageElements call site. Previously both the handler and
1293
+ // buildPageElements read and normalized it independently, which invited
1294
+ // silent drift if a future refactor changed only one path.
1295
+ const __mountedSlotsHeader = __normalizeMountedSlotsHeader(
1296
+ request.headers.get("x-vinext-mounted-slots"),
1297
+ );
1298
+ const interceptionContextHeader = request.headers.get("X-Vinext-Interception-Context")?.replaceAll("\0", "") || null;
1201
1299
  let cleanPathname = pathname.replace(/\\.rsc$/, "");
1202
1300
 
1203
1301
  // Middleware response headers and custom rewrite status are stored in
@@ -1336,6 +1434,9 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1336
1434
  // be merged into the outgoing HTTP response — this prefix is reserved for
1337
1435
  // internal routing signals and must never reach clients.
1338
1436
  if (_mwCtx.headers) {
1437
+ // Preserve the pre-strip header set so route handlers can reconstruct
1438
+ // a request object with middleware header overrides applied.
1439
+ _mwCtx.requestHeaders = new Headers(_mwCtx.headers);
1339
1440
  applyMiddlewareRequestHeaders(_mwCtx.headers);
1340
1441
  processMiddlewareHeaders(_mwCtx.headers);
1341
1442
  }
@@ -1520,10 +1621,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1520
1621
  returnValue = { ok: true, data };
1521
1622
  } catch (e) {
1522
1623
  // Detect redirect() / permanentRedirect() called inside the action.
1523
- // These throw errors with digest "NEXT_REDIRECT;<type>;<url>[;<status>]".
1524
- // The type field is empty when redirect() was called without an explicit
1525
- // type argument. In Server Action context, Next.js defaults to "push" so
1526
- // the Back button works after form submissions.
1624
+ // These throw errors with digest "NEXT_REDIRECT;replace;url[;status]".
1527
1625
  // The URL is encodeURIComponent-encoded to prevent semicolons in the URL
1528
1626
  // from corrupting the delimiter-based digest format.
1529
1627
  if (e && typeof e === "object" && "digest" in e) {
@@ -1532,7 +1630,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1532
1630
  const parts = digest.split(";");
1533
1631
  actionRedirect = {
1534
1632
  url: decodeURIComponent(parts[2]),
1535
- type: parts[1] || "push", // Server Action → default "push"
1633
+ type: parts[1] || "push", // "push" or "replace"
1536
1634
  status: parts[3] ? parseInt(parts[3], 10) : 307,
1537
1635
  };
1538
1636
  returnValue = { ok: true, data: undefined };
@@ -1569,9 +1667,6 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1569
1667
  "Content-Type": "text/x-component; charset=utf-8",
1570
1668
  "Vary": "RSC, Accept",
1571
1669
  });
1572
- // Merge middleware headers first so the framework's own redirect control
1573
- // headers below are always authoritative and cannot be clobbered by
1574
- // middleware that happens to set x-action-redirect* keys.
1575
1670
  __mergeMiddlewareResponseHeaders(redirectHeaders, _mwCtx.headers);
1576
1671
  redirectHeaders.set("x-action-redirect", actionRedirect.url);
1577
1672
  redirectHeaders.set("x-action-redirect-type", actionRedirect.type);
@@ -1586,24 +1681,71 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1586
1681
 
1587
1682
  // After the action, re-render the current page so the client
1588
1683
  // gets an updated React tree reflecting any mutations.
1684
+ //
1685
+ // When the original request came from inside an intercepted modal
1686
+ // (X-Vinext-Interception-Context present + source route still
1687
+ // matches), rebuild the intercepted tree — otherwise the modal would
1688
+ // unmount and the direct route would render in its place. Mirrors
1689
+ // the interception resolution used by the GET path.
1589
1690
  const match = matchRoute(cleanPathname);
1590
1691
  let element;
1692
+ let errorPattern = match ? match.route.pattern : cleanPathname;
1591
1693
  if (match) {
1592
1694
  const { route: actionRoute, params: actionParams } = match;
1695
+ const __actionRerenderTarget = __resolveAppPageActionRerenderTarget({
1696
+ cleanPathname,
1697
+ currentParams: actionParams,
1698
+ currentRoute: actionRoute,
1699
+ findIntercept,
1700
+ getRouteParamNames(sourceRoute) {
1701
+ return sourceRoute.params;
1702
+ },
1703
+ getSourceRoute(sourceRouteIndex) {
1704
+ return routes[sourceRouteIndex];
1705
+ },
1706
+ isRscRequest,
1707
+ toInterceptOpts(intercept) {
1708
+ return {
1709
+ interceptionContext: interceptionContextHeader,
1710
+ interceptSlotKey: intercept.slotKey,
1711
+ interceptPage: intercept.page,
1712
+ interceptParams: intercept.matchedParams,
1713
+ };
1714
+ },
1715
+ });
1716
+
1593
1717
  setNavigationContext({
1594
1718
  pathname: cleanPathname,
1595
1719
  searchParams: url.searchParams,
1596
- params: actionParams,
1720
+ params: __actionRerenderTarget.navigationParams,
1597
1721
  });
1598
- element = await buildPageElement(actionRoute, actionParams, undefined, url.searchParams);
1722
+ element = buildPageElements(
1723
+ __actionRerenderTarget.route,
1724
+ __actionRerenderTarget.params,
1725
+ cleanPathname,
1726
+ {
1727
+ opts: __actionRerenderTarget.interceptOpts,
1728
+ searchParams: url.searchParams,
1729
+ isRscRequest,
1730
+ request,
1731
+ mountedSlotsHeader: __mountedSlotsHeader,
1732
+ },
1733
+ );
1734
+ errorPattern = __actionRerenderTarget.route.pattern;
1599
1735
  } else {
1600
- element = createElement("div", null, "Page not found");
1736
+ const _actionRouteId = __createAppPayloadRouteId(cleanPathname, null);
1737
+ element = {
1738
+ [__APP_INTERCEPTION_CONTEXT_KEY]: null,
1739
+ __route: _actionRouteId,
1740
+ __rootLayout: null,
1741
+ [_actionRouteId]: createElement("div", null, "Page not found"),
1742
+ };
1601
1743
  }
1602
1744
 
1603
1745
  const onRenderError = createRscOnErrorHandler(
1604
1746
  request,
1605
1747
  cleanPathname,
1606
- match ? match.route.pattern : cleanPathname,
1748
+ errorPattern,
1607
1749
  );
1608
1750
  const rscStream = renderToReadableStream(
1609
1751
  { root: element, returnValue },
@@ -1618,15 +1760,22 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1618
1760
  const actionPendingCookies = getAndClearPendingCookies();
1619
1761
  const actionDraftCookie = getDraftModeCookieHeader();
1620
1762
 
1621
- const actionHeaders = new Headers({ "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" });
1763
+ const actionHeaders = new Headers({
1764
+ "Content-Type": "text/x-component; charset=utf-8",
1765
+ "Vary": "RSC, Accept",
1766
+ });
1622
1767
  __mergeMiddlewareResponseHeaders(actionHeaders, _mwCtx.headers);
1768
+ const actionResponse = new Response(rscStream, {
1769
+ status: _mwCtx.status ?? 200,
1770
+ headers: actionHeaders,
1771
+ });
1623
1772
  if (actionPendingCookies.length > 0 || actionDraftCookie) {
1624
1773
  for (const cookie of actionPendingCookies) {
1625
- actionHeaders.append("Set-Cookie", cookie);
1774
+ actionResponse.headers.append("Set-Cookie", cookie);
1626
1775
  }
1627
- if (actionDraftCookie) actionHeaders.append("Set-Cookie", actionDraftCookie);
1776
+ if (actionDraftCookie) actionResponse.headers.append("Set-Cookie", actionDraftCookie);
1628
1777
  }
1629
- return new Response(rscStream, { status: _mwCtx.status ?? 200, headers: actionHeaders });
1778
+ return actionResponse;
1630
1779
  } catch (err) {
1631
1780
  getAndClearPendingCookies(); // Clear pending cookies on error
1632
1781
  console.error("[vinext] Server action error:", err);
@@ -1686,12 +1835,24 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1686
1835
  if (!isRscRequest) {
1687
1836
  const __pagesEntry = await import.meta.viteRsc.loadModule("ssr", "index");
1688
1837
  if (typeof __pagesEntry.renderPage === "function") {
1838
+ const __pagesRequestHeaders = _mwCtx.requestHeaders
1839
+ ? __buildRequestHeadersFromMiddlewareResponse(request.headers, _mwCtx.requestHeaders)
1840
+ : null;
1841
+ const __pagesRequest = __pagesRequestHeaders
1842
+ ? new Request(request.url, { method: request.method, headers: __pagesRequestHeaders })
1843
+ : request;
1689
1844
  // Use segment-wise decoding to preserve encoded path delimiters (%2F).
1690
1845
  // decodeURIComponent would turn /admin%2Fpanel into /admin/panel,
1691
1846
  // changing the path structure and bypassing middleware matchers.
1692
1847
  // Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts
1693
1848
  // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts
1694
- const __pagesRes = await __pagesEntry.renderPage(request, __decodePathParams(url.pathname) + (url.search || ""), {});
1849
+ const __pagesRes = await __pagesEntry.renderPage(
1850
+ __pagesRequest,
1851
+ __decodePathParams(url.pathname) + (url.search || ""),
1852
+ {},
1853
+ undefined,
1854
+ _mwCtx.requestHeaders,
1855
+ );
1695
1856
  // Only return the Pages Router response if it matched a route
1696
1857
  // (non-404). A 404 means the path isn't a Pages route either,
1697
1858
  // so fall through to the App Router not-found page below.
@@ -1834,6 +1995,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1834
1995
  markDynamicUsage,
1835
1996
  method,
1836
1997
  middlewareContext: _mwCtx,
1998
+ middlewareRequestHeaders: _mwCtx.requestHeaders,
1837
1999
  params: makeThenableParams(params),
1838
2000
  reportRequestError: _reportRequestError,
1839
2001
  request,
@@ -1932,6 +2094,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1932
2094
  isrHtmlKey: __isrHtmlKey,
1933
2095
  isrRscKey: __isrRscKey,
1934
2096
  isrSet: __isrSet,
2097
+ mountedSlotsHeader: __mountedSlotsHeader,
1935
2098
  revalidateSeconds,
1936
2099
  renderFreshPageForCache: async function() {
1937
2100
  // Re-render the page to produce fresh HTML + RSC data for the cache
@@ -1946,7 +2109,21 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1946
2109
  return _runWithUnifiedCtx(__revalUCtx, async () => {
1947
2110
  _ensureFetchPatch();
1948
2111
  setNavigationContext({ pathname: cleanPathname, searchParams: new URLSearchParams(), params });
1949
- const __revalElement = await buildPageElement(route, params, undefined, new URLSearchParams());
2112
+ // Slot context (X-Vinext-Mounted-Slots) is inherited from the
2113
+ // triggering request so the regen result is cached under the
2114
+ // correct slot-variant key.
2115
+ const __revalElement = await buildPageElements(
2116
+ route,
2117
+ params,
2118
+ cleanPathname,
2119
+ {
2120
+ opts: undefined,
2121
+ searchParams: new URLSearchParams(),
2122
+ isRscRequest,
2123
+ request,
2124
+ mountedSlotsHeader: __mountedSlotsHeader,
2125
+ },
2126
+ );
1950
2127
  const __revalOnError = createRscOnErrorHandler(request, cleanPathname, route.pattern);
1951
2128
  const __revalRscStream = renderToReadableStream(__revalElement, { onError: __revalOnError });
1952
2129
  const __revalRscCapture = __teeAppPageRscStreamForCapture(__revalRscStream, true);
@@ -1995,44 +2172,30 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
1995
2172
  // If the target URL matches an intercepting route in a parallel slot,
1996
2173
  // render the source route with the intercepting page in the slot.
1997
2174
  const __interceptResult = await __resolveAppPageIntercept({
1998
- buildPageElement,
2175
+ buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams) {
2176
+ return buildPageElements(
2177
+ interceptRoute,
2178
+ interceptParams,
2179
+ cleanPathname,
2180
+ {
2181
+ opts: interceptOpts,
2182
+ searchParams: interceptSearchParams,
2183
+ isRscRequest,
2184
+ request,
2185
+ mountedSlotsHeader: __mountedSlotsHeader,
2186
+ },
2187
+ );
2188
+ },
1999
2189
  cleanPathname,
2000
2190
  currentRoute: route,
2001
2191
  findIntercept,
2002
- getRoutePattern(sourceRoute) {
2003
- return sourceRoute.pattern;
2192
+ getRouteParamNames(sourceRoute) {
2193
+ return sourceRoute.params;
2004
2194
  },
2005
2195
  getSourceRoute(sourceRouteIndex) {
2006
2196
  return routes[sourceRouteIndex];
2007
2197
  },
2008
2198
  isRscRequest,
2009
- matchSourceRouteParams(pattern) {
2010
- // Extract actual URL param values by prefix-matching the request pathname
2011
- // against the source route's pattern. This handles all interception conventions:
2012
- // (.) same-level, (..) one-level-up, and (...) root — the source pattern's
2013
- // dynamic segments that align with the URL get their real values extracted.
2014
- // We must NOT use matchRoute(pattern) here: the trie would match the literal
2015
- // ":param" strings as dynamic segment values, returning e.g. {id: ":id"}.
2016
- const patternParts = pattern.split("/").filter(Boolean);
2017
- const urlParts = cleanPathname.split("/").filter(Boolean);
2018
- const params = Object.create(null);
2019
- for (let i = 0; i < patternParts.length; i++) {
2020
- const pp = patternParts[i];
2021
- if (pp.endsWith("+") || pp.endsWith("*")) {
2022
- // urlParts.slice(i) safely returns [] when i >= urlParts.length,
2023
- // which is the correct value for optional catch-all with zero segments.
2024
- params[pp.slice(1, -1)] = urlParts.slice(i);
2025
- break;
2026
- }
2027
- if (i >= urlParts.length) break;
2028
- if (pp.startsWith(":")) {
2029
- params[pp.slice(1)] = urlParts[i];
2030
- } else if (pp !== urlParts[i]) {
2031
- break;
2032
- }
2033
- }
2034
- return params;
2035
- },
2036
2199
  renderInterceptResponse(sourceRoute, interceptElement) {
2037
2200
  const interceptOnError = createRscOnErrorHandler(
2038
2201
  request,
@@ -2046,7 +2209,10 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2046
2209
  // by the client, and async server components that run during consumption need the
2047
2210
  // context to still be live. The AsyncLocalStorage scope from runWithRequestContext
2048
2211
  // handles cleanup naturally when all async continuations complete.
2049
- const interceptHeaders = new Headers({ "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" });
2212
+ const interceptHeaders = new Headers({
2213
+ "Content-Type": "text/x-component; charset=utf-8",
2214
+ "Vary": "RSC, Accept",
2215
+ });
2050
2216
  __mergeMiddlewareResponseHeaders(interceptHeaders, _mwCtx.headers);
2051
2217
  return new Response(interceptStream, {
2052
2218
  status: _mwCtx.status ?? 200,
@@ -2057,7 +2223,8 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2057
2223
  setNavigationContext,
2058
2224
  toInterceptOpts(intercept) {
2059
2225
  return {
2060
- interceptSlot: intercept.slotName,
2226
+ interceptionContext: interceptionContextHeader,
2227
+ interceptSlotKey: intercept.slotKey,
2061
2228
  interceptPage: intercept.page,
2062
2229
  interceptParams: intercept.matchedParams,
2063
2230
  };
@@ -2070,7 +2237,13 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2070
2237
 
2071
2238
  const __pageBuildResult = await __buildAppPageElement({
2072
2239
  buildPageElement() {
2073
- return buildPageElement(route, params, interceptOpts, url.searchParams);
2240
+ return buildPageElements(route, params, cleanPathname, {
2241
+ opts: interceptOpts,
2242
+ searchParams: url.searchParams,
2243
+ isRscRequest,
2244
+ request,
2245
+ mountedSlotsHeader: __mountedSlotsHeader,
2246
+ });
2074
2247
  },
2075
2248
  renderErrorBoundaryPage(buildErr) {
2076
2249
  return renderErrorBoundaryPage(route, buildErr, isRscRequest, request, params, _scriptNonce);
@@ -2108,19 +2281,6 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2108
2281
  // rscCssTransform — no manual loadCss() call needed.
2109
2282
  const _hasLoadingBoundary = !!(route.loading && route.loading.default);
2110
2283
  const _asyncLayoutParams = makeThenableParams(params);
2111
- // Convert URLSearchParams to a plain object then wrap in makeThenableParams()
2112
- // so probePage() passes the same shape that buildPageElement() gives to the
2113
- // real render. Without this, pages that destructure await-ed searchParams
2114
- // throw TypeError during probe.
2115
- const _probeSearchObj = {};
2116
- url.searchParams.forEach(function(v, k) {
2117
- if (k in _probeSearchObj) {
2118
- _probeSearchObj[k] = Array.isArray(_probeSearchObj[k]) ? _probeSearchObj[k].concat(v) : [_probeSearchObj[k], v];
2119
- } else {
2120
- _probeSearchObj[k] = v;
2121
- }
2122
- });
2123
- const _asyncSearchParams = makeThenableParams(_probeSearchObj);
2124
2284
  return __renderAppPageLifecycle({
2125
2285
  cleanPathname,
2126
2286
  clearRequestContext() {
@@ -2166,9 +2326,41 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
2166
2326
  return LayoutComp({ params: _asyncLayoutParams, children: null });
2167
2327
  },
2168
2328
  probePage() {
2329
+ const _probeSearchObj = {};
2330
+ url.searchParams.forEach(function(v, k) {
2331
+ if (k in _probeSearchObj) {
2332
+ _probeSearchObj[k] = Array.isArray(_probeSearchObj[k])
2333
+ ? _probeSearchObj[k].concat(v)
2334
+ : [_probeSearchObj[k], v];
2335
+ } else {
2336
+ _probeSearchObj[k] = v;
2337
+ }
2338
+ });
2339
+ const _asyncSearchParams = makeThenableParams(_probeSearchObj);
2169
2340
  return PageComponent({ params: _asyncLayoutParams, searchParams: _asyncSearchParams });
2170
2341
  },
2342
+ classification: {
2343
+ getLayoutId(index) {
2344
+ const tp = route.layoutTreePositions?.[index] ?? 0;
2345
+ return "layout:" + __createAppPageTreePath(route.routeSegments, tp);
2346
+ },
2347
+ buildTimeClassifications: route.__buildTimeClassifications,
2348
+ buildTimeReasons: route.__buildTimeReasons,
2349
+ debugClassification: __classDebug,
2350
+ async runWithIsolatedDynamicScope(fn) {
2351
+ const priorDynamic = consumeDynamicUsage();
2352
+ try {
2353
+ const result = await fn();
2354
+ const dynamicDetected = consumeDynamicUsage();
2355
+ return { result, dynamicDetected };
2356
+ } finally {
2357
+ consumeDynamicUsage();
2358
+ if (priorDynamic) markDynamicUsage();
2359
+ }
2360
+ },
2361
+ },
2171
2362
  revalidateSeconds,
2363
+ mountedSlotsHeader: __mountedSlotsHeader,
2172
2364
  renderErrorBoundaryResponse(renderErr) {
2173
2365
  return renderErrorBoundaryPage(route, renderErr, isRscRequest, request, params, _scriptNonce);
2174
2366
  },