vinext 0.0.41 → 0.0.43
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.
- package/README.md +0 -1
- package/dist/build/client-build-config.d.ts +119 -0
- package/dist/build/client-build-config.js +149 -0
- package/dist/build/client-build-config.js.map +1 -0
- package/dist/build/layout-classification-types.d.ts +62 -0
- package/dist/build/layout-classification-types.js +1 -0
- package/dist/build/layout-classification.d.ts +60 -0
- package/dist/build/layout-classification.js +98 -0
- package/dist/build/layout-classification.js.map +1 -0
- package/dist/build/report.d.ts +15 -1
- package/dist/build/report.js +50 -1
- package/dist/build/report.js.map +1 -1
- package/dist/build/route-classification-manifest.d.ts +53 -0
- package/dist/build/route-classification-manifest.js +145 -0
- package/dist/build/route-classification-manifest.js.map +1 -0
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/ssr-manifest.d.ts +19 -0
- package/dist/build/ssr-manifest.js +71 -0
- package/dist/build/ssr-manifest.js.map +1 -0
- package/dist/check.js +2 -2
- package/dist/check.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/client/entry.js +1 -1
- package/dist/config/config-matchers.js +1 -0
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +315 -101
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/index.d.ts +1 -169
- package/dist/index.js +112 -432
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.d.ts +49 -1
- package/dist/plugins/fonts.js +96 -3
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/postcss.d.ts +27 -0
- package/dist/plugins/postcss.js +94 -0
- package/dist/plugins/postcss.js.map +1 -0
- package/dist/plugins/strip-server-exports.d.ts +14 -0
- package/dist/plugins/strip-server-exports.js +73 -0
- package/dist/plugins/strip-server-exports.js.map +1 -0
- package/dist/routing/app-router.d.ts +6 -4
- package/dist/routing/app-router.js +44 -25
- package/dist/routing/app-router.js.map +1 -1
- package/dist/server/app-browser-entry.js +307 -100
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-error.d.ts +8 -0
- package/dist/server/app-browser-error.js +9 -0
- package/dist/server/app-browser-error.js.map +1 -0
- package/dist/server/app-browser-state.d.ts +93 -0
- package/dist/server/app-browser-state.js +132 -0
- package/dist/server/app-browser-state.js.map +1 -0
- package/dist/server/app-elements.d.ts +92 -0
- package/dist/server/app-elements.js +122 -0
- package/dist/server/app-elements.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +40 -1
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +6 -3
- package/dist/server/app-page-cache.js +14 -8
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +36 -3
- package/dist/server/app-page-execution.js +50 -10
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +10 -4
- package/dist/server/app-page-probe.js +24 -15
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +7 -4
- package/dist/server/app-page-render.js +13 -4
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +52 -4
- package/dist/server/app-page-request.js +86 -16
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +1 -0
- package/dist/server/app-page-response.js +1 -0
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +22 -8
- package/dist/server/app-page-route-wiring.js +219 -83
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-render-dependency.d.ts +13 -0
- package/dist/server/app-render-dependency.js +35 -0
- package/dist/server/app-render-dependency.js.map +1 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-policy.js +5 -3
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.js +2 -0
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +26 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-ssr-entry.js +6 -2
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/dev-server.js +2 -4
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/middleware.js +1 -5
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/prod-server.d.ts +3 -3
- package/dist/server/prod-server.js +1 -1
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +2 -1
- package/dist/server/request-pipeline.js +34 -5
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +1 -0
- package/dist/shims/cache-runtime.js +0 -5
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -8
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/client-hook-error.d.ts +14 -0
- package/dist/shims/client-hook-error.js +19 -0
- package/dist/shims/client-hook-error.js.map +1 -0
- package/dist/shims/constants.d.ts +3 -3
- package/dist/shims/constants.js +3 -3
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/document.d.ts +6 -6
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error-boundary.js +1 -1
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/form.d.ts +3 -3
- package/dist/shims/head-state.d.ts +1 -0
- package/dist/shims/head-state.js +0 -5
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/headers.d.ts +11 -0
- package/dist/shims/headers.js +13 -10
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-state.d.ts +1 -0
- package/dist/shims/i18n-state.js +0 -4
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/internal/app-router-context.d.ts +6 -6
- package/dist/shims/internal/router-context.d.ts +2 -2
- package/dist/shims/layout-segment-context.d.ts +2 -2
- package/dist/shims/link.js +19 -11
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +3 -3
- package/dist/shims/navigation-state.d.ts +2 -0
- package/dist/shims/navigation-state.js +0 -13
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +56 -9
- package/dist/shims/navigation.js +112 -28
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.d.ts +14 -0
- package/dist/shims/navigation.react-server.js +29 -0
- package/dist/shims/navigation.react-server.js.map +1 -0
- package/dist/shims/request-context.d.ts +1 -0
- package/dist/shims/request-context.js +0 -9
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +0 -5
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/slot.d.ts +11 -7
- package/dist/shims/slot.js +28 -19
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +2 -0
- package/dist/shims/unified-request-context.js +0 -14
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/utils/mdx-scan.d.ts +10 -0
- package/dist/utils/mdx-scan.js +36 -0
- package/dist/utils/mdx-scan.js.map +1 -0
- package/dist/utils/public-routes.d.ts +5 -0
- package/dist/utils/public-routes.js +50 -0
- package/dist/utils/public-routes.js.map +1 -0
- package/package.json +3 -3
- package/dist/plugins/fix-use-server-closure-collision.d.ts +0 -29
- package/dist/plugins/fix-use-server-closure-collision.js +0 -204
- 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)
|
|
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) =>
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
];
|
|
@@ -730,18 +785,22 @@ function matchPattern(urlParts, patternParts) {
|
|
|
730
785
|
return params;
|
|
731
786
|
}
|
|
732
787
|
|
|
788
|
+
function mergeMatchedParams(sourceParams, targetParams) {
|
|
789
|
+
return Object.assign(Object.create(null), sourceParams, targetParams);
|
|
790
|
+
}
|
|
791
|
+
|
|
733
792
|
// Build a global intercepting route lookup for RSC navigation.
|
|
734
|
-
// Maps target URL patterns to { sourceRouteIndex,
|
|
793
|
+
// Maps target URL patterns to { sourceRouteIndex, slotKey, interceptPage, params }.
|
|
735
794
|
const interceptLookup = [];
|
|
736
795
|
for (let ri = 0; ri < routes.length; ri++) {
|
|
737
796
|
const r = routes[ri];
|
|
738
797
|
if (!r.slots) continue;
|
|
739
|
-
for (const [
|
|
798
|
+
for (const [slotKey, slotMod] of Object.entries(r.slots)) {
|
|
740
799
|
if (!slotMod.intercepts) continue;
|
|
741
800
|
for (const intercept of slotMod.intercepts) {
|
|
742
801
|
interceptLookup.push({
|
|
743
802
|
sourceRouteIndex: ri,
|
|
744
|
-
|
|
803
|
+
slotKey,
|
|
745
804
|
targetPattern: intercept.targetPattern,
|
|
746
805
|
targetPatternParts: intercept.targetPattern.split("/").filter(Boolean),
|
|
747
806
|
page: intercept.page,
|
|
@@ -755,21 +814,54 @@ for (let ri = 0; ri < routes.length; ri++) {
|
|
|
755
814
|
* Check if a pathname matches any intercepting route.
|
|
756
815
|
* Returns the match info or null.
|
|
757
816
|
*/
|
|
758
|
-
function findIntercept(pathname) {
|
|
817
|
+
function findIntercept(pathname, sourcePathname = null) {
|
|
759
818
|
const urlParts = pathname.split("/").filter(Boolean);
|
|
760
819
|
for (const entry of interceptLookup) {
|
|
761
820
|
const params = matchPattern(urlParts, entry.targetPatternParts);
|
|
762
821
|
if (params !== null) {
|
|
763
|
-
|
|
822
|
+
let sourceParams = Object.create(null);
|
|
823
|
+
if (sourcePathname !== null) {
|
|
824
|
+
const sourceRoute = routes[entry.sourceRouteIndex];
|
|
825
|
+
const sourceParts = sourcePathname.split("/").filter(Boolean);
|
|
826
|
+
const matchedSourceParams = sourceRoute
|
|
827
|
+
? matchPattern(sourceParts, sourceRoute.patternParts)
|
|
828
|
+
: null;
|
|
829
|
+
if (matchedSourceParams !== null) {
|
|
830
|
+
sourceParams = matchedSourceParams;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
return { ...entry, matchedParams: mergeMatchedParams(sourceParams, params) };
|
|
764
834
|
}
|
|
765
835
|
}
|
|
766
836
|
return null;
|
|
767
837
|
}
|
|
768
838
|
|
|
769
|
-
async function
|
|
839
|
+
async function buildPageElements(route, params, routePath, pageRequest) {
|
|
840
|
+
const {
|
|
841
|
+
opts,
|
|
842
|
+
searchParams,
|
|
843
|
+
isRscRequest,
|
|
844
|
+
request,
|
|
845
|
+
mountedSlotsHeader,
|
|
846
|
+
} = pageRequest;
|
|
847
|
+
const hasPageModule = !!route.page;
|
|
770
848
|
const PageComponent = route.page?.default;
|
|
771
|
-
if (!PageComponent) {
|
|
772
|
-
|
|
849
|
+
if (hasPageModule && !PageComponent) {
|
|
850
|
+
const _interceptionContext = opts?.interceptionContext ?? null;
|
|
851
|
+
const _noExportRouteId = __createAppPayloadRouteId(routePath, _interceptionContext);
|
|
852
|
+
let _noExportRootLayout = null;
|
|
853
|
+
if (route.layouts?.length > 0) {
|
|
854
|
+
// Compute the root layout tree path for this error payload using the
|
|
855
|
+
// canonical helper so it stays aligned with buildAppPageElements().
|
|
856
|
+
const _tp = route.layoutTreePositions?.[0] ?? 0;
|
|
857
|
+
_noExportRootLayout = __createAppPageTreePath(route.routeSegments, _tp);
|
|
858
|
+
}
|
|
859
|
+
return {
|
|
860
|
+
[__APP_INTERCEPTION_CONTEXT_KEY]: _interceptionContext,
|
|
861
|
+
__route: _noExportRouteId,
|
|
862
|
+
__rootLayout: _noExportRootLayout,
|
|
863
|
+
[_noExportRouteId]: createElement("div", null, "Page has no default export"),
|
|
864
|
+
};
|
|
773
865
|
}
|
|
774
866
|
|
|
775
867
|
// Resolve metadata and viewport from layouts and page.
|
|
@@ -798,6 +890,24 @@ async function buildPageElement(route, params, opts, searchParams) {
|
|
|
798
890
|
// route it to the nearest error.tsx boundary (or global-error.tsx).
|
|
799
891
|
const layoutMods = route.layouts.filter(Boolean);
|
|
800
892
|
|
|
893
|
+
// Convert URLSearchParams → plain object for page generateMetadata() and
|
|
894
|
+
// pageProps.searchParams. Built before the layout loop so the page metadata
|
|
895
|
+
// call (below) and pageProps can reference the same object.
|
|
896
|
+
// NOTE: Layouts do NOT receive searchParams in generateMetadata() — only
|
|
897
|
+
// pages do. This matches Next.js behavior (resolve-metadata.ts:777).
|
|
898
|
+
const spObj = Object.create(null);
|
|
899
|
+
let hasSearchParams = false;
|
|
900
|
+
if (searchParams && searchParams.forEach) {
|
|
901
|
+
searchParams.forEach(function(v, k) {
|
|
902
|
+
hasSearchParams = true;
|
|
903
|
+
if (k in spObj) {
|
|
904
|
+
spObj[k] = Array.isArray(spObj[k]) ? spObj[k].concat(v) : [spObj[k], v];
|
|
905
|
+
} else {
|
|
906
|
+
spObj[k] = v;
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
|
|
801
911
|
// Build the parent promise chain and kick off metadata resolution in one pass.
|
|
802
912
|
// Each layout module is called exactly once. layoutMetaPromises[i] is the
|
|
803
913
|
// promise for layout[i]'s own metadata result.
|
|
@@ -820,22 +930,6 @@ async function buildPageElement(route, params, opts, searchParams) {
|
|
|
820
930
|
// Page's parent is the fully-accumulated layout metadata.
|
|
821
931
|
const pageParentPromise = accumulatedMetaPromise;
|
|
822
932
|
|
|
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
933
|
const [layoutMetaResults, layoutVpResults, pageMeta, pageVp] = await Promise.all([
|
|
840
934
|
Promise.all(layoutMetaPromises),
|
|
841
935
|
Promise.all(layoutMods.map((mod) => resolveModuleViewport(mod, params).catch((err) => { console.error("[vinext] Layout generateViewport() failed:", err); return null; }))),
|
|
@@ -867,19 +961,31 @@ async function buildPageElement(route, params, opts, searchParams) {
|
|
|
867
961
|
// dynamic, and this avoids false positives from React internals.
|
|
868
962
|
if (hasSearchParams) markDynamicUsage();
|
|
869
963
|
}
|
|
870
|
-
|
|
871
|
-
|
|
964
|
+
// mountedSlotsHeader is threaded through from the handler scope so every
|
|
965
|
+
// call site shares one source of truth for request-derived values. Reading
|
|
966
|
+
// the same header in two places invites silent drift when a future refactor
|
|
967
|
+
// changes only one of them.
|
|
968
|
+
const mountedSlotIds = mountedSlotsHeader
|
|
969
|
+
? new Set(mountedSlotsHeader.split(" "))
|
|
970
|
+
: null;
|
|
971
|
+
|
|
972
|
+
return __buildAppPageElements({
|
|
973
|
+
element: PageComponent ? createElement(PageComponent, pageProps) : null,
|
|
872
974
|
globalErrorModule: ${globalErrorVar ? globalErrorVar : "null"},
|
|
975
|
+
isRscRequest,
|
|
976
|
+
mountedSlotIds,
|
|
873
977
|
makeThenableParams,
|
|
874
978
|
matchedParams: params,
|
|
875
979
|
resolvedMetadata,
|
|
876
980
|
resolvedViewport,
|
|
981
|
+
interceptionContext: opts?.interceptionContext ?? null,
|
|
982
|
+
routePath,
|
|
877
983
|
rootNotFoundModule: ${rootNotFoundVar ? rootNotFoundVar : "null"},
|
|
878
984
|
route,
|
|
879
985
|
slotOverrides:
|
|
880
|
-
opts && opts.
|
|
986
|
+
opts && opts.interceptSlotKey && opts.interceptPage
|
|
881
987
|
? {
|
|
882
|
-
[opts.
|
|
988
|
+
[opts.interceptSlotKey]: {
|
|
883
989
|
pageModule: opts.interceptPage,
|
|
884
990
|
params: opts.interceptParams || params,
|
|
885
991
|
},
|
|
@@ -1034,7 +1140,7 @@ export default async function handler(request, ctx) {
|
|
|
1034
1140
|
// Per-request container for middleware state. Passed into
|
|
1035
1141
|
// _handleRequest which fills in .headers and .status;
|
|
1036
1142
|
// avoids module-level variables that race on Workers.
|
|
1037
|
-
const _mwCtx = { headers: null, status: null };
|
|
1143
|
+
const _mwCtx = { headers: null, requestHeaders: null, status: null };
|
|
1038
1144
|
const response = await _handleRequest(request, __reqCtx, _mwCtx);
|
|
1039
1145
|
// Apply custom headers from next.config.js to non-redirect responses.
|
|
1040
1146
|
// Skip redirects (3xx) because Response.redirect() creates immutable headers,
|
|
@@ -1198,6 +1304,14 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1198
1304
|
}
|
|
1199
1305
|
|
|
1200
1306
|
const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("accept")?.includes("text/x-component");
|
|
1307
|
+
// Read mounted-slots header once at the handler scope and thread it through
|
|
1308
|
+
// every buildPageElements call site. Previously both the handler and
|
|
1309
|
+
// buildPageElements read and normalized it independently, which invited
|
|
1310
|
+
// silent drift if a future refactor changed only one path.
|
|
1311
|
+
const __mountedSlotsHeader = __normalizeMountedSlotsHeader(
|
|
1312
|
+
request.headers.get("x-vinext-mounted-slots"),
|
|
1313
|
+
);
|
|
1314
|
+
const interceptionContextHeader = request.headers.get("X-Vinext-Interception-Context")?.replaceAll("\0", "") || null;
|
|
1201
1315
|
let cleanPathname = pathname.replace(/\\.rsc$/, "");
|
|
1202
1316
|
|
|
1203
1317
|
// Middleware response headers and custom rewrite status are stored in
|
|
@@ -1336,6 +1450,9 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1336
1450
|
// be merged into the outgoing HTTP response — this prefix is reserved for
|
|
1337
1451
|
// internal routing signals and must never reach clients.
|
|
1338
1452
|
if (_mwCtx.headers) {
|
|
1453
|
+
// Preserve the pre-strip header set so route handlers can reconstruct
|
|
1454
|
+
// a request object with middleware header overrides applied.
|
|
1455
|
+
_mwCtx.requestHeaders = new Headers(_mwCtx.headers);
|
|
1339
1456
|
applyMiddlewareRequestHeaders(_mwCtx.headers);
|
|
1340
1457
|
processMiddlewareHeaders(_mwCtx.headers);
|
|
1341
1458
|
}
|
|
@@ -1520,10 +1637,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1520
1637
|
returnValue = { ok: true, data };
|
|
1521
1638
|
} catch (e) {
|
|
1522
1639
|
// Detect redirect() / permanentRedirect() called inside the action.
|
|
1523
|
-
// These throw errors with digest "NEXT_REDIRECT
|
|
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.
|
|
1640
|
+
// These throw errors with digest "NEXT_REDIRECT;replace;url[;status]".
|
|
1527
1641
|
// The URL is encodeURIComponent-encoded to prevent semicolons in the URL
|
|
1528
1642
|
// from corrupting the delimiter-based digest format.
|
|
1529
1643
|
if (e && typeof e === "object" && "digest" in e) {
|
|
@@ -1532,7 +1646,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1532
1646
|
const parts = digest.split(";");
|
|
1533
1647
|
actionRedirect = {
|
|
1534
1648
|
url: decodeURIComponent(parts[2]),
|
|
1535
|
-
type: parts[1] || "push", //
|
|
1649
|
+
type: parts[1] || "push", // "push" or "replace"
|
|
1536
1650
|
status: parts[3] ? parseInt(parts[3], 10) : 307,
|
|
1537
1651
|
};
|
|
1538
1652
|
returnValue = { ok: true, data: undefined };
|
|
@@ -1569,9 +1683,6 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1569
1683
|
"Content-Type": "text/x-component; charset=utf-8",
|
|
1570
1684
|
"Vary": "RSC, Accept",
|
|
1571
1685
|
});
|
|
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
1686
|
__mergeMiddlewareResponseHeaders(redirectHeaders, _mwCtx.headers);
|
|
1576
1687
|
redirectHeaders.set("x-action-redirect", actionRedirect.url);
|
|
1577
1688
|
redirectHeaders.set("x-action-redirect-type", actionRedirect.type);
|
|
@@ -1586,24 +1697,73 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1586
1697
|
|
|
1587
1698
|
// After the action, re-render the current page so the client
|
|
1588
1699
|
// gets an updated React tree reflecting any mutations.
|
|
1700
|
+
//
|
|
1701
|
+
// When the original request came from inside an intercepted modal
|
|
1702
|
+
// (X-Vinext-Interception-Context present + source route still
|
|
1703
|
+
// matches), rebuild the intercepted tree — otherwise the modal would
|
|
1704
|
+
// unmount and the direct route would render in its place. Mirrors
|
|
1705
|
+
// the interception resolution used by the GET path.
|
|
1589
1706
|
const match = matchRoute(cleanPathname);
|
|
1590
1707
|
let element;
|
|
1708
|
+
let errorPattern = match ? match.route.pattern : cleanPathname;
|
|
1591
1709
|
if (match) {
|
|
1592
1710
|
const { route: actionRoute, params: actionParams } = match;
|
|
1711
|
+
const __actionRerenderTarget = __resolveAppPageActionRerenderTarget({
|
|
1712
|
+
cleanPathname,
|
|
1713
|
+
currentParams: actionParams,
|
|
1714
|
+
currentRoute: actionRoute,
|
|
1715
|
+
findIntercept(pathname) {
|
|
1716
|
+
return findIntercept(pathname, interceptionContextHeader);
|
|
1717
|
+
},
|
|
1718
|
+
getRouteParamNames(sourceRoute) {
|
|
1719
|
+
return sourceRoute.params;
|
|
1720
|
+
},
|
|
1721
|
+
getSourceRoute(sourceRouteIndex) {
|
|
1722
|
+
return routes[sourceRouteIndex];
|
|
1723
|
+
},
|
|
1724
|
+
isRscRequest,
|
|
1725
|
+
toInterceptOpts(intercept) {
|
|
1726
|
+
return {
|
|
1727
|
+
interceptionContext: interceptionContextHeader,
|
|
1728
|
+
interceptSlotKey: intercept.slotKey,
|
|
1729
|
+
interceptPage: intercept.page,
|
|
1730
|
+
interceptParams: intercept.matchedParams,
|
|
1731
|
+
};
|
|
1732
|
+
},
|
|
1733
|
+
});
|
|
1734
|
+
|
|
1593
1735
|
setNavigationContext({
|
|
1594
1736
|
pathname: cleanPathname,
|
|
1595
1737
|
searchParams: url.searchParams,
|
|
1596
|
-
params:
|
|
1738
|
+
params: __actionRerenderTarget.navigationParams,
|
|
1597
1739
|
});
|
|
1598
|
-
element =
|
|
1740
|
+
element = buildPageElements(
|
|
1741
|
+
__actionRerenderTarget.route,
|
|
1742
|
+
__actionRerenderTarget.params,
|
|
1743
|
+
cleanPathname,
|
|
1744
|
+
{
|
|
1745
|
+
opts: __actionRerenderTarget.interceptOpts,
|
|
1746
|
+
searchParams: url.searchParams,
|
|
1747
|
+
isRscRequest,
|
|
1748
|
+
request,
|
|
1749
|
+
mountedSlotsHeader: __mountedSlotsHeader,
|
|
1750
|
+
},
|
|
1751
|
+
);
|
|
1752
|
+
errorPattern = __actionRerenderTarget.route.pattern;
|
|
1599
1753
|
} else {
|
|
1600
|
-
|
|
1754
|
+
const _actionRouteId = __createAppPayloadRouteId(cleanPathname, null);
|
|
1755
|
+
element = {
|
|
1756
|
+
[__APP_INTERCEPTION_CONTEXT_KEY]: null,
|
|
1757
|
+
__route: _actionRouteId,
|
|
1758
|
+
__rootLayout: null,
|
|
1759
|
+
[_actionRouteId]: createElement("div", null, "Page not found"),
|
|
1760
|
+
};
|
|
1601
1761
|
}
|
|
1602
1762
|
|
|
1603
1763
|
const onRenderError = createRscOnErrorHandler(
|
|
1604
1764
|
request,
|
|
1605
1765
|
cleanPathname,
|
|
1606
|
-
|
|
1766
|
+
errorPattern,
|
|
1607
1767
|
);
|
|
1608
1768
|
const rscStream = renderToReadableStream(
|
|
1609
1769
|
{ root: element, returnValue },
|
|
@@ -1618,15 +1778,22 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1618
1778
|
const actionPendingCookies = getAndClearPendingCookies();
|
|
1619
1779
|
const actionDraftCookie = getDraftModeCookieHeader();
|
|
1620
1780
|
|
|
1621
|
-
const actionHeaders = new Headers({
|
|
1781
|
+
const actionHeaders = new Headers({
|
|
1782
|
+
"Content-Type": "text/x-component; charset=utf-8",
|
|
1783
|
+
"Vary": "RSC, Accept",
|
|
1784
|
+
});
|
|
1622
1785
|
__mergeMiddlewareResponseHeaders(actionHeaders, _mwCtx.headers);
|
|
1786
|
+
const actionResponse = new Response(rscStream, {
|
|
1787
|
+
status: _mwCtx.status ?? 200,
|
|
1788
|
+
headers: actionHeaders,
|
|
1789
|
+
});
|
|
1623
1790
|
if (actionPendingCookies.length > 0 || actionDraftCookie) {
|
|
1624
1791
|
for (const cookie of actionPendingCookies) {
|
|
1625
|
-
|
|
1792
|
+
actionResponse.headers.append("Set-Cookie", cookie);
|
|
1626
1793
|
}
|
|
1627
|
-
if (actionDraftCookie)
|
|
1794
|
+
if (actionDraftCookie) actionResponse.headers.append("Set-Cookie", actionDraftCookie);
|
|
1628
1795
|
}
|
|
1629
|
-
return
|
|
1796
|
+
return actionResponse;
|
|
1630
1797
|
} catch (err) {
|
|
1631
1798
|
getAndClearPendingCookies(); // Clear pending cookies on error
|
|
1632
1799
|
console.error("[vinext] Server action error:", err);
|
|
@@ -1686,12 +1853,24 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1686
1853
|
if (!isRscRequest) {
|
|
1687
1854
|
const __pagesEntry = await import.meta.viteRsc.loadModule("ssr", "index");
|
|
1688
1855
|
if (typeof __pagesEntry.renderPage === "function") {
|
|
1856
|
+
const __pagesRequestHeaders = _mwCtx.requestHeaders
|
|
1857
|
+
? __buildRequestHeadersFromMiddlewareResponse(request.headers, _mwCtx.requestHeaders)
|
|
1858
|
+
: null;
|
|
1859
|
+
const __pagesRequest = __pagesRequestHeaders
|
|
1860
|
+
? new Request(request.url, { method: request.method, headers: __pagesRequestHeaders })
|
|
1861
|
+
: request;
|
|
1689
1862
|
// Use segment-wise decoding to preserve encoded path delimiters (%2F).
|
|
1690
1863
|
// decodeURIComponent would turn /admin%2Fpanel into /admin/panel,
|
|
1691
1864
|
// changing the path structure and bypassing middleware matchers.
|
|
1692
1865
|
// Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts
|
|
1693
1866
|
// 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(
|
|
1867
|
+
const __pagesRes = await __pagesEntry.renderPage(
|
|
1868
|
+
__pagesRequest,
|
|
1869
|
+
__decodePathParams(url.pathname) + (url.search || ""),
|
|
1870
|
+
{},
|
|
1871
|
+
undefined,
|
|
1872
|
+
_mwCtx.requestHeaders,
|
|
1873
|
+
);
|
|
1695
1874
|
// Only return the Pages Router response if it matched a route
|
|
1696
1875
|
// (non-404). A 404 means the path isn't a Pages route either,
|
|
1697
1876
|
// so fall through to the App Router not-found page below.
|
|
@@ -1834,6 +2013,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1834
2013
|
markDynamicUsage,
|
|
1835
2014
|
method,
|
|
1836
2015
|
middlewareContext: _mwCtx,
|
|
2016
|
+
middlewareRequestHeaders: _mwCtx.requestHeaders,
|
|
1837
2017
|
params: makeThenableParams(params),
|
|
1838
2018
|
reportRequestError: _reportRequestError,
|
|
1839
2019
|
request,
|
|
@@ -1853,8 +2033,9 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1853
2033
|
}
|
|
1854
2034
|
|
|
1855
2035
|
// Build the component tree: layouts wrapping the page
|
|
2036
|
+
const hasPageModule = !!route.page;
|
|
1856
2037
|
const PageComponent = route.page?.default;
|
|
1857
|
-
if (!PageComponent) {
|
|
2038
|
+
if (hasPageModule && !PageComponent) {
|
|
1858
2039
|
setHeadersContext(null);
|
|
1859
2040
|
setNavigationContext(null);
|
|
1860
2041
|
return new Response("Page has no default export", { status: 500 });
|
|
@@ -1932,6 +2113,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1932
2113
|
isrHtmlKey: __isrHtmlKey,
|
|
1933
2114
|
isrRscKey: __isrRscKey,
|
|
1934
2115
|
isrSet: __isrSet,
|
|
2116
|
+
mountedSlotsHeader: __mountedSlotsHeader,
|
|
1935
2117
|
revalidateSeconds,
|
|
1936
2118
|
renderFreshPageForCache: async function() {
|
|
1937
2119
|
// Re-render the page to produce fresh HTML + RSC data for the cache
|
|
@@ -1946,7 +2128,21 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1946
2128
|
return _runWithUnifiedCtx(__revalUCtx, async () => {
|
|
1947
2129
|
_ensureFetchPatch();
|
|
1948
2130
|
setNavigationContext({ pathname: cleanPathname, searchParams: new URLSearchParams(), params });
|
|
1949
|
-
|
|
2131
|
+
// Slot context (X-Vinext-Mounted-Slots) is inherited from the
|
|
2132
|
+
// triggering request so the regen result is cached under the
|
|
2133
|
+
// correct slot-variant key.
|
|
2134
|
+
const __revalElement = await buildPageElements(
|
|
2135
|
+
route,
|
|
2136
|
+
params,
|
|
2137
|
+
cleanPathname,
|
|
2138
|
+
{
|
|
2139
|
+
opts: undefined,
|
|
2140
|
+
searchParams: new URLSearchParams(),
|
|
2141
|
+
isRscRequest,
|
|
2142
|
+
request,
|
|
2143
|
+
mountedSlotsHeader: __mountedSlotsHeader,
|
|
2144
|
+
},
|
|
2145
|
+
);
|
|
1950
2146
|
const __revalOnError = createRscOnErrorHandler(request, cleanPathname, route.pattern);
|
|
1951
2147
|
const __revalRscStream = renderToReadableStream(__revalElement, { onError: __revalOnError });
|
|
1952
2148
|
const __revalRscCapture = __teeAppPageRscStreamForCapture(__revalRscStream, true);
|
|
@@ -1995,44 +2191,32 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1995
2191
|
// If the target URL matches an intercepting route in a parallel slot,
|
|
1996
2192
|
// render the source route with the intercepting page in the slot.
|
|
1997
2193
|
const __interceptResult = await __resolveAppPageIntercept({
|
|
1998
|
-
buildPageElement,
|
|
2194
|
+
buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams) {
|
|
2195
|
+
return buildPageElements(
|
|
2196
|
+
interceptRoute,
|
|
2197
|
+
interceptParams,
|
|
2198
|
+
cleanPathname,
|
|
2199
|
+
{
|
|
2200
|
+
opts: interceptOpts,
|
|
2201
|
+
searchParams: interceptSearchParams,
|
|
2202
|
+
isRscRequest,
|
|
2203
|
+
request,
|
|
2204
|
+
mountedSlotsHeader: __mountedSlotsHeader,
|
|
2205
|
+
},
|
|
2206
|
+
);
|
|
2207
|
+
},
|
|
1999
2208
|
cleanPathname,
|
|
2000
2209
|
currentRoute: route,
|
|
2001
|
-
findIntercept
|
|
2002
|
-
|
|
2003
|
-
|
|
2210
|
+
findIntercept(pathname) {
|
|
2211
|
+
return findIntercept(pathname, interceptionContextHeader);
|
|
2212
|
+
},
|
|
2213
|
+
getRouteParamNames(sourceRoute) {
|
|
2214
|
+
return sourceRoute.params;
|
|
2004
2215
|
},
|
|
2005
2216
|
getSourceRoute(sourceRouteIndex) {
|
|
2006
2217
|
return routes[sourceRouteIndex];
|
|
2007
2218
|
},
|
|
2008
2219
|
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
2220
|
renderInterceptResponse(sourceRoute, interceptElement) {
|
|
2037
2221
|
const interceptOnError = createRscOnErrorHandler(
|
|
2038
2222
|
request,
|
|
@@ -2046,7 +2230,10 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2046
2230
|
// by the client, and async server components that run during consumption need the
|
|
2047
2231
|
// context to still be live. The AsyncLocalStorage scope from runWithRequestContext
|
|
2048
2232
|
// handles cleanup naturally when all async continuations complete.
|
|
2049
|
-
const interceptHeaders = new Headers({
|
|
2233
|
+
const interceptHeaders = new Headers({
|
|
2234
|
+
"Content-Type": "text/x-component; charset=utf-8",
|
|
2235
|
+
"Vary": "RSC, Accept",
|
|
2236
|
+
});
|
|
2050
2237
|
__mergeMiddlewareResponseHeaders(interceptHeaders, _mwCtx.headers);
|
|
2051
2238
|
return new Response(interceptStream, {
|
|
2052
2239
|
status: _mwCtx.status ?? 200,
|
|
@@ -2057,7 +2244,8 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2057
2244
|
setNavigationContext,
|
|
2058
2245
|
toInterceptOpts(intercept) {
|
|
2059
2246
|
return {
|
|
2060
|
-
|
|
2247
|
+
interceptionContext: interceptionContextHeader,
|
|
2248
|
+
interceptSlotKey: intercept.slotKey,
|
|
2061
2249
|
interceptPage: intercept.page,
|
|
2062
2250
|
interceptParams: intercept.matchedParams,
|
|
2063
2251
|
};
|
|
@@ -2070,7 +2258,13 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2070
2258
|
|
|
2071
2259
|
const __pageBuildResult = await __buildAppPageElement({
|
|
2072
2260
|
buildPageElement() {
|
|
2073
|
-
return
|
|
2261
|
+
return buildPageElements(route, params, cleanPathname, {
|
|
2262
|
+
opts: interceptOpts,
|
|
2263
|
+
searchParams: url.searchParams,
|
|
2264
|
+
isRscRequest,
|
|
2265
|
+
request,
|
|
2266
|
+
mountedSlotsHeader: __mountedSlotsHeader,
|
|
2267
|
+
});
|
|
2074
2268
|
},
|
|
2075
2269
|
renderErrorBoundaryPage(buildErr) {
|
|
2076
2270
|
return renderErrorBoundaryPage(route, buildErr, isRscRequest, request, params, _scriptNonce);
|
|
@@ -2108,19 +2302,6 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2108
2302
|
// rscCssTransform — no manual loadCss() call needed.
|
|
2109
2303
|
const _hasLoadingBoundary = !!(route.loading && route.loading.default);
|
|
2110
2304
|
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
2305
|
return __renderAppPageLifecycle({
|
|
2125
2306
|
cleanPathname,
|
|
2126
2307
|
clearRequestContext() {
|
|
@@ -2166,9 +2347,42 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2166
2347
|
return LayoutComp({ params: _asyncLayoutParams, children: null });
|
|
2167
2348
|
},
|
|
2168
2349
|
probePage() {
|
|
2350
|
+
if (!PageComponent) return null;
|
|
2351
|
+
const _probeSearchObj = {};
|
|
2352
|
+
url.searchParams.forEach(function(v, k) {
|
|
2353
|
+
if (k in _probeSearchObj) {
|
|
2354
|
+
_probeSearchObj[k] = Array.isArray(_probeSearchObj[k])
|
|
2355
|
+
? _probeSearchObj[k].concat(v)
|
|
2356
|
+
: [_probeSearchObj[k], v];
|
|
2357
|
+
} else {
|
|
2358
|
+
_probeSearchObj[k] = v;
|
|
2359
|
+
}
|
|
2360
|
+
});
|
|
2361
|
+
const _asyncSearchParams = makeThenableParams(_probeSearchObj);
|
|
2169
2362
|
return PageComponent({ params: _asyncLayoutParams, searchParams: _asyncSearchParams });
|
|
2170
2363
|
},
|
|
2364
|
+
classification: {
|
|
2365
|
+
getLayoutId(index) {
|
|
2366
|
+
const tp = route.layoutTreePositions?.[index] ?? 0;
|
|
2367
|
+
return "layout:" + __createAppPageTreePath(route.routeSegments, tp);
|
|
2368
|
+
},
|
|
2369
|
+
buildTimeClassifications: route.__buildTimeClassifications,
|
|
2370
|
+
buildTimeReasons: route.__buildTimeReasons,
|
|
2371
|
+
debugClassification: __classDebug,
|
|
2372
|
+
async runWithIsolatedDynamicScope(fn) {
|
|
2373
|
+
const priorDynamic = consumeDynamicUsage();
|
|
2374
|
+
try {
|
|
2375
|
+
const result = await fn();
|
|
2376
|
+
const dynamicDetected = consumeDynamicUsage();
|
|
2377
|
+
return { result, dynamicDetected };
|
|
2378
|
+
} finally {
|
|
2379
|
+
consumeDynamicUsage();
|
|
2380
|
+
if (priorDynamic) markDynamicUsage();
|
|
2381
|
+
}
|
|
2382
|
+
},
|
|
2383
|
+
},
|
|
2171
2384
|
revalidateSeconds,
|
|
2385
|
+
mountedSlotsHeader: __mountedSlotsHeader,
|
|
2172
2386
|
renderErrorBoundaryResponse(renderErr) {
|
|
2173
2387
|
return renderErrorBoundaryPage(route, renderErr, isRscRequest, request, params, _scriptNonce);
|
|
2174
2388
|
},
|