vinext 1.4.0 → 1.4.1
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 +20 -20
- package/dist/build/prerender.js +3 -2
- package/dist/check.js +3 -6
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +19 -3
- package/dist/config/config-matchers.js +2 -0
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +52 -2
- package/dist/config/next-config.d.ts +6 -0
- package/dist/config/next-config.js +18 -3
- package/dist/entries/app-rsc-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +3 -1
- package/dist/index.js +29 -20
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/server/api-handler.js +2 -1
- package/dist/server/app-browser-entry.js +7 -3
- package/dist/server/app-browser-rsc-redirect.js +3 -3
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-visible-commit.js +2 -2
- package/dist/server/app-optimistic-routing.js +2 -3
- package/dist/server/app-page-boundary-render.js +5 -10
- package/dist/server/app-page-dispatch.d.ts +0 -1
- package/dist/server/app-page-dispatch.js +0 -1
- package/dist/server/app-page-element-builder.js +3 -3
- package/dist/server/app-page-execution.js +9 -6
- package/dist/server/app-page-render.d.ts +0 -1
- package/dist/server/app-page-render.js +14 -14
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.js +22 -5
- package/dist/server/app-page-stream.d.ts +10 -8
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-route-handler-execution.js +3 -2
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +11 -7
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +10 -10
- package/dist/server/app-rsc-cache-busting.js +27 -68
- package/dist/server/app-rsc-error-handler.js +1 -1
- package/dist/server/app-rsc-errors.js +4 -1
- package/dist/server/app-rsc-handler.js +53 -62
- package/dist/server/app-rsc-request-normalization.d.ts +10 -12
- package/dist/server/app-rsc-request-normalization.js +11 -14
- package/dist/server/app-rsc-response-stage.js +4 -12
- package/dist/server/app-server-action-execution.js +8 -4
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +13 -8
- package/dist/server/app-worker-stages.d.ts +12 -3
- package/dist/server/app-worker-stages.js +37 -4
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +2 -1
- package/dist/server/image-optimization.d.ts +5 -0
- package/dist/server/image-optimization.js +6 -1
- package/dist/server/isr-cache.js +4 -1
- package/dist/server/metadata-route-response.js +1 -1
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +7 -3
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +2 -0
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +17 -6
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-stage-entry.js +24 -4
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +42 -8
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +9 -4
- package/dist/server/request-pipeline.js +23 -15
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/shims/cache-request-state.d.ts +6 -6
- package/dist/shims/cache-request-state.js +6 -36
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +77 -47
- package/dist/shims/cache.d.ts +10 -5
- package/dist/shims/cache.js +35 -22
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/fetch-cache.js +6 -2
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.js +5 -3
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/link.js +5 -10
- package/dist/shims/navigation.js +2 -3
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/slot.d.ts +6 -2
- package/dist/shims/slot.js +10 -3
- package/dist/shims/unified-request-context.d.ts +6 -0
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/package.json +1 -1
|
@@ -22,8 +22,10 @@ function encodeBase64Url(bytes) {
|
|
|
22
22
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
23
23
|
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
25
|
+
function serializeHeaderValue(value) {
|
|
26
|
+
if (value === null) return "0";
|
|
27
|
+
if (value === "0") return "\\0";
|
|
28
|
+
return value.replaceAll("\\", "\\\\").replaceAll(",", "\\,");
|
|
27
29
|
}
|
|
28
30
|
function normalizeCompatibilityId(value) {
|
|
29
31
|
return value && value.length > 0 ? value : null;
|
|
@@ -57,9 +59,9 @@ function resolveHardNavigationTargetFromRscResponse(responseUrl, currentHref, or
|
|
|
57
59
|
const parsed = new URL(responseUrl, origin);
|
|
58
60
|
stripRscCacheBustingSearchParam(parsed);
|
|
59
61
|
const origUrl = new URL(currentHref, origin);
|
|
60
|
-
let pathname =
|
|
62
|
+
let pathname = parsed.pathname;
|
|
61
63
|
if (origUrl.pathname.length > 1 && origUrl.pathname.endsWith("/") && !pathname.endsWith("/")) pathname += "/";
|
|
62
|
-
let hardNavigationTarget = pathname + parsed.search;
|
|
64
|
+
let hardNavigationTarget = toPathAbsolutePathname(pathname) + parsed.search;
|
|
63
65
|
if (origUrl.hash) hardNavigationTarget += origUrl.hash;
|
|
64
66
|
return hardNavigationTarget;
|
|
65
67
|
}
|
|
@@ -74,21 +76,21 @@ function normalizeRenderModeHeaderValue(value) {
|
|
|
74
76
|
const renderMode = parseAppRscRenderMode(value);
|
|
75
77
|
return renderMode === "navigation" ? null : renderMode;
|
|
76
78
|
}
|
|
77
|
-
function createCacheBustingInput(headers
|
|
79
|
+
function createCacheBustingInput(headers) {
|
|
78
80
|
const values = [
|
|
79
81
|
headers.get(NEXT_ROUTER_PREFETCH_HEADER),
|
|
80
82
|
headers.get(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER),
|
|
81
83
|
headers.get(NEXT_ROUTER_STATE_TREE_HEADER),
|
|
82
84
|
headers.get(NEXT_URL_HEADER),
|
|
83
85
|
headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER),
|
|
84
|
-
|
|
86
|
+
headers.get(VINEXT_INTERCEPTION_ID_HEADER),
|
|
85
87
|
headers.get(VINEXT_MOUNTED_SLOTS_HEADER),
|
|
86
|
-
|
|
88
|
+
normalizeRenderModeHeaderValue(headers.get(VINEXT_RSC_RENDER_MODE_HEADER))
|
|
87
89
|
];
|
|
88
90
|
const stateFingerprint = headers.get(VINEXT_RSC_STATE_FINGERPRINT_HEADER);
|
|
89
|
-
if (
|
|
91
|
+
if (stateFingerprint !== null) values.push(stateFingerprint);
|
|
90
92
|
if (values.every((value) => value === null)) return null;
|
|
91
|
-
return values.map(
|
|
93
|
+
return values.map(serializeHeaderValue).join(",");
|
|
92
94
|
}
|
|
93
95
|
async function sha256CacheBustingHash(input) {
|
|
94
96
|
const subtle = globalThis.crypto?.subtle;
|
|
@@ -147,13 +149,6 @@ function keepOnlyValidatedRscCacheBustingSearchParam(url, isRscRequest) {
|
|
|
147
149
|
url.search = "";
|
|
148
150
|
if (hash !== null) setRscCacheBustingSearchParam(url, hash);
|
|
149
151
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Remove a trailing `.rsc` suffix from a pathname. Returns the pathname
|
|
152
|
-
* unchanged when the suffix is absent.
|
|
153
|
-
*/
|
|
154
|
-
function stripRscSuffix(pathname) {
|
|
155
|
-
return pathname.endsWith(".rsc") ? pathname.slice(0, -4) : pathname;
|
|
156
|
-
}
|
|
157
152
|
function createCanonicalRscRequestHeaders(deploymentId = getDeploymentId()) {
|
|
158
153
|
const headers = new Headers({
|
|
159
154
|
Accept: VINEXT_RSC_CONTENT_TYPE,
|
|
@@ -232,15 +227,22 @@ function parseRscRequestPath(href) {
|
|
|
232
227
|
return new URL(beforeHash, RSC_REQUEST_URL_BASE);
|
|
233
228
|
}
|
|
234
229
|
/**
|
|
230
|
+
* A pathname as the start of a path-absolute reference. One that begins with
|
|
231
|
+
* "//" would serialize as a protocol-relative URL naming another host, so it
|
|
232
|
+
* keeps a "/." prefix, as the WHATWG URL serializer does. URL resolution drops
|
|
233
|
+
* the dot segment, so the reference still targets the same pathname on the
|
|
234
|
+
* origin it is resolved against.
|
|
235
|
+
*/
|
|
236
|
+
function toPathAbsolutePathname(pathname) {
|
|
237
|
+
return pathname.startsWith("//") ? `/.${pathname}` : pathname;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
235
240
|
* Serialize the path-absolute reference callers fetch against the app origin.
|
|
236
|
-
* A pathname
|
|
237
|
-
*
|
|
238
|
-
* WHATWG URL serializer does. URL resolution drops the dot segment, so the
|
|
239
|
-
* request still targets the same pathname on the app origin, as Next.js's
|
|
240
|
-
* full-URL fetch does.
|
|
241
|
+
* A "//" pathname keeps its "/." prefix so the request still targets the same
|
|
242
|
+
* pathname on the app origin, as Next.js's full-URL fetch does.
|
|
241
243
|
*/
|
|
242
244
|
function formatRscRequestPath(url) {
|
|
243
|
-
return `${url.pathname
|
|
245
|
+
return `${toPathAbsolutePathname(url.pathname)}${url.search}`;
|
|
244
246
|
}
|
|
245
247
|
async function createRscRequestUrl(href, headers) {
|
|
246
248
|
const url = parseRscRequestPath(href);
|
|
@@ -275,55 +277,12 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
275
277
|
const url = new URL(options.request.url);
|
|
276
278
|
const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
|
|
277
279
|
const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);
|
|
278
|
-
if (actualHash
|
|
279
|
-
const acceptedHashes = /* @__PURE__ */ new Set([expectedHash]);
|
|
280
|
-
if (actualHash !== null && actualHash !== expectedHash) {
|
|
281
|
-
acceptedHashes.add(computeLegacyRscCacheBustingSearchParam(options.request.headers));
|
|
282
|
-
const compatibilityInputs = [];
|
|
283
|
-
const hasInterceptionId = options.request.headers.has(VINEXT_INTERCEPTION_ID_HEADER);
|
|
284
|
-
const hasStateFingerprint = options.request.headers.has(VINEXT_RSC_STATE_FINGERPRINT_HEADER);
|
|
285
|
-
const hasNormalRenderMode = normalizeRenderModeHeaderValue(options.request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) === null;
|
|
286
|
-
if (!hasInterceptionId) compatibilityInputs.push({ includeInterceptionIdHeader: false });
|
|
287
|
-
if (hasStateFingerprint) {
|
|
288
|
-
compatibilityInputs.push({ includeStateFingerprintHeader: false });
|
|
289
|
-
if (!hasInterceptionId) compatibilityInputs.push({
|
|
290
|
-
includeInterceptionIdHeader: false,
|
|
291
|
-
includeStateFingerprintHeader: false
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
if (hasNormalRenderMode) {
|
|
295
|
-
compatibilityInputs.push({ includeRenderModeHeader: false });
|
|
296
|
-
if (!hasInterceptionId) compatibilityInputs.push({
|
|
297
|
-
includeInterceptionIdHeader: false,
|
|
298
|
-
includeRenderModeHeader: false
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
if (hasStateFingerprint && hasNormalRenderMode) {
|
|
302
|
-
compatibilityInputs.push({
|
|
303
|
-
includeRenderModeHeader: false,
|
|
304
|
-
includeStateFingerprintHeader: false
|
|
305
|
-
});
|
|
306
|
-
if (!hasInterceptionId) compatibilityInputs.push({
|
|
307
|
-
includeInterceptionIdHeader: false,
|
|
308
|
-
includeRenderModeHeader: false,
|
|
309
|
-
includeStateFingerprintHeader: false
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
for (const compatibilityOptions of compatibilityInputs) {
|
|
313
|
-
const input = createCacheBustingInput(options.request.headers, compatibilityOptions);
|
|
314
|
-
if (input === null) acceptedHashes.add("");
|
|
315
|
-
else {
|
|
316
|
-
acceptedHashes.add(await sha256CacheBustingHash(input));
|
|
317
|
-
acceptedHashes.add(fnv1a64(input));
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
if (actualHash !== null && acceptedHashes.has(actualHash)) return null;
|
|
280
|
+
if (actualHash !== null && (actualHash === expectedHash || actualHash === computeLegacyRscCacheBustingSearchParam(options.request.headers))) return null;
|
|
322
281
|
setRscCacheBustingSearchParam(url, expectedHash);
|
|
323
282
|
return new Response(null, {
|
|
324
283
|
status: 307,
|
|
325
|
-
headers: { Location:
|
|
284
|
+
headers: { Location: formatRscRequestPath(url) }
|
|
326
285
|
});
|
|
327
286
|
}
|
|
328
287
|
//#endregion
|
|
329
|
-
export { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam,
|
|
288
|
+
export { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, toPathAbsolutePathname };
|
|
@@ -23,7 +23,7 @@ function createAppRscOnErrorHandler(reportRequestError, request, pathname, route
|
|
|
23
23
|
routerKind: "App Router",
|
|
24
24
|
routePath: routePath || pathname,
|
|
25
25
|
routeType: overrides?.routeType ?? "render",
|
|
26
|
-
renderSource: overrides?.renderSource ?? (request.headers.get("RSC") === "1"
|
|
26
|
+
renderSource: overrides?.renderSource ?? (request.headers.get("RSC") === "1" ? "react-server-components-payload" : "react-server-components"),
|
|
27
27
|
revalidateReason: isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) ? "on-demand" : overrides?.revalidateReason
|
|
28
28
|
};
|
|
29
29
|
let loggedErrors = loggedErrorsByRequest.get(request);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
2
|
+
import { logRequestError } from "./request-error-log.js";
|
|
3
|
+
import { rewriteClientHookError } from "../shims/client-hook-error.js";
|
|
2
4
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
3
5
|
import { isAppRenderAbortError } from "./app-render-abort-error.js";
|
|
4
6
|
import { getProperError } from "./proper-error.js";
|
|
@@ -87,6 +89,7 @@ function createRscOnErrorHandler(options) {
|
|
|
87
89
|
if (!hasDigest(properError) && (properError !== reportableError || options.attachDigest !== false)) try {
|
|
88
90
|
Object.assign(properError, { digest });
|
|
89
91
|
} catch {}
|
|
92
|
+
if (nodeEnv !== "production") rewriteClientHookError(properError);
|
|
90
93
|
if (options.requestInfo && options.errorContext) options.reportRequestError(properError, options.requestInfo, options.errorContext);
|
|
91
94
|
if (process.env.VINEXT_PRERENDER === "1" && error) {
|
|
92
95
|
if (!loggedPrerenderErrors?.has(reportableError)) {
|
|
@@ -94,7 +97,7 @@ function createRscOnErrorHandler(options) {
|
|
|
94
97
|
const route = options.requestInfo?.path ?? options.errorContext?.routePath ?? "<unknown>";
|
|
95
98
|
console.error(`[vinext] Error prerendering route ${JSON.stringify(route)}:`, reportableError);
|
|
96
99
|
}
|
|
97
|
-
} else if (!(reportableError !== error && thrownHasDigest) && !wasLogged(reportableError))
|
|
100
|
+
} else if (!(reportableError !== error && thrownHasDigest) && !wasLogged(reportableError)) logRequestError("[vinext] Server render error:", properError);
|
|
98
101
|
return digest;
|
|
99
102
|
};
|
|
100
103
|
}
|
|
@@ -8,7 +8,7 @@ import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base
|
|
|
8
8
|
import "./app-rsc-vary.js";
|
|
9
9
|
import { ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_REWRITTEN_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
|
|
10
10
|
import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
11
|
-
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute } from "./request-pipeline.js";
|
|
11
|
+
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute, stripRequestUrlFragment } from "./request-pipeline.js";
|
|
12
12
|
import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
|
|
13
13
|
import { normalizePathnameForRouteMatch, normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
14
14
|
import { patternToNextFormat } from "../routing/route-validation.js";
|
|
@@ -31,7 +31,7 @@ import { openForwardedMiddlewareContext } from "./forwarded-middleware-context.j
|
|
|
31
31
|
import { consumeResponseStageLinkProvenance, copyLinkHeaderProvenance } from "./app-response-header-provenance.js";
|
|
32
32
|
import { setFrameworkRequestRoute, traceFrameworkRequest } from "./request-tracing.js";
|
|
33
33
|
import { mergeMiddlewareResponseHeaders, mergeMiddlewareResponseHeadersOntoResponse, withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
|
|
34
|
-
import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestUrl, hasRscCacheBustingSearchParam, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam
|
|
34
|
+
import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestUrl, hasRscCacheBustingSearchParam, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
|
|
35
35
|
import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
36
36
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
|
|
37
37
|
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
@@ -44,7 +44,7 @@ import { buildPageCacheTags } from "./implicit-tags.js";
|
|
|
44
44
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
45
45
|
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
46
46
|
import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
|
|
47
|
-
import { createSharedAppCacheIdentity, createSharedAppPageCacheIdentity, createSharedHybridPagesCacheIdentity, isStaticCandidateAppPageDispatch, prepareSharedAppPageDispatch, withoutAppPageDispatchQuery } from "./app-worker-stages.js";
|
|
47
|
+
import { createSharedAppCacheIdentity, createSharedAppPageCacheIdentity, createSharedAppRouteCacheIdentity, createSharedHybridPagesCacheIdentity, isStaticCandidateAppPageDispatch, prepareSharedAppPageDispatch, withoutAppPageDispatchQuery } from "./app-worker-stages.js";
|
|
48
48
|
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
49
49
|
import { applyAppRscConfigHeaders, finalizeAppRscResponse, markAppRscResponseConfigHeadersApplied } from "./app-rsc-response-finalizer.js";
|
|
50
50
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
@@ -257,13 +257,6 @@ function requestWithoutRscCacheBustingSearchParam(request) {
|
|
|
257
257
|
stripRscCacheBustingSearchParam(url);
|
|
258
258
|
return cloneRequestWithUrl(request, url.toString());
|
|
259
259
|
}
|
|
260
|
-
function requestWithoutRscSuffix(request) {
|
|
261
|
-
const url = new URL(request.url);
|
|
262
|
-
const pathname = stripRscSuffix(url.pathname);
|
|
263
|
-
if (pathname === url.pathname) return request;
|
|
264
|
-
url.pathname = pathname;
|
|
265
|
-
return cloneRequestWithUrl(request, url.toString());
|
|
266
|
-
}
|
|
267
260
|
/** Send a response with the never-cache policy, rebuilding immutable headers. */
|
|
268
261
|
function withNeverCacheControl(response) {
|
|
269
262
|
const applyNoStore = (headers) => {
|
|
@@ -320,8 +313,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
320
313
|
setInterceptionResponseUncacheable(true);
|
|
321
314
|
return badRequestResponse();
|
|
322
315
|
}
|
|
323
|
-
const {
|
|
324
|
-
let
|
|
316
|
+
const { pathname, requestPathname } = normalized;
|
|
317
|
+
let cleanPathname = pathname;
|
|
325
318
|
let resolvedUrl = cleanPathname + url.search;
|
|
326
319
|
const originalResolvedUrl = serializeResolvedUrl(resolvedUrl, url);
|
|
327
320
|
const getResolvedSearchParams = () => new URL(resolvedUrl, url).searchParams;
|
|
@@ -331,7 +324,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
331
324
|
hadBasePath
|
|
332
325
|
};
|
|
333
326
|
let cleanPathnameIsRequestPathname = true;
|
|
334
|
-
const matchCleanPathname = () => cleanPathnameIsRequestPathname && options.matchRequestRoute ? options.matchRequestRoute(
|
|
327
|
+
const matchCleanPathname = () => cleanPathnameIsRequestPathname && options.matchRequestRoute ? options.matchRequestRoute(requestPathname) : options.matchRoute(cleanPathname);
|
|
335
328
|
if (interceptionIdHeader !== null && (!isRscRequest || interceptionContextHeader === null || request.method !== "GET" && request.method !== "HEAD" || !options.hasInterceptionId(interceptionIdHeader))) {
|
|
336
329
|
setInterceptionResponseUncacheable(true);
|
|
337
330
|
return badRequestResponse();
|
|
@@ -348,7 +341,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
348
341
|
if (sourceMatch.interceptionSourceIsConcrete !== void 0) return sourceMatch.interceptionSourceIsConcrete;
|
|
349
342
|
return sourceContext !== null && (options.matchRequestRoute ?? options.matchRoute)(sourceContext)?.route === sourceMatch.route;
|
|
350
343
|
};
|
|
351
|
-
if (provesConcreteInterceptionSource(hadBasePath && hasRawInterceptionContext && interceptionContextHeader !== null ? options.matchInterceptRoute?.(
|
|
344
|
+
if (provesConcreteInterceptionSource(hadBasePath && hasRawInterceptionContext && interceptionContextHeader !== null ? options.matchInterceptRoute?.(requestPathname, interceptionContextHeader, interceptionIdHeader) ?? null : null)) setInterceptionResponseUncacheable(false);
|
|
352
345
|
if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths" || pathname === "/__vinext/prerender/metadata-routes") {
|
|
353
346
|
const { handleAppPrerenderEndpoint } = await import("./app-prerender-endpoints.js");
|
|
354
347
|
const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {
|
|
@@ -364,16 +357,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
364
357
|
if (prerenderEndpointResponse) return prerenderEndpointResponse;
|
|
365
358
|
}
|
|
366
359
|
if (!isDataRequest && !options.skipTrailingSlashRedirect) {
|
|
367
|
-
const trailingSlashRedirect = options.trailingSlash && options.isMetadataRoutePath && await options.isMetadataRoutePath(cleanPathname) ? null : normalizeTrailingSlash(
|
|
360
|
+
const trailingSlashRedirect = options.trailingSlash && options.isMetadataRoutePath && await options.isMetadataRoutePath(cleanPathname) ? null : normalizeTrailingSlash(requestPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
|
|
368
361
|
if (trailingSlashRedirect) return trailingSlashRedirect;
|
|
369
362
|
}
|
|
370
363
|
const matchPathname = (p) => normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });
|
|
371
|
-
const restoreLocaleRootTrailingSlash = !pagesDataRequest && shouldRestoreLocaleRootTrailingSlash(
|
|
372
|
-
const headerMatchPathname = normalizeDefaultLocalePathname(
|
|
364
|
+
const restoreLocaleRootTrailingSlash = !pagesDataRequest && shouldRestoreLocaleRootTrailingSlash(url.pathname, options);
|
|
365
|
+
const headerMatchPathname = normalizeDefaultLocalePathname(requestPathname, options.i18nConfig, {
|
|
373
366
|
hostname: url.hostname,
|
|
374
367
|
restoreRootTrailingSlash: restoreLocaleRootTrailingSlash
|
|
375
368
|
});
|
|
376
|
-
const redirectPathname = matchPathname(
|
|
369
|
+
const redirectPathname = matchPathname(requestPathname);
|
|
377
370
|
const configMatchers = HAS_CONFIG_REDIRECTS && options.configRedirects.length ? await import("../config/config-matchers.js") : null;
|
|
378
371
|
const redirect = configMatchers ? configMatchers.matchRedirect(redirectPathname, options.configRedirects, preMiddlewareRequestContext, basePathState, dispatchResponseStage ? void 0 : markConditionalRedirectCacheability) : null;
|
|
379
372
|
if (configMatchers && redirect) {
|
|
@@ -399,9 +392,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
399
392
|
};
|
|
400
393
|
const runMiddleware = isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) ? void 0 : options.runMiddleware;
|
|
401
394
|
const isolatedMiddlewareSource = runMiddleware && request.body && !request.bodyUsed ? request.clone() : null;
|
|
402
|
-
const
|
|
403
|
-
const
|
|
404
|
-
const isolatedMiddlewareRequest = isolatedMiddlewareSource ? requestWithoutRscCacheBustingSearchParam(requestWithoutRscSuffix(isolatedMiddlewareSource)) : void 0;
|
|
395
|
+
const userlandRequest = requestWithoutRscCacheBustingSearchParam(request);
|
|
396
|
+
const isolatedMiddlewareRequest = isolatedMiddlewareSource ? requestWithoutRscCacheBustingSearchParam(isolatedMiddlewareSource) : void 0;
|
|
405
397
|
let didMiddlewareRewrite = false;
|
|
406
398
|
let didMiddlewareRewritePathname = false;
|
|
407
399
|
let resolvedPathnameHasBasePath = hadBasePath;
|
|
@@ -413,7 +405,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
413
405
|
const middlewareResult = await runMiddleware({
|
|
414
406
|
cleanPathname,
|
|
415
407
|
context: middlewareContext,
|
|
416
|
-
externalRewriteRequest:
|
|
408
|
+
externalRewriteRequest: request,
|
|
417
409
|
hadBasePath,
|
|
418
410
|
isDataRequest: isMiddlewareDataRequest,
|
|
419
411
|
middlewareRequest: isolatedMiddlewareRequest,
|
|
@@ -448,8 +440,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
448
440
|
cleanPathname = middlewareResult.cleanPathname;
|
|
449
441
|
didMiddlewareRewrite = middlewareResult.rewritten;
|
|
450
442
|
if (didMiddlewareRewrite) resolvedPathnameHasBasePath = middlewareResult.rewriteHadBasePath ?? true;
|
|
451
|
-
if (didMiddlewareRewrite || cleanPathname !==
|
|
452
|
-
didMiddlewareRewritePathname = cleanPathname !==
|
|
443
|
+
if (didMiddlewareRewrite || cleanPathname !== pathname) cleanPathnameIsRequestPathname = false;
|
|
444
|
+
didMiddlewareRewritePathname = cleanPathname !== pathname;
|
|
453
445
|
if (middlewareResult.search !== null) url.search = middlewareResult.search;
|
|
454
446
|
resolvedUrl = cleanPathname + url.search;
|
|
455
447
|
}
|
|
@@ -505,7 +497,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
505
497
|
const rscPath = canonicalRsc.navigation ? createCanonicalRscRequestUrl(dispatchRequest.url) : await createRscRequestUrl(dispatchRequest.url, canonicalRsc.headers);
|
|
506
498
|
dispatchRequest = cloneRequestWithUrl(dispatchRequest, new URL(rscPath, dispatchRequest.url).toString());
|
|
507
499
|
}
|
|
508
|
-
const cacheIdentity = cache !== "shared" || stageProps.kind === "app-full-request" || stageProps.kind === "hybrid-pages" || !adapterUsesSharedCacheIdentity() ? void 0 :
|
|
500
|
+
const cacheIdentity = cache !== "shared" || stageProps.kind === "app-full-request" || stageProps.kind === "hybrid-pages" || !adapterUsesSharedCacheIdentity() ? void 0 : adapterSharedCacheIdentity() !== "query-free" || responseStagePolicy !== null ? createSharedAppCacheIdentity(dispatchRequest, stageProps) : stageProps.kind === "app-page" && stageProps.matchKind !== "interception" && stageProps.interceptionContext === null && stageProps.interceptionId === null && stageProps.mountedSlotsHeader === null ? createSharedAppPageCacheIdentity(dispatchRequest, stageProps) : stageProps.kind === "app-metadata" || stageProps.kind === "app-route-handler" && stageProps.matchKind !== "interception" ? createSharedAppRouteCacheIdentity(dispatchRequest, stageProps) : createSharedAppCacheIdentity(dispatchRequest, stageProps);
|
|
509
501
|
let response = await dispatchResponseStage(dispatchRequest, stageProps, cacheIdentity ? {
|
|
510
502
|
cache,
|
|
511
503
|
cacheIdentity
|
|
@@ -536,7 +528,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
536
528
|
};
|
|
537
529
|
const renderMetadataRouteIfMatched = async () => {
|
|
538
530
|
if (!filesystemRouteEligible || (options.isMetadataRoute ? !options.isMetadataRoute(cleanPathname) : !options.handleMetadataRouteRequest)) return null;
|
|
539
|
-
const metadataRoutePathname = cleanPathnameIsRequestPathname ?
|
|
531
|
+
const metadataRoutePathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
|
|
540
532
|
const metadataResponseStage = transportedResponseStage ?? options.renderResponseStageLocally;
|
|
541
533
|
if (metadataResponseStage) {
|
|
542
534
|
const response = await metadataResponseStage(responseStageRequest(), {
|
|
@@ -616,9 +608,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
616
608
|
basePathState: currentBasePathState(),
|
|
617
609
|
clearRequestContext: options.clearRequestContext,
|
|
618
610
|
middlewareContext,
|
|
619
|
-
request
|
|
611
|
+
request,
|
|
620
612
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
621
|
-
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ?
|
|
613
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname),
|
|
622
614
|
rewrites: [rewrite],
|
|
623
615
|
validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
|
|
624
616
|
}, matchPathname(cleanPathname), dispatchResponseStage === void 0);
|
|
@@ -663,7 +655,6 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
663
655
|
const publicFileResponse = resolvePublicFileRoute({
|
|
664
656
|
cleanPathname: cleanPathnameIsRequestPathname ? cleanPathname : normalizePathnameForRouteMatch(cleanPathname),
|
|
665
657
|
middlewareContext,
|
|
666
|
-
pathname,
|
|
667
658
|
publicFiles: options.publicFiles,
|
|
668
659
|
request
|
|
669
660
|
});
|
|
@@ -680,7 +671,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
680
671
|
params: {}
|
|
681
672
|
});
|
|
682
673
|
const directPreActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
|
|
683
|
-
const preActionRoutePathname = cleanPathnameIsRequestPathname ?
|
|
674
|
+
const preActionRoutePathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
|
|
684
675
|
let interceptionSourceContext = interceptionSourcePathname !== null ? interceptionContextHeader : null;
|
|
685
676
|
let interceptionSourceMatch = filesystemRouteEligible && interceptionSourcePathname !== null && interceptionContextHeader !== null ? options.matchInterceptRoute?.(preActionRoutePathname, interceptionContextHeader, interceptionIdHeader) ?? null : null;
|
|
686
677
|
let hasVerifiedInterceptionSource = provesConcreteInterceptionSource(interceptionSourceMatch);
|
|
@@ -749,7 +740,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
749
740
|
sourceMiddlewareResult = await runWithHeadersContext(sourceHeadersContext, () => runMiddleware({
|
|
750
741
|
cleanPathname: decodedSourceRequestPathname,
|
|
751
742
|
context: sourceMiddlewareContext,
|
|
752
|
-
externalRewriteRequest:
|
|
743
|
+
externalRewriteRequest: request,
|
|
753
744
|
hadBasePath: resolvedPathnameHasBasePath,
|
|
754
745
|
isDataRequest: isMiddlewareDataRequest,
|
|
755
746
|
request: sourceMiddlewareRequest,
|
|
@@ -792,21 +783,22 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
792
783
|
sourceRulesPathname = sourceMiddlewareResult.cleanPathname;
|
|
793
784
|
}
|
|
794
785
|
}
|
|
795
|
-
if (HAS_CONFIG_REWRITES && options.configRewrites.beforeFiles.length) {
|
|
786
|
+
if (HAS_CONFIG_REWRITES && (options.configRewrites.beforeFiles.length || options.configRewrites.afterFiles.length)) {
|
|
796
787
|
const { matchRewrite } = await import("../config/config-matchers.js");
|
|
797
788
|
const sourceRewriteContext = requestContextForResolvedUrl(buildPostMwRequestContext(userlandRequest), resolvedUrl, url);
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
789
|
+
const rewriteSource = (rewrites, stopAtRoute) => {
|
|
790
|
+
let didRewriteSource = false;
|
|
791
|
+
for (const rewrite of rewrites) {
|
|
792
|
+
const destination = matchRewrite(matchPathname(sourceRulesPathname), [rewrite], sourceRewriteContext, currentBasePathState(), matchPathname(sourceRulesPathname), dispatchResponseStage === void 0 ? markConditionalRewriteCacheability : void 0);
|
|
793
|
+
if (!destination) continue;
|
|
794
|
+
if (isExternalUrl(destination) || destination.includes("?")) return false;
|
|
795
|
+
sourceRulesPathname = pathnameForResolvedUrl(destination);
|
|
796
|
+
didRewriteSource = true;
|
|
797
|
+
if (stopAtRoute && options.matchRoute(sourceRulesPathname)) break;
|
|
805
798
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
if (didRewriteSource && !adoptRewrittenInterceptionSource(sourceRulesPathname)) {
|
|
799
|
+
return !didRewriteSource || adoptRewrittenInterceptionSource(sourceRulesPathname);
|
|
800
|
+
};
|
|
801
|
+
if (!rewriteSource(options.configRewrites.beforeFiles, false) || interceptionSourceMatch.route.isDynamic && !rewriteSource(options.configRewrites.afterFiles, true)) {
|
|
810
802
|
options.clearRequestContext();
|
|
811
803
|
return notFoundResponse();
|
|
812
804
|
}
|
|
@@ -831,7 +823,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
831
823
|
const isInterceptionMatch = interceptionPreActionMatch !== null;
|
|
832
824
|
const rendersRawRequestMatch = options.matchRawRequestRoute !== void 0 && (isPossibleAppRouteActionRequest(request) || isDraftModeRequest(request, options.draftModeSecret) || isDraftModeEnabled());
|
|
833
825
|
const usesRawRequestMatch = () => rendersRawRequestMatch && cleanPathnameIsRequestPathname && !isInterceptionMatch;
|
|
834
|
-
const renderedRouteMatch = (routeMatch) => routeMatch !== null && usesRawRequestMatch() ? options.matchRawRequestRoute(
|
|
826
|
+
const renderedRouteMatch = (routeMatch) => routeMatch !== null && usesRawRequestMatch() ? options.matchRawRequestRoute(requestPathname) ?? routeMatch : routeMatch;
|
|
835
827
|
const renderedPreActionMatch = renderedRouteMatch(preActionMatch);
|
|
836
828
|
if (renderedPreActionMatch) setRootParams(pickRootParams(renderedPreActionMatch.params, renderedPreActionMatch.route.rootParamNames));
|
|
837
829
|
if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch && !preActionMatch.route.isDynamic) {
|
|
@@ -854,9 +846,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
854
846
|
if (routeMatch && isAppRouteHandlerRoute(routeMatch.route)) return null;
|
|
855
847
|
if (!options.handleServerActionRequest) return createMissingServerActionResponse(options, actionId);
|
|
856
848
|
const sourceConfigHeaders = new Headers();
|
|
857
|
-
|
|
858
|
-
sourceConfigUrl.pathname = hadBasePath ? addBasePathToPathname(requestCleanPathname, options.basePath) : requestCleanPathname;
|
|
859
|
-
await applyAppRscConfigHeaders(sourceConfigHeaders, cloneRequestWithUrl(request, sourceConfigUrl.toString()), {
|
|
849
|
+
await applyAppRscConfigHeaders(sourceConfigHeaders, request, {
|
|
860
850
|
basePath: options.basePath,
|
|
861
851
|
configHeaders: options.configHeaders,
|
|
862
852
|
i18nConfig: options.i18nConfig,
|
|
@@ -915,7 +905,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
915
905
|
let match = preActionMatch;
|
|
916
906
|
const renderPagesForMatchKind = async (matchKind) => {
|
|
917
907
|
if (!filesystemRouteEligible) return null;
|
|
918
|
-
const pagesRouteUrl = cleanPathnameIsRequestPathname ?
|
|
908
|
+
const pagesRouteUrl = cleanPathnameIsRequestPathname ? requestPathname + resolvedUrl.slice(pathnameForResolvedUrl(resolvedUrl).length) : resolvedUrl;
|
|
919
909
|
let sharedOuterPolicyNeedsReconciliation = false;
|
|
920
910
|
const dispatchPagesResponseStage = dispatchResponseStage ? async (stageRequest, resourceKind, dataKind, hasRequestAwareDocument, runsInitialProps) => {
|
|
921
911
|
const pagesOnDemandRevalidate = resourceKind === "page" && isOnDemandRevalidateRequest(stageRequest.headers.get("x-prerender-revalidate"));
|
|
@@ -1009,9 +999,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1009
999
|
basePathState: currentBasePathState(),
|
|
1010
1000
|
clearRequestContext: options.clearRequestContext,
|
|
1011
1001
|
middlewareContext,
|
|
1012
|
-
request
|
|
1002
|
+
request,
|
|
1013
1003
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
1014
|
-
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ?
|
|
1004
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname),
|
|
1015
1005
|
rewrites: [rewrite],
|
|
1016
1006
|
validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
|
|
1017
1007
|
}, matchPathname(cleanPathname), dispatchResponseStage === void 0);
|
|
@@ -1057,9 +1047,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1057
1047
|
basePathState: currentBasePathState(),
|
|
1058
1048
|
clearRequestContext: options.clearRequestContext,
|
|
1059
1049
|
middlewareContext,
|
|
1060
|
-
request
|
|
1050
|
+
request,
|
|
1061
1051
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
1062
|
-
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ?
|
|
1052
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname),
|
|
1063
1053
|
rewrites: [rewrite],
|
|
1064
1054
|
validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
|
|
1065
1055
|
}, matchPathname(cleanPathname), dispatchResponseStage === void 0);
|
|
@@ -1096,7 +1086,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1096
1086
|
if (match) break;
|
|
1097
1087
|
}
|
|
1098
1088
|
if (interceptionCacheProofInvalidated && interceptionSourceContext !== null) {
|
|
1099
|
-
const finalInterceptionTargetPathname = cleanPathnameIsRequestPathname ?
|
|
1089
|
+
const finalInterceptionTargetPathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
|
|
1100
1090
|
const finalInterceptionSourceMatch = filesystemRouteEligible && match !== null ? options.matchInterceptRoute?.(finalInterceptionTargetPathname, interceptionSourceContext, interceptionIdHeader) ?? null : null;
|
|
1101
1091
|
const hasVerifiedFinalInterceptionSource = hasVerifiedInterceptionSource && interceptionSourceMatch !== null && provesConcreteInterceptionSource(finalInterceptionSourceMatch) && finalInterceptionSourceMatch?.route === interceptionSourceMatch.route && haveSamePageParams(finalInterceptionSourceMatch.params, interceptionSourceMatch.params);
|
|
1102
1092
|
if (interceptionIdHeader !== null && !hasVerifiedFinalInterceptionSource) {
|
|
@@ -1140,7 +1130,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1140
1130
|
const finalRouteMatch = renderedRouteMatch(match);
|
|
1141
1131
|
setRootParams(finalRouteMatch ? pickRootParams(finalRouteMatch.params, finalRouteMatch.route.rootParamNames) : null);
|
|
1142
1132
|
if (isServerActionRequest) {
|
|
1143
|
-
const serverActionResponse = await handleServerAction(finalRouteMatch, cleanPathnameIsRequestPathname ?
|
|
1133
|
+
const serverActionResponse = await handleServerAction(finalRouteMatch, cleanPathnameIsRequestPathname ? requestPathname : cleanPathname);
|
|
1144
1134
|
if (serverActionResponse) return serverActionResponse;
|
|
1145
1135
|
} else {
|
|
1146
1136
|
const progressiveActionResult = await handleProgressiveAction(finalRouteMatch, match);
|
|
@@ -1186,7 +1176,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1186
1176
|
}
|
|
1187
1177
|
match = renderedRouteMatch(match);
|
|
1188
1178
|
const { route, params } = match;
|
|
1189
|
-
const requestPathnameDiffersFromCachePath =
|
|
1179
|
+
const requestPathnameDiffersFromCachePath = requestPathname !== cleanPathname;
|
|
1190
1180
|
const rawRequestPathnameIsObservable = isInterceptionMatch || route.routeHandler != null || typeof route.__loadRouteHandler === "function";
|
|
1191
1181
|
if ((!isInterceptionMatch || requestPathnameDiffersFromCachePath) && options.matchRequestRoute) {
|
|
1192
1182
|
const cachePathMatch = options.matchRoute(cleanPathname);
|
|
@@ -1213,7 +1203,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1213
1203
|
const isPrerenderFallbackShell = prerenderRouteParamsMatch?.kind === "fallback-shell";
|
|
1214
1204
|
const renderParams = prerenderRouteParams ?? params;
|
|
1215
1205
|
const responseStageMatchKind = isInterceptionMatch ? "interception" : cleanPathnameIsRequestPathname && options.matchRequestRoute ? usesRawRequestMatch() ? "raw-request" : "request" : "resolved";
|
|
1216
|
-
const responseStageRoutePathname = isInterceptionMatch ? preActionRoutePathname : cleanPathnameIsRequestPathname ?
|
|
1206
|
+
const responseStageRoutePathname = isInterceptionMatch ? preActionRoutePathname : cleanPathnameIsRequestPathname ? requestPathname || "/" : cleanPathname || "/";
|
|
1217
1207
|
const matchedResponseStage = transportedResponseStage ?? options.renderResponseStageLocally;
|
|
1218
1208
|
let runtimeFallbackShells = [];
|
|
1219
1209
|
if (options.createPprFallbackShells && request.method === "GET" && !isRscRequest && !isPrerenderFallbackShell && route.params) runtimeFallbackShells = options.createPprFallbackShells({
|
|
@@ -1229,7 +1219,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1229
1219
|
const rootParams = pickRootParams(renderParams, route.rootParamNames);
|
|
1230
1220
|
setRootParams(rootParams);
|
|
1231
1221
|
if (route.routeHandler) {
|
|
1232
|
-
const routeHandlerRequest = isEdgeRouteHandler(route.routeHandler) ? userlandRequest :
|
|
1222
|
+
const routeHandlerRequest = isEdgeRouteHandler(route.routeHandler) ? userlandRequest : request;
|
|
1233
1223
|
const routeHandlerUrl = new URL(routeHandlerRequest.url);
|
|
1234
1224
|
const internalRscValues = isEdgeRouteHandler(route.routeHandler) ? [] : routeHandlerUrl.searchParams.getAll(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
|
|
1235
1225
|
routeHandlerUrl.search = resolvedSearchParams.toString();
|
|
@@ -1312,7 +1302,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1312
1302
|
handlerStart,
|
|
1313
1303
|
interceptionContext: interceptionSourceContext,
|
|
1314
1304
|
interceptionId: interceptionIdHeader,
|
|
1315
|
-
interceptionPathname: cleanPathnameIsRequestPathname ?
|
|
1305
|
+
interceptionPathname: cleanPathnameIsRequestPathname ? requestPathname : cleanPathname,
|
|
1316
1306
|
isProgressiveActionRender: progressiveActionFormState !== null,
|
|
1317
1307
|
isRscRequest,
|
|
1318
1308
|
middlewareContext,
|
|
@@ -1375,8 +1365,9 @@ function applyProgressiveActionSideEffects(response, sideEffects) {
|
|
|
1375
1365
|
}
|
|
1376
1366
|
/** Build the request-only handler without retaining the response renderer graph. */
|
|
1377
1367
|
function createAppRscRequestHandler(options) {
|
|
1378
|
-
const handleAppRscRequestLifecycle = async (
|
|
1379
|
-
const rawRequestSignal =
|
|
1368
|
+
const handleAppRscRequestLifecycle = async (hostRequest, ctx, allowInternalRscDocumentFallback = false, dispatchResponseStage, responseStageProbeMode = null, transportedPrerenderState) => {
|
|
1369
|
+
const rawRequestSignal = hostRequest.signal;
|
|
1370
|
+
const rawRequest = stripRequestUrlFragment(hostRequest);
|
|
1380
1371
|
const mwCtx = openForwardedMiddlewareContext(rawRequest.headers.get(VINEXT_MW_CTX_HEADER), options.devForwardedMiddlewareContextKey);
|
|
1381
1372
|
const pagesDataUrl = new URL(rawRequest.url);
|
|
1382
1373
|
const pagesDataInScope = !options.basePath || hasBasePath(pagesDataUrl.pathname, options.basePath);
|
|
@@ -1440,7 +1431,7 @@ function createAppRscRequestHandler(options) {
|
|
|
1440
1431
|
basePath: options.basePath,
|
|
1441
1432
|
configHeaders: options.configHeaders,
|
|
1442
1433
|
i18nConfig: options.i18nConfig,
|
|
1443
|
-
restoreLocaleRootTrailingSlash: shouldRestoreLocaleRootTrailingSlash(
|
|
1434
|
+
restoreLocaleRootTrailingSlash: shouldRestoreLocaleRootTrailingSlash(new URL(rawRequest.url).pathname, options),
|
|
1444
1435
|
middlewareHeaders: middlewareContext.headers,
|
|
1445
1436
|
recordCacheability: dispatchResponseStage === void 0,
|
|
1446
1437
|
requestContext: preMiddlewareRequestContext
|
|
@@ -1468,7 +1459,7 @@ function createAppRscRequestHandler(options) {
|
|
|
1468
1459
|
detached: detachedTrace,
|
|
1469
1460
|
getStatus: (response) => response?.status,
|
|
1470
1461
|
headers: rawRequest.headers,
|
|
1471
|
-
isRsc:
|
|
1462
|
+
isRsc: rawRequest.headers.get("RSC") === "1",
|
|
1472
1463
|
method: rawRequest.method,
|
|
1473
1464
|
target: traceUrl.pathname + traceUrl.search
|
|
1474
1465
|
});
|
|
@@ -6,11 +6,9 @@ export type NormalizedRscRequest = {
|
|
|
6
6
|
url: URL;
|
|
7
7
|
/** Normalized pathname with basePath stripped. Used for all internal routing. */
|
|
8
8
|
pathname: string;
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
requestCleanPathname: string;
|
|
13
|
-
/** True when the request targets a canonical `.rsc` payload URL. */
|
|
9
|
+
/** Original encoded request pathname with basePath stripped. */
|
|
10
|
+
requestPathname: string;
|
|
11
|
+
/** True when the request selects the RSC payload with `RSC: 1`. */
|
|
14
12
|
isRscRequest: boolean;
|
|
15
13
|
/** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */
|
|
16
14
|
interceptionContextHeader: string | null;
|
|
@@ -42,13 +40,13 @@ export type NormalizedRscRequest = {
|
|
|
42
40
|
* 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
|
|
43
41
|
* 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
|
|
44
42
|
* `/__vinext/` bypasses this for internal prerender endpoints.
|
|
45
|
-
* 6. RSC detection:
|
|
46
|
-
* `_rsc` cache-busting query is
|
|
47
|
-
* responses do not share the
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
43
|
+
* 6. RSC detection: `RSC: 1`, as in Next.js. A `.rsc` suffix is an ordinary
|
|
44
|
+
* part of the pathname. The internal `_rsc` cache-busting query is
|
|
45
|
+
* validated separately so full-route Flight responses do not share the
|
|
46
|
+
* canonical HTML URL in caches that ignore Vary.
|
|
47
|
+
* 7. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
|
|
48
|
+
* 8. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
|
|
49
|
+
* 9. Read semantic render mode for refresh/action payload rendering
|
|
52
50
|
*
|
|
53
51
|
* @returns A 400 or 404 Response for invalid or out-of-scope inputs,
|
|
54
52
|
* or a NormalizedRscRequest for valid requests.
|