vinext 0.0.39 → 0.0.41
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 +1 -1
- package/dist/build/standalone.js +7 -0
- package/dist/build/standalone.js.map +1 -1
- package/dist/check.js +2 -2
- package/dist/check.js.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +2 -1
- package/dist/entries/app-rsc-entry.js +185 -264
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +205 -199
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +81 -6
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js +2 -2
- package/dist/init.js.map +1 -1
- package/dist/plugins/fonts.js +1 -0
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/server-externals-manifest.d.ts +11 -1
- package/dist/plugins/server-externals-manifest.js +10 -3
- package/dist/plugins/server-externals-manifest.js.map +1 -1
- package/dist/routing/app-router.d.ts +10 -2
- package/dist/routing/app-router.js +37 -22
- package/dist/routing/app-router.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +1 -0
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-render.d.ts +1 -0
- package/dist/server/app-page-render.js +2 -0
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-response.d.ts +4 -1
- package/dist/server/app-page-response.js +14 -8
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +79 -0
- package/dist/server/app-page-route-wiring.js +167 -0
- package/dist/server/app-page-route-wiring.js.map +1 -0
- package/dist/server/app-page-stream.d.ts +4 -1
- package/dist/server/app-page-stream.js +5 -1
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-response.js +6 -2
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-router-entry.d.ts +6 -1
- package/dist/server/app-router-entry.js +9 -2
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -1
- package/dist/server/app-ssr-entry.js +17 -17
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +1 -1
- package/dist/server/app-ssr-stream.js +4 -4
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/csp.d.ts +12 -0
- package/dist/server/csp.js +46 -0
- package/dist/server/csp.js.map +1 -0
- package/dist/server/dev-server.js +20 -14
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/html.d.ts +4 -1
- package/dist/server/html.js +11 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/middleware-response-headers.d.ts +12 -0
- package/dist/server/middleware-response-headers.js +23 -0
- package/dist/server/middleware-response-headers.js.map +1 -0
- package/dist/server/pages-page-data.d.ts +1 -0
- package/dist/server/pages-page-data.js +2 -2
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +16 -14
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.d.ts +1 -1
- package/dist/server/prod-server.js +41 -14
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +14 -1
- package/dist/server/request-pipeline.js +55 -1
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/worker-utils.d.ts +4 -1
- package/dist/server/worker-utils.js +31 -1
- package/dist/server/worker-utils.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +14 -5
- package/dist/shims/error-boundary.js +23 -3
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/navigation.d.ts +16 -1
- package/dist/shims/navigation.js +18 -3
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.js +127 -38
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script-nonce-context.d.ts +12 -0
- package/dist/shims/script-nonce-context.js +17 -0
- package/dist/shims/script-nonce-context.js.map +1 -0
- package/dist/shims/script.js +41 -10
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.d.ts +17 -4
- package/dist/shims/server.js +97 -74
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +28 -0
- package/dist/shims/slot.js +49 -0
- package/dist/shims/slot.js.map +1 -0
- package/dist/shims/url-safety.js +25 -4
- package/dist/shims/url-safety.js.map +1 -1
- package/package.json +7 -8
|
@@ -24,7 +24,10 @@ const appRouteHandlerCachePath = resolveEntryPath("../server/app-route-handler-c
|
|
|
24
24
|
const appPageCachePath = resolveEntryPath("../server/app-page-cache.js", import.meta.url);
|
|
25
25
|
const appPageExecutionPath = resolveEntryPath("../server/app-page-execution.js", import.meta.url);
|
|
26
26
|
const appPageBoundaryRenderPath = resolveEntryPath("../server/app-page-boundary-render.js", import.meta.url);
|
|
27
|
+
const appPageRouteWiringPath = resolveEntryPath("../server/app-page-route-wiring.js", import.meta.url);
|
|
27
28
|
const appPageRenderPath = resolveEntryPath("../server/app-page-render.js", import.meta.url);
|
|
29
|
+
const appPageResponsePath = resolveEntryPath("../server/app-page-response.js", import.meta.url);
|
|
30
|
+
const cspPath = resolveEntryPath("../server/csp.js", import.meta.url);
|
|
28
31
|
const appPageRequestPath = resolveEntryPath("../server/app-page-request.js", import.meta.url);
|
|
29
32
|
const appRouteHandlerResponsePath = resolveEntryPath("../server/app-route-handler-response.js", import.meta.url);
|
|
30
33
|
const routeTriePath = resolveEntryPath("../routing/route-trie.js", import.meta.url);
|
|
@@ -50,6 +53,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
50
53
|
const bodySizeLimit = config?.bodySizeLimit ?? 1 * 1024 * 1024;
|
|
51
54
|
const i18nConfig = config?.i18n ?? null;
|
|
52
55
|
const hasPagesDir = config?.hasPagesDir ?? false;
|
|
56
|
+
const publicFiles = config?.publicFiles ?? [];
|
|
53
57
|
const imports = [];
|
|
54
58
|
const importMap = /* @__PURE__ */ new Map();
|
|
55
59
|
let importIdx = 0;
|
|
@@ -65,7 +69,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
65
69
|
if (route.pagePath) getImportVar(route.pagePath);
|
|
66
70
|
if (route.routePath) getImportVar(route.routePath);
|
|
67
71
|
for (const layout of route.layouts) getImportVar(layout);
|
|
68
|
-
for (const tmpl of route.templates) getImportVar(tmpl);
|
|
72
|
+
for (const tmpl of route.templates) if (tmpl) getImportVar(tmpl);
|
|
69
73
|
if (route.loadingPath) getImportVar(route.loadingPath);
|
|
70
74
|
if (route.errorPath) getImportVar(route.errorPath);
|
|
71
75
|
if (route.layoutErrorPaths) {
|
|
@@ -86,7 +90,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
86
90
|
}
|
|
87
91
|
const routeEntries = routes.map((route) => {
|
|
88
92
|
const layoutVars = route.layouts.map((l) => getImportVar(l));
|
|
89
|
-
const templateVars = route.templates.map((t) => getImportVar(t));
|
|
93
|
+
const templateVars = route.templates.map((t) => t ? getImportVar(t) : "null");
|
|
90
94
|
const notFoundVars = (route.notFoundPaths || []).map((nf) => nf ? getImportVar(nf) : "null");
|
|
91
95
|
const slotEntries = route.parallelSlots.map((slot) => {
|
|
92
96
|
const interceptEntries = slot.interceptingRoutes.map((ir) => ` {
|
|
@@ -102,6 +106,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
102
106
|
loading: ${slot.loadingPath ? getImportVar(slot.loadingPath) : "null"},
|
|
103
107
|
error: ${slot.errorPath ? getImportVar(slot.errorPath) : "null"},
|
|
104
108
|
layoutIndex: ${slot.layoutIndex},
|
|
109
|
+
routeSegments: ${JSON.stringify(slot.routeSegments)},
|
|
105
110
|
intercepts: [
|
|
106
111
|
${interceptEntries.join(",\n")}
|
|
107
112
|
],
|
|
@@ -204,19 +209,17 @@ function renderToReadableStream(model, options) {
|
|
|
204
209
|
}
|
|
205
210
|
}));
|
|
206
211
|
}
|
|
207
|
-
import { createElement
|
|
212
|
+
import { createElement } from "react";
|
|
208
213
|
import { setNavigationContext as _setNavigationContextOrig, getNavigationContext as _getNavigationContext } from "next/navigation";
|
|
209
214
|
import { setHeadersContext, headersContextFromRequest, getDraftModeCookieHeader, getAndClearPendingCookies, consumeDynamicUsage, markDynamicUsage, applyMiddlewareRequestHeaders, getHeadersContext, setHeadersAccessPhase } from "next/headers";
|
|
210
215
|
import { NextRequest, NextFetchEvent } from "next/server";
|
|
211
|
-
import {
|
|
212
|
-
import { LayoutSegmentProvider } from "vinext/layout-segment-context";
|
|
213
|
-
import { MetadataHead, mergeMetadata, resolveModuleMetadata, ViewportHead, mergeViewport, resolveModuleViewport } from "vinext/metadata";
|
|
216
|
+
import { mergeMetadata, resolveModuleMetadata, mergeViewport, resolveModuleViewport } from "vinext/metadata";
|
|
214
217
|
${middlewarePath ? `import * as middlewareModule from ${JSON.stringify(middlewarePath.replace(/\\/g, "/"))};` : ""}
|
|
215
218
|
${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(instrumentationPath.replace(/\\/g, "/"))};` : ""}
|
|
216
219
|
${effectiveMetaRoutes.length > 0 ? `import { sitemapToXml, robotsToText, manifestToJson } from ${JSON.stringify(metadataRoutesPath)};` : ""}
|
|
217
220
|
import { requestContextFromRequest, normalizeHost, matchRedirect, matchRewrite, matchHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination } from ${JSON.stringify(configMatchersPath)};
|
|
218
221
|
import { decodePathParams as __decodePathParams } from ${JSON.stringify(normalizePathModulePath)};
|
|
219
|
-
import { validateCsrfOrigin, validateImageUrl, guardProtocolRelativeUrl, hasBasePath, stripBasePath, normalizeTrailingSlash, processMiddlewareHeaders } from ${JSON.stringify(requestPipelinePath)};
|
|
222
|
+
import { validateCsrfOrigin, validateServerActionPayload, validateImageUrl, guardProtocolRelativeUrl, hasBasePath, stripBasePath, normalizeTrailingSlash, processMiddlewareHeaders } from ${JSON.stringify(requestPipelinePath)};
|
|
220
223
|
import {
|
|
221
224
|
isKnownDynamicAppRoute as __isKnownDynamicAppRoute,
|
|
222
225
|
} from ${JSON.stringify(appRouteHandlerRuntimePath)};
|
|
@@ -242,9 +245,17 @@ import {
|
|
|
242
245
|
renderAppPageErrorBoundary as __renderAppPageErrorBoundary,
|
|
243
246
|
renderAppPageHttpAccessFallback as __renderAppPageHttpAccessFallback,
|
|
244
247
|
} from ${JSON.stringify(appPageBoundaryRenderPath)};
|
|
248
|
+
import {
|
|
249
|
+
buildAppPageRouteElement as __buildAppPageRouteElement,
|
|
250
|
+
resolveAppPageChildSegments as __resolveAppPageChildSegments,
|
|
251
|
+
} from ${JSON.stringify(appPageRouteWiringPath)};
|
|
245
252
|
import {
|
|
246
253
|
renderAppPageLifecycle as __renderAppPageLifecycle,
|
|
247
254
|
} from ${JSON.stringify(appPageRenderPath)};
|
|
255
|
+
import {
|
|
256
|
+
mergeMiddlewareResponseHeaders as __mergeMiddlewareResponseHeaders,
|
|
257
|
+
} from ${JSON.stringify(appPageResponsePath)};
|
|
258
|
+
import { getScriptNonceFromHeaderSources as __getScriptNonceFromHeaderSources } from ${JSON.stringify(cspPath)};
|
|
248
259
|
import {
|
|
249
260
|
buildAppPageElement as __buildAppPageElement,
|
|
250
261
|
resolveAppPageIntercept as __resolveAppPageIntercept,
|
|
@@ -409,38 +420,6 @@ function makeThenableParams(obj) {
|
|
|
409
420
|
return Object.assign(Promise.resolve(plain), plain);
|
|
410
421
|
}
|
|
411
422
|
|
|
412
|
-
// Resolve route tree segments to actual values using matched params.
|
|
413
|
-
// Dynamic segments like [id] are replaced with param values, catch-all
|
|
414
|
-
// segments like [...slug] are joined with "/", and route groups are kept as-is.
|
|
415
|
-
function __resolveChildSegments(routeSegments, treePosition, params) {
|
|
416
|
-
var raw = routeSegments.slice(treePosition);
|
|
417
|
-
var result = [];
|
|
418
|
-
for (var j = 0; j < raw.length; j++) {
|
|
419
|
-
var seg = raw[j];
|
|
420
|
-
// Optional catch-all: [[...param]]
|
|
421
|
-
if (seg.indexOf("[[...") === 0 && seg.charAt(seg.length - 1) === "]" && seg.charAt(seg.length - 2) === "]") {
|
|
422
|
-
var pn = seg.slice(5, -2);
|
|
423
|
-
var v = params[pn];
|
|
424
|
-
// Skip empty optional catch-all (e.g., visiting /blog on [[...slug]] route)
|
|
425
|
-
if (Array.isArray(v) && v.length === 0) continue;
|
|
426
|
-
if (v == null) continue;
|
|
427
|
-
result.push(Array.isArray(v) ? v.join("/") : v);
|
|
428
|
-
// Catch-all: [...param]
|
|
429
|
-
} else if (seg.indexOf("[...") === 0 && seg.charAt(seg.length - 1) === "]") {
|
|
430
|
-
var pn2 = seg.slice(4, -1);
|
|
431
|
-
var v2 = params[pn2];
|
|
432
|
-
result.push(Array.isArray(v2) ? v2.join("/") : (v2 || seg));
|
|
433
|
-
// Dynamic: [param]
|
|
434
|
-
} else if (seg.charAt(0) === "[" && seg.charAt(seg.length - 1) === "]" && seg.indexOf(".") === -1) {
|
|
435
|
-
var pn3 = seg.slice(1, -1);
|
|
436
|
-
result.push(params[pn3] || seg);
|
|
437
|
-
} else {
|
|
438
|
-
result.push(seg);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
return result;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
423
|
// djb2 hash — matches Next.js's stringHash for digest generation.
|
|
445
424
|
// Produces a stable numeric string from error message + stack.
|
|
446
425
|
function __errorDigest(str) {
|
|
@@ -616,7 +595,7 @@ const rootLayouts = [${rootLayoutVars.join(", ")}];
|
|
|
616
595
|
* @param opts.boundaryComponent - Override the boundary component (for layout-level notFound)
|
|
617
596
|
* @param opts.layouts - Override the layouts to wrap with (for layout-level notFound, excludes the throwing layout)
|
|
618
597
|
*/
|
|
619
|
-
async function renderHTTPAccessFallbackPage(route, statusCode, isRscRequest, request, opts) {
|
|
598
|
+
async function renderHTTPAccessFallbackPage(route, statusCode, isRscRequest, request, opts, scriptNonce) {
|
|
620
599
|
return __renderAppPageHttpAccessFallback({
|
|
621
600
|
boundaryComponent: opts?.boundaryComponent ?? null,
|
|
622
601
|
buildFontLinkHeader: __buildAppPageFontLinkHeader,
|
|
@@ -640,20 +619,21 @@ async function renderHTTPAccessFallbackPage(route, statusCode, isRscRequest, req
|
|
|
640
619
|
makeThenableParams,
|
|
641
620
|
matchedParams: opts?.matchedParams ?? route?.params ?? {},
|
|
642
621
|
requestUrl: request.url,
|
|
643
|
-
resolveChildSegments:
|
|
622
|
+
resolveChildSegments: __resolveAppPageChildSegments,
|
|
644
623
|
rootForbiddenModule: rootForbiddenModule,
|
|
645
624
|
rootLayouts: rootLayouts,
|
|
646
625
|
rootNotFoundModule: rootNotFoundModule,
|
|
647
626
|
rootUnauthorizedModule: rootUnauthorizedModule,
|
|
648
627
|
route,
|
|
649
628
|
renderToReadableStream,
|
|
629
|
+
scriptNonce,
|
|
650
630
|
statusCode,
|
|
651
631
|
});
|
|
652
632
|
}
|
|
653
633
|
|
|
654
634
|
/** Convenience: render a not-found page (404) */
|
|
655
|
-
async function renderNotFoundPage(route, isRscRequest, request, matchedParams) {
|
|
656
|
-
return renderHTTPAccessFallbackPage(route, 404, isRscRequest, request, { matchedParams });
|
|
635
|
+
async function renderNotFoundPage(route, isRscRequest, request, matchedParams, scriptNonce) {
|
|
636
|
+
return renderHTTPAccessFallbackPage(route, 404, isRscRequest, request, { matchedParams }, scriptNonce);
|
|
657
637
|
}
|
|
658
638
|
|
|
659
639
|
/**
|
|
@@ -663,7 +643,7 @@ async function renderNotFoundPage(route, isRscRequest, request, matchedParams) {
|
|
|
663
643
|
* Next.js returns HTTP 200 when error.tsx catches an error (the error is "handled"
|
|
664
644
|
* by the boundary). This matches that behavior intentionally.
|
|
665
645
|
*/
|
|
666
|
-
async function renderErrorBoundaryPage(route, error, isRscRequest, request, matchedParams) {
|
|
646
|
+
async function renderErrorBoundaryPage(route, error, isRscRequest, request, matchedParams, scriptNonce) {
|
|
667
647
|
return __renderAppPageErrorBoundary({
|
|
668
648
|
buildFontLinkHeader: __buildAppPageFontLinkHeader,
|
|
669
649
|
clearRequestContext() {
|
|
@@ -686,11 +666,12 @@ async function renderErrorBoundaryPage(route, error, isRscRequest, request, matc
|
|
|
686
666
|
makeThenableParams,
|
|
687
667
|
matchedParams: matchedParams ?? route?.params ?? {},
|
|
688
668
|
requestUrl: request.url,
|
|
689
|
-
resolveChildSegments:
|
|
669
|
+
resolveChildSegments: __resolveAppPageChildSegments,
|
|
690
670
|
rootLayouts: rootLayouts,
|
|
691
671
|
route,
|
|
692
672
|
renderToReadableStream,
|
|
693
673
|
sanitizeErrorForClient: __sanitizeErrorForClient,
|
|
674
|
+
scriptNonce,
|
|
694
675
|
});
|
|
695
676
|
}
|
|
696
677
|
|
|
@@ -704,6 +685,21 @@ function matchRoute(url) {
|
|
|
704
685
|
return _trieMatch(_routeTrie, urlParts);
|
|
705
686
|
}
|
|
706
687
|
|
|
688
|
+
function __createStaticFileSignal(pathname, _mwCtx) {
|
|
689
|
+
const headers = new Headers({
|
|
690
|
+
"x-vinext-static-file": encodeURIComponent(pathname),
|
|
691
|
+
});
|
|
692
|
+
if (_mwCtx.headers) {
|
|
693
|
+
for (const [key, value] of _mwCtx.headers) {
|
|
694
|
+
headers.append(key, value);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return new Response(null, {
|
|
698
|
+
status: _mwCtx.status ?? 200,
|
|
699
|
+
headers,
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
707
703
|
// matchPattern is kept for findIntercept (linear scan over small interceptLookup array).
|
|
708
704
|
function matchPattern(urlParts, patternParts) {
|
|
709
705
|
const params = Object.create(null);
|
|
@@ -852,12 +848,10 @@ async function buildPageElement(route, params, opts, searchParams) {
|
|
|
852
848
|
const resolvedMetadata = metadataList.length > 0 ? mergeMetadata(metadataList) : null;
|
|
853
849
|
const resolvedViewport = mergeViewport(viewportList);
|
|
854
850
|
|
|
855
|
-
// Build
|
|
856
|
-
//
|
|
857
|
-
//
|
|
858
|
-
|
|
859
|
-
const asyncParams = makeThenableParams(params);
|
|
860
|
-
const pageProps = { params: asyncParams };
|
|
851
|
+
// Build the route tree from the leaf page, then delegate the boundary/layout/
|
|
852
|
+
// template/segment wiring to a typed runtime helper so the generated entry
|
|
853
|
+
// stays thin and the wiring logic can be unit tested directly.
|
|
854
|
+
const pageProps = { params: makeThenableParams(params) };
|
|
861
855
|
if (searchParams) {
|
|
862
856
|
// Always provide searchParams prop when the URL object is available, even
|
|
863
857
|
// when the query string is empty -- pages that do "await searchParams" need
|
|
@@ -873,192 +867,25 @@ async function buildPageElement(route, params, opts, searchParams) {
|
|
|
873
867
|
// dynamic, and this avoids false positives from React internals.
|
|
874
868
|
if (hasSearchParams) markDynamicUsage();
|
|
875
869
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
// Wrap with loading.tsx Suspense if present
|
|
895
|
-
if (route.loading?.default) {
|
|
896
|
-
element = createElement(
|
|
897
|
-
Suspense,
|
|
898
|
-
{ fallback: createElement(route.loading.default) },
|
|
899
|
-
element,
|
|
900
|
-
);
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
// Wrap with the leaf's error.tsx ErrorBoundary if it's not already covered
|
|
904
|
-
// by a per-layout error boundary (i.e., the leaf has error.tsx but no layout).
|
|
905
|
-
// Per-layout error boundaries are interleaved with layouts below.
|
|
906
|
-
{
|
|
907
|
-
const lastLayoutError = route.errors ? route.errors[route.errors.length - 1] : null;
|
|
908
|
-
if (route.error?.default && route.error !== lastLayoutError) {
|
|
909
|
-
element = createElement(ErrorBoundary, {
|
|
910
|
-
fallback: route.error.default,
|
|
911
|
-
children: element,
|
|
912
|
-
});
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// Wrap with NotFoundBoundary so client-side notFound() renders not-found.tsx
|
|
917
|
-
// instead of crashing the React tree. Must be above ErrorBoundary since
|
|
918
|
-
// ErrorBoundary re-throws notFound errors.
|
|
919
|
-
// Pre-render the not-found component as a React element since it may be a
|
|
920
|
-
// server component (not a client reference) and can't be passed as a function prop.
|
|
921
|
-
{
|
|
922
|
-
const NotFoundComponent = route.notFound?.default ?? ${rootNotFoundVar ? `${rootNotFoundVar}?.default` : "null"};
|
|
923
|
-
if (NotFoundComponent) {
|
|
924
|
-
element = createElement(NotFoundBoundary, {
|
|
925
|
-
fallback: createElement(NotFoundComponent),
|
|
926
|
-
children: element,
|
|
927
|
-
});
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// Wrap with templates (innermost first, then outer)
|
|
932
|
-
// Templates are like layouts but re-mount on navigation (client-side concern).
|
|
933
|
-
// On the server, they just wrap the content like layouts do.
|
|
934
|
-
if (route.templates) {
|
|
935
|
-
for (let i = route.templates.length - 1; i >= 0; i--) {
|
|
936
|
-
const TemplateComponent = route.templates[i]?.default;
|
|
937
|
-
if (TemplateComponent) {
|
|
938
|
-
element = createElement(TemplateComponent, { children: element, params });
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
// Wrap with layouts (innermost first, then outer).
|
|
944
|
-
// At each layout level, first wrap with that level's error boundary (if any)
|
|
945
|
-
// so the boundary is inside the layout and catches errors from children.
|
|
946
|
-
// This matches Next.js behavior: Layout > ErrorBoundary > children.
|
|
947
|
-
// Parallel slots are passed as named props to the innermost layout
|
|
948
|
-
// (the layout at the same directory level as the page/slots)
|
|
949
|
-
for (let i = route.layouts.length - 1; i >= 0; i--) {
|
|
950
|
-
// Wrap with per-layout error boundary before wrapping with layout.
|
|
951
|
-
// This places the ErrorBoundary inside the layout, catching errors
|
|
952
|
-
// from child segments (matching Next.js per-segment error handling).
|
|
953
|
-
if (route.errors && route.errors[i]?.default) {
|
|
954
|
-
element = createElement(ErrorBoundary, {
|
|
955
|
-
fallback: route.errors[i].default,
|
|
956
|
-
children: element,
|
|
957
|
-
});
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
const LayoutComponent = route.layouts[i]?.default;
|
|
961
|
-
if (LayoutComponent) {
|
|
962
|
-
// Per-layout NotFoundBoundary: wraps this layout's children so that
|
|
963
|
-
// notFound() thrown from a child layout is caught here.
|
|
964
|
-
// Matches Next.js behavior where each segment has its own boundary.
|
|
965
|
-
// The boundary at level N catches errors from Layout[N+1] and below,
|
|
966
|
-
// but NOT from Layout[N] itself (which propagates to level N-1).
|
|
967
|
-
{
|
|
968
|
-
const LayoutNotFound = route.notFounds?.[i]?.default;
|
|
969
|
-
if (LayoutNotFound) {
|
|
970
|
-
element = createElement(NotFoundBoundary, {
|
|
971
|
-
fallback: createElement(LayoutNotFound),
|
|
972
|
-
children: element,
|
|
973
|
-
});
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
const layoutProps = { children: element, params: makeThenableParams(params) };
|
|
978
|
-
|
|
979
|
-
// Add parallel slot elements to the layout that defines them.
|
|
980
|
-
// Each slot has a layoutIndex indicating which layout it belongs to.
|
|
981
|
-
if (route.slots) {
|
|
982
|
-
for (const [slotName, slotMod] of Object.entries(route.slots)) {
|
|
983
|
-
// Attach slot to the layout at its layoutIndex, or to the innermost layout if -1
|
|
984
|
-
const targetIdx = slotMod.layoutIndex >= 0 ? slotMod.layoutIndex : route.layouts.length - 1;
|
|
985
|
-
if (i !== targetIdx) continue;
|
|
986
|
-
// Check if this slot has an intercepting route that should activate
|
|
987
|
-
let SlotPage = null;
|
|
988
|
-
let slotParams = params;
|
|
989
|
-
|
|
990
|
-
if (opts && opts.interceptSlot === slotName && opts.interceptPage) {
|
|
991
|
-
// Use the intercepting route's page component
|
|
992
|
-
SlotPage = opts.interceptPage.default;
|
|
993
|
-
slotParams = opts.interceptParams || params;
|
|
994
|
-
} else {
|
|
995
|
-
SlotPage = slotMod.page?.default || slotMod.default?.default;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
if (SlotPage) {
|
|
999
|
-
let slotElement = createElement(SlotPage, { params: makeThenableParams(slotParams) });
|
|
1000
|
-
// Wrap with slot-specific layout if present.
|
|
1001
|
-
// In Next.js, @slot/layout.tsx wraps the slot's page content
|
|
1002
|
-
// before it is passed as a prop to the parent layout.
|
|
1003
|
-
const SlotLayout = slotMod.layout?.default;
|
|
1004
|
-
if (SlotLayout) {
|
|
1005
|
-
slotElement = createElement(SlotLayout, {
|
|
1006
|
-
children: slotElement,
|
|
1007
|
-
params: makeThenableParams(slotParams),
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
// Wrap with slot-specific loading if present
|
|
1011
|
-
if (slotMod.loading?.default) {
|
|
1012
|
-
slotElement = createElement(Suspense,
|
|
1013
|
-
{ fallback: createElement(slotMod.loading.default) },
|
|
1014
|
-
slotElement,
|
|
1015
|
-
);
|
|
1016
|
-
}
|
|
1017
|
-
// Wrap with slot-specific error boundary if present
|
|
1018
|
-
if (slotMod.error?.default) {
|
|
1019
|
-
slotElement = createElement(ErrorBoundary, {
|
|
1020
|
-
fallback: slotMod.error.default,
|
|
1021
|
-
children: slotElement,
|
|
1022
|
-
});
|
|
1023
|
-
}
|
|
1024
|
-
layoutProps[slotName] = slotElement;
|
|
870
|
+
return __buildAppPageRouteElement({
|
|
871
|
+
element: createElement(PageComponent, pageProps),
|
|
872
|
+
globalErrorModule: ${globalErrorVar ? globalErrorVar : "null"},
|
|
873
|
+
makeThenableParams,
|
|
874
|
+
matchedParams: params,
|
|
875
|
+
resolvedMetadata,
|
|
876
|
+
resolvedViewport,
|
|
877
|
+
rootNotFoundModule: ${rootNotFoundVar ? rootNotFoundVar : "null"},
|
|
878
|
+
route,
|
|
879
|
+
slotOverrides:
|
|
880
|
+
opts && opts.interceptSlot && opts.interceptPage
|
|
881
|
+
? {
|
|
882
|
+
[opts.interceptSlot]: {
|
|
883
|
+
pageModule: opts.interceptPage,
|
|
884
|
+
params: opts.interceptParams || params,
|
|
885
|
+
},
|
|
1025
886
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
element = createElement(LayoutComponent, layoutProps);
|
|
1030
|
-
|
|
1031
|
-
// Wrap the layout with LayoutSegmentProvider so useSelectedLayoutSegments()
|
|
1032
|
-
// called INSIDE this layout gets the correct child segments. We resolve the
|
|
1033
|
-
// route tree segments using actual param values and pass them through context.
|
|
1034
|
-
// We wrap the layout (not just children) because hooks are called from
|
|
1035
|
-
// components rendered inside the layout's own JSX.
|
|
1036
|
-
const treePos = route.layoutTreePositions ? route.layoutTreePositions[i] : 0;
|
|
1037
|
-
const childSegs = __resolveChildSegments(route.routeSegments || [], treePos, params);
|
|
1038
|
-
element = createElement(LayoutSegmentProvider, { segmentMap: { children: childSegs } }, element);
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
// Wrap with global error boundary if app/global-error.tsx exists.
|
|
1043
|
-
// This must be present in both HTML and RSC paths so the component tree
|
|
1044
|
-
// structure matches — otherwise React reconciliation on client-side navigation
|
|
1045
|
-
// would see a mismatched tree and destroy/recreate the DOM.
|
|
1046
|
-
//
|
|
1047
|
-
// For RSC requests (client-side nav), this provides error recovery on the client.
|
|
1048
|
-
// For HTML requests (initial page load), the ErrorBoundary catches during SSR
|
|
1049
|
-
// but produces double <html>/<body> (root layout + global-error). The request
|
|
1050
|
-
// handler detects this via the rscOnError flag and re-renders without layouts.
|
|
1051
|
-
${globalErrorVar ? `
|
|
1052
|
-
const GlobalErrorComponent = ${globalErrorVar}.default;
|
|
1053
|
-
if (GlobalErrorComponent) {
|
|
1054
|
-
element = createElement(ErrorBoundary, {
|
|
1055
|
-
fallback: GlobalErrorComponent,
|
|
1056
|
-
children: element,
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
` : ""}
|
|
1060
|
-
|
|
1061
|
-
return element;
|
|
887
|
+
: null,
|
|
888
|
+
});
|
|
1062
889
|
}
|
|
1063
890
|
|
|
1064
891
|
${middlewarePath ? generateMiddlewareMatcherCode("modern") : ""}
|
|
@@ -1069,6 +896,7 @@ const __i18nConfig = ${JSON.stringify(i18nConfig)};
|
|
|
1069
896
|
const __configRedirects = ${JSON.stringify(redirects)};
|
|
1070
897
|
const __configRewrites = ${JSON.stringify(rewrites)};
|
|
1071
898
|
const __configHeaders = ${JSON.stringify(headers)};
|
|
899
|
+
const __publicFiles = new Set(${JSON.stringify(publicFiles)});
|
|
1072
900
|
const __allowedOrigins = ${JSON.stringify(allowedOrigins)};
|
|
1073
901
|
|
|
1074
902
|
${generateDevOriginCheckCode(config?.allowedDevOrigins)}
|
|
@@ -1267,6 +1095,9 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1267
1095
|
let pathname = __normalizePath(decodedUrlPathname);
|
|
1268
1096
|
|
|
1269
1097
|
${bp ? `
|
|
1098
|
+
if (!hasBasePath(pathname, __basePath) && !pathname.startsWith("/__vinext/")) {
|
|
1099
|
+
return new Response("Not Found", { status: 404 });
|
|
1100
|
+
}
|
|
1270
1101
|
// Strip basePath prefix
|
|
1271
1102
|
pathname = stripBasePath(pathname, __basePath);
|
|
1272
1103
|
` : ""}
|
|
@@ -1510,6 +1341,8 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1510
1341
|
}
|
|
1511
1342
|
` : ""}
|
|
1512
1343
|
|
|
1344
|
+
const _scriptNonce = __getScriptNonceFromHeaderSources(request.headers, _mwCtx.headers);
|
|
1345
|
+
|
|
1513
1346
|
// Build post-middleware request context for afterFiles/fallback rewrites.
|
|
1514
1347
|
// These run after middleware in the App Router execution order and should
|
|
1515
1348
|
// evaluate has/missing conditions against middleware-modified headers.
|
|
@@ -1614,6 +1447,18 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1614
1447
|
}
|
|
1615
1448
|
}
|
|
1616
1449
|
|
|
1450
|
+
// Serve public/ files as filesystem routes after middleware and before
|
|
1451
|
+
// afterFiles/fallback rewrites, matching Next.js routing semantics.
|
|
1452
|
+
if (
|
|
1453
|
+
(request.method === "GET" || request.method === "HEAD") &&
|
|
1454
|
+
!pathname.endsWith(".rsc") &&
|
|
1455
|
+
__publicFiles.has(cleanPathname)
|
|
1456
|
+
) {
|
|
1457
|
+
setHeadersContext(null);
|
|
1458
|
+
setNavigationContext(null);
|
|
1459
|
+
return __createStaticFileSignal(cleanPathname, _mwCtx);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1617
1462
|
// Set navigation context for Server Components.
|
|
1618
1463
|
// Note: Headers context is already set by runWithRequestContext in the handler wrapper.
|
|
1619
1464
|
setNavigationContext({
|
|
@@ -1657,6 +1502,12 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1657
1502
|
}
|
|
1658
1503
|
throw sizeErr;
|
|
1659
1504
|
}
|
|
1505
|
+
const payloadResponse = await validateServerActionPayload(body);
|
|
1506
|
+
if (payloadResponse) {
|
|
1507
|
+
setHeadersContext(null);
|
|
1508
|
+
setNavigationContext(null);
|
|
1509
|
+
return payloadResponse;
|
|
1510
|
+
}
|
|
1660
1511
|
const temporaryReferences = createTemporaryReferenceSet();
|
|
1661
1512
|
const args = await decodeReply(body, { temporaryReferences });
|
|
1662
1513
|
const action = await loadServerAction(actionId);
|
|
@@ -1669,7 +1520,10 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1669
1520
|
returnValue = { ok: true, data };
|
|
1670
1521
|
} catch (e) {
|
|
1671
1522
|
// Detect redirect() / permanentRedirect() called inside the action.
|
|
1672
|
-
// These throw errors with digest "NEXT_REDIRECT
|
|
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.
|
|
1673
1527
|
// The URL is encodeURIComponent-encoded to prevent semicolons in the URL
|
|
1674
1528
|
// from corrupting the delimiter-based digest format.
|
|
1675
1529
|
if (e && typeof e === "object" && "digest" in e) {
|
|
@@ -1678,7 +1532,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1678
1532
|
const parts = digest.split(";");
|
|
1679
1533
|
actionRedirect = {
|
|
1680
1534
|
url: decodeURIComponent(parts[2]),
|
|
1681
|
-
type: parts[1] || "
|
|
1535
|
+
type: parts[1] || "push", // Server Action → default "push"
|
|
1682
1536
|
status: parts[3] ? parseInt(parts[3], 10) : 307,
|
|
1683
1537
|
};
|
|
1684
1538
|
returnValue = { ok: true, data: undefined };
|
|
@@ -1714,10 +1568,14 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1714
1568
|
const redirectHeaders = new Headers({
|
|
1715
1569
|
"Content-Type": "text/x-component; charset=utf-8",
|
|
1716
1570
|
"Vary": "RSC, Accept",
|
|
1717
|
-
"x-action-redirect": actionRedirect.url,
|
|
1718
|
-
"x-action-redirect-type": actionRedirect.type,
|
|
1719
|
-
"x-action-redirect-status": String(actionRedirect.status),
|
|
1720
1571
|
});
|
|
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
|
+
__mergeMiddlewareResponseHeaders(redirectHeaders, _mwCtx.headers);
|
|
1576
|
+
redirectHeaders.set("x-action-redirect", actionRedirect.url);
|
|
1577
|
+
redirectHeaders.set("x-action-redirect-type", actionRedirect.type);
|
|
1578
|
+
redirectHeaders.set("x-action-redirect-status", String(actionRedirect.status));
|
|
1721
1579
|
for (const cookie of actionPendingCookies) {
|
|
1722
1580
|
redirectHeaders.append("Set-Cookie", cookie);
|
|
1723
1581
|
}
|
|
@@ -1737,7 +1595,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1737
1595
|
searchParams: url.searchParams,
|
|
1738
1596
|
params: actionParams,
|
|
1739
1597
|
});
|
|
1740
|
-
element = buildPageElement(actionRoute, actionParams, undefined, url.searchParams);
|
|
1598
|
+
element = await buildPageElement(actionRoute, actionParams, undefined, url.searchParams);
|
|
1741
1599
|
} else {
|
|
1742
1600
|
element = createElement("div", null, "Page not found");
|
|
1743
1601
|
}
|
|
@@ -1760,15 +1618,15 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1760
1618
|
const actionPendingCookies = getAndClearPendingCookies();
|
|
1761
1619
|
const actionDraftCookie = getDraftModeCookieHeader();
|
|
1762
1620
|
|
|
1763
|
-
const actionHeaders = { "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" };
|
|
1764
|
-
|
|
1621
|
+
const actionHeaders = new Headers({ "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" });
|
|
1622
|
+
__mergeMiddlewareResponseHeaders(actionHeaders, _mwCtx.headers);
|
|
1765
1623
|
if (actionPendingCookies.length > 0 || actionDraftCookie) {
|
|
1766
1624
|
for (const cookie of actionPendingCookies) {
|
|
1767
|
-
|
|
1625
|
+
actionHeaders.append("Set-Cookie", cookie);
|
|
1768
1626
|
}
|
|
1769
|
-
if (actionDraftCookie)
|
|
1627
|
+
if (actionDraftCookie) actionHeaders.append("Set-Cookie", actionDraftCookie);
|
|
1770
1628
|
}
|
|
1771
|
-
return
|
|
1629
|
+
return new Response(rscStream, { status: _mwCtx.status ?? 200, headers: actionHeaders });
|
|
1772
1630
|
} catch (err) {
|
|
1773
1631
|
getAndClearPendingCookies(); // Clear pending cookies on error
|
|
1774
1632
|
console.error("[vinext] Server action error:", err);
|
|
@@ -1846,7 +1704,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
1846
1704
|
}
|
|
1847
1705
|
` : ""}
|
|
1848
1706
|
// Render custom not-found page if available, otherwise plain 404
|
|
1849
|
-
const notFoundResponse = await renderNotFoundPage(null, isRscRequest, request);
|
|
1707
|
+
const notFoundResponse = await renderNotFoundPage(null, isRscRequest, request, undefined, _scriptNonce);
|
|
1850
1708
|
if (notFoundResponse) return notFoundResponse;
|
|
1851
1709
|
setHeadersContext(null);
|
|
1852
1710
|
setNavigationContext(null);
|
|
@@ -2059,6 +1917,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2059
1917
|
if (
|
|
2060
1918
|
process.env.NODE_ENV === "production" &&
|
|
2061
1919
|
!isForceDynamic &&
|
|
1920
|
+
(isRscRequest || !_scriptNonce) &&
|
|
2062
1921
|
revalidateSeconds !== null && revalidateSeconds > 0 && revalidateSeconds !== Infinity
|
|
2063
1922
|
) {
|
|
2064
1923
|
const __cachedPageResponse = await __readAppPageCacheResponse({
|
|
@@ -2148,7 +2007,31 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2148
2007
|
},
|
|
2149
2008
|
isRscRequest,
|
|
2150
2009
|
matchSourceRouteParams(pattern) {
|
|
2151
|
-
|
|
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;
|
|
2152
2035
|
},
|
|
2153
2036
|
renderInterceptResponse(sourceRoute, interceptElement) {
|
|
2154
2037
|
const interceptOnError = createRscOnErrorHandler(
|
|
@@ -2163,8 +2046,11 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2163
2046
|
// by the client, and async server components that run during consumption need the
|
|
2164
2047
|
// context to still be live. The AsyncLocalStorage scope from runWithRequestContext
|
|
2165
2048
|
// handles cleanup naturally when all async continuations complete.
|
|
2049
|
+
const interceptHeaders = new Headers({ "Content-Type": "text/x-component; charset=utf-8", "Vary": "RSC, Accept" });
|
|
2050
|
+
__mergeMiddlewareResponseHeaders(interceptHeaders, _mwCtx.headers);
|
|
2166
2051
|
return new Response(interceptStream, {
|
|
2167
|
-
|
|
2052
|
+
status: _mwCtx.status ?? 200,
|
|
2053
|
+
headers: interceptHeaders,
|
|
2168
2054
|
});
|
|
2169
2055
|
},
|
|
2170
2056
|
searchParams: url.searchParams,
|
|
@@ -2187,7 +2073,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2187
2073
|
return buildPageElement(route, params, interceptOpts, url.searchParams);
|
|
2188
2074
|
},
|
|
2189
2075
|
renderErrorBoundaryPage(buildErr) {
|
|
2190
|
-
return renderErrorBoundaryPage(route, buildErr, isRscRequest, request, params);
|
|
2076
|
+
return renderErrorBoundaryPage(route, buildErr, isRscRequest, request, params, _scriptNonce);
|
|
2191
2077
|
},
|
|
2192
2078
|
renderSpecialError(__buildSpecialError) {
|
|
2193
2079
|
return __buildAppPageSpecialErrorResponse({
|
|
@@ -2196,9 +2082,16 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2196
2082
|
setNavigationContext(null);
|
|
2197
2083
|
},
|
|
2198
2084
|
renderFallbackPage(statusCode) {
|
|
2199
|
-
return renderHTTPAccessFallbackPage(
|
|
2200
|
-
|
|
2201
|
-
|
|
2085
|
+
return renderHTTPAccessFallbackPage(
|
|
2086
|
+
route,
|
|
2087
|
+
statusCode,
|
|
2088
|
+
isRscRequest,
|
|
2089
|
+
request,
|
|
2090
|
+
{
|
|
2091
|
+
matchedParams: params,
|
|
2092
|
+
},
|
|
2093
|
+
_scriptNonce,
|
|
2094
|
+
);
|
|
2202
2095
|
},
|
|
2203
2096
|
requestUrl: request.url,
|
|
2204
2097
|
specialError: __buildSpecialError,
|
|
@@ -2215,6 +2108,19 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2215
2108
|
// rscCssTransform — no manual loadCss() call needed.
|
|
2216
2109
|
const _hasLoadingBoundary = !!(route.loading && route.loading.default);
|
|
2217
2110
|
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);
|
|
2218
2124
|
return __renderAppPageLifecycle({
|
|
2219
2125
|
cleanPathname,
|
|
2220
2126
|
clearRequestContext() {
|
|
@@ -2260,11 +2166,11 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2260
2166
|
return LayoutComp({ params: _asyncLayoutParams, children: null });
|
|
2261
2167
|
},
|
|
2262
2168
|
probePage() {
|
|
2263
|
-
return PageComponent({ params });
|
|
2169
|
+
return PageComponent({ params: _asyncLayoutParams, searchParams: _asyncSearchParams });
|
|
2264
2170
|
},
|
|
2265
2171
|
revalidateSeconds,
|
|
2266
2172
|
renderErrorBoundaryResponse(renderErr) {
|
|
2267
|
-
return renderErrorBoundaryPage(route, renderErr, isRscRequest, request, params);
|
|
2173
|
+
return renderErrorBoundaryPage(route, renderErr, isRscRequest, request, params, _scriptNonce);
|
|
2268
2174
|
},
|
|
2269
2175
|
async renderLayoutSpecialError(__layoutSpecialError, li) {
|
|
2270
2176
|
return __buildAppPageSpecialErrorResponse({
|
|
@@ -2287,11 +2193,18 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2287
2193
|
}
|
|
2288
2194
|
if (!parentNotFound) parentNotFound = ${rootNotFoundVar ? `${rootNotFoundVar}?.default` : "null"};
|
|
2289
2195
|
const parentLayouts = route.layouts.slice(0, li);
|
|
2290
|
-
return renderHTTPAccessFallbackPage(
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2196
|
+
return renderHTTPAccessFallbackPage(
|
|
2197
|
+
route,
|
|
2198
|
+
statusCode,
|
|
2199
|
+
isRscRequest,
|
|
2200
|
+
request,
|
|
2201
|
+
{
|
|
2202
|
+
boundaryComponent: parentNotFound,
|
|
2203
|
+
layouts: parentLayouts,
|
|
2204
|
+
matchedParams: params,
|
|
2205
|
+
},
|
|
2206
|
+
_scriptNonce,
|
|
2207
|
+
);
|
|
2295
2208
|
},
|
|
2296
2209
|
requestUrl: request.url,
|
|
2297
2210
|
specialError: __layoutSpecialError,
|
|
@@ -2304,9 +2217,16 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2304
2217
|
setNavigationContext(null);
|
|
2305
2218
|
},
|
|
2306
2219
|
renderFallbackPage(statusCode) {
|
|
2307
|
-
return renderHTTPAccessFallbackPage(
|
|
2308
|
-
|
|
2309
|
-
|
|
2220
|
+
return renderHTTPAccessFallbackPage(
|
|
2221
|
+
route,
|
|
2222
|
+
statusCode,
|
|
2223
|
+
isRscRequest,
|
|
2224
|
+
request,
|
|
2225
|
+
{
|
|
2226
|
+
matchedParams: params,
|
|
2227
|
+
},
|
|
2228
|
+
_scriptNonce,
|
|
2229
|
+
);
|
|
2310
2230
|
},
|
|
2311
2231
|
requestUrl: request.url,
|
|
2312
2232
|
specialError,
|
|
@@ -2321,6 +2241,7 @@ async function _handleRequest(request, __reqCtx, _mwCtx) {
|
|
|
2321
2241
|
// each have their own ALS store and are unaffected.
|
|
2322
2242
|
return _suppressHookWarningAls.run(true, probe);
|
|
2323
2243
|
},
|
|
2244
|
+
scriptNonce: _scriptNonce,
|
|
2324
2245
|
waitUntil(__cachePromise) {
|
|
2325
2246
|
_getRequestExecutionContext()?.waitUntil(__cachePromise);
|
|
2326
2247
|
},
|