vinext 1.0.0-beta.1 → 1.0.0-beta.2
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 +4 -1
- package/dist/build/client-build-config.js +1 -0
- package/dist/build/report.d.ts +8 -1
- package/dist/build/report.js +12 -2
- package/dist/check.js +15 -2
- package/dist/cli.js +3 -2
- package/dist/config/config-matchers.d.ts +13 -37
- package/dist/config/config-matchers.js +31 -121
- package/dist/config/next-config.d.ts +3 -2
- package/dist/config/next-config.js +3 -1
- package/dist/config/request-context.d.ts +14 -0
- package/dist/config/request-context.js +26 -0
- package/dist/entries/app-rsc-entry.js +27 -9
- package/dist/entries/app-rsc-manifest.js +17 -0
- package/dist/entries/pages-server-entry.js +3 -2
- package/dist/index.js +82 -58
- package/dist/init.d.ts +6 -4
- package/dist/init.js +20 -22
- package/dist/plugins/og-assets.js +1 -1
- package/dist/routing/app-route-graph.d.ts +13 -5
- package/dist/routing/app-route-graph.js +59 -13
- package/dist/routing/app-router.js +12 -6
- package/dist/routing/file-matcher.d.ts +11 -22
- package/dist/routing/file-matcher.js +21 -33
- package/dist/routing/pages-router.js +23 -29
- package/dist/routing/route-matching.d.ts +14 -1
- package/dist/routing/route-matching.js +13 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +7 -4
- package/dist/routing/route-trie.d.ts +5 -1
- package/dist/routing/route-trie.js +5 -2
- package/dist/server/app-browser-entry.js +7 -6
- package/dist/server/app-browser-history-controller.d.ts +1 -1
- package/dist/server/app-browser-history-controller.js +3 -3
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +3 -0
- package/dist/server/app-fallback-renderer.js +4 -2
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +12 -1
- package/dist/server/app-page-boundary-render.js +84 -2
- package/dist/server/app-page-cache-finalizer.d.ts +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-dispatch.d.ts +11 -2
- package/dist/server/app-page-dispatch.js +14 -17
- package/dist/server/app-page-element-builder.d.ts +7 -2
- package/dist/server/app-page-element-builder.js +112 -27
- package/dist/server/app-page-head.d.ts +54 -2
- package/dist/server/app-page-head.js +164 -78
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +106 -0
- package/dist/server/app-page-render.d.ts +2 -2
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-request.d.ts +12 -0
- package/dist/server/app-page-request.js +133 -13
- package/dist/server/app-page-route-wiring.d.ts +9 -0
- package/dist/server/app-page-route-wiring.js +43 -3
- package/dist/server/app-post-middleware-context.d.ts +1 -1
- package/dist/server/app-post-middleware-context.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +31 -17
- package/dist/server/app-route-handler-execution.d.ts +6 -1
- package/dist/server/app-route-handler-execution.js +42 -16
- package/dist/server/app-route-handler-policy.d.ts +2 -0
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-module-loader.d.ts +3 -1
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-rsc-cache-busting.d.ts +1 -1
- package/dist/server/app-rsc-errors.d.ts +1 -1
- package/dist/server/app-rsc-errors.js +12 -2
- package/dist/server/app-rsc-handler.d.ts +10 -5
- package/dist/server/app-rsc-handler.js +52 -24
- package/dist/server/app-rsc-request-normalization.d.ts +3 -2
- package/dist/server/app-rsc-request-normalization.js +8 -2
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
- package/dist/server/app-rsc-response-finalizer.js +5 -11
- package/dist/server/app-rsc-route-matching.d.ts +20 -0
- package/dist/server/app-rsc-route-matching.js +87 -11
- package/dist/server/app-segment-config.js +13 -3
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +9 -7
- package/dist/server/app-ssr-entry.js +2 -2
- package/dist/server/app-ssr-stream.d.ts +1 -7
- package/dist/server/app-ssr-stream.js +2 -10
- package/dist/server/config-headers.d.ts +24 -0
- package/dist/server/config-headers.js +52 -0
- package/dist/server/dev-initial-server-error.d.ts +1 -1
- package/dist/server/dev-server.js +29 -13
- package/dist/server/isr-cache.d.ts +1 -1
- package/dist/server/middleware-matcher-pattern.d.ts +22 -0
- package/dist/server/middleware-matcher-pattern.js +219 -0
- package/dist/server/middleware-matcher.d.ts +2 -7
- package/dist/server/middleware-matcher.js +13 -60
- package/dist/server/middleware-path-to-regexp.d.ts +14 -0
- package/dist/server/middleware-path-to-regexp.js +228 -0
- package/dist/server/middleware-runtime.js +4 -3
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +2 -1
- package/dist/server/pages-data-route.d.ts +11 -1
- package/dist/server/pages-data-route.js +16 -1
- package/dist/server/pages-get-initial-props.d.ts +15 -2
- package/dist/server/pages-get-initial-props.js +16 -6
- package/dist/server/pages-page-data.d.ts +3 -1
- package/dist/server/pages-page-data.js +16 -7
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +16 -17
- package/dist/server/pages-page-response.js +1 -1
- package/dist/server/pages-readiness.d.ts +3 -3
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +25 -11
- package/dist/server/pages-router-entry.js +6 -0
- package/dist/server/prerender-route-params.js +2 -2
- package/dist/server/prod-server.d.ts +1 -4
- package/dist/server/prod-server.js +36 -23
- package/dist/server/request-pipeline.d.ts +15 -29
- package/dist/server/request-pipeline.js +24 -59
- package/dist/server/rsc-stream-hints.js +122 -18
- package/dist/shims/app.d.ts +1 -1
- package/dist/shims/cache-request-state.d.ts +27 -1
- package/dist/shims/cache-request-state.js +60 -1
- package/dist/shims/cache-runtime.d.ts +12 -1
- package/dist/shims/cache-runtime.js +22 -7
- package/dist/shims/cache.d.ts +5 -5
- package/dist/shims/cache.js +26 -10
- package/dist/shims/document.d.ts +42 -83
- package/dist/shims/document.js +62 -53
- package/dist/shims/dynamic.d.ts +5 -25
- package/dist/shims/dynamic.js +29 -8
- package/dist/shims/error.d.ts +1 -1
- package/dist/shims/error.js +1 -1
- package/dist/shims/fetch-cache.js +12 -3
- package/dist/shims/font-google-base.d.ts +11 -4
- package/dist/shims/font-local.d.ts +10 -3
- package/dist/shims/head.d.ts +13 -2
- package/dist/shims/head.js +3 -3
- package/dist/shims/headers.d.ts +28 -31
- package/dist/shims/headers.js +109 -49
- package/dist/shims/image.d.ts +27 -37
- package/dist/shims/image.js +21 -14
- package/dist/shims/internal/cookie-serialize.d.ts +3 -1
- package/dist/shims/internal/cookie-serialize.js +3 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
- package/dist/shims/internal/utils.d.ts +3 -3
- package/dist/shims/legacy-image.d.ts +3 -37
- package/dist/shims/legacy-image.js +6 -16
- package/dist/shims/link.d.ts +15 -22
- package/dist/shims/link.js +20 -11
- package/dist/shims/navigation-context-state.d.ts +1 -1
- package/dist/shims/navigation.d.ts +7 -3
- package/dist/shims/navigation.js +24 -13
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/next-shims-augmentations.d.ts +1 -0
- package/dist/shims/next-shims-public.d.ts +1 -0
- package/dist/shims/public-shim-map.json.js +103 -0
- package/dist/shims/readonly-url-search-params.d.ts +3 -3
- package/dist/shims/readonly-url-search-params.js +3 -3
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router.d.ts +55 -21
- package/dist/shims/router.js +162 -37
- package/dist/shims/script.d.ts +6 -10
- package/dist/shims/script.js +6 -3
- package/dist/shims/server.d.ts +45 -22
- package/dist/shims/server.js +44 -5
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/url-safety.d.ts +1 -1
- package/dist/shims/url-safety.js +2 -2
- package/dist/typegen.d.ts +8 -2
- package/dist/typegen.js +76 -15
- package/dist/utils/domain-locale.d.ts +2 -2
- package/dist/utils/external-url.d.ts +5 -0
- package/dist/utils/external-url.js +7 -0
- package/dist/utils/regex-safety.d.ts +8 -0
- package/dist/utils/regex-safety.js +737 -0
- package/package.json +13 -2
|
@@ -1,15 +1,27 @@
|
|
|
1
|
+
import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
|
|
1
2
|
import { isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
|
|
2
|
-
import {
|
|
3
|
+
import { _drainPendingRevalidations } from "../shims/cache-request-state.js";
|
|
3
4
|
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
5
|
+
import { runWithRootParamsUsage } from "../shims/root-params.js";
|
|
4
6
|
import { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss } from "./app-route-handler-response.js";
|
|
5
7
|
import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
|
|
6
8
|
import { createStaticGenerationHeadersContext, getAppRouteStaticGenerationErrorMessage } from "./app-static-generation.js";
|
|
7
9
|
import { resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
8
10
|
//#region src/server/app-route-handler-execution.ts
|
|
11
|
+
function applyDraftModeCachePolicy(response, isDraftMode) {
|
|
12
|
+
if (!isDraftMode) return response;
|
|
13
|
+
const headers = new Headers(response.headers);
|
|
14
|
+
applyCdnResponseHeaders(headers, { cacheControl: NEVER_CACHE_CONTROL });
|
|
15
|
+
return new Response(response.body, {
|
|
16
|
+
status: response.status,
|
|
17
|
+
statusText: response.statusText,
|
|
18
|
+
headers
|
|
19
|
+
});
|
|
20
|
+
}
|
|
9
21
|
function configureAppRouteStaticGenerationContext(options) {
|
|
10
22
|
if (options.dynamicConfig === "force-static" || options.dynamicConfig === "error") {
|
|
11
23
|
setHeadersContext(createStaticGenerationHeadersContext({
|
|
12
|
-
draftModeEnabled: options.draftModeSecret !== void 0 && isDraftModeRequest(options.request, options.draftModeSecret),
|
|
24
|
+
draftModeEnabled: options.isDraftMode ?? (options.draftModeSecret !== void 0 && isDraftModeRequest(options.request, options.draftModeSecret)),
|
|
13
25
|
draftModeSecret: options.draftModeSecret,
|
|
14
26
|
dynamicConfig: options.dynamicConfig,
|
|
15
27
|
routeKind: "route",
|
|
@@ -46,18 +58,30 @@ async function runAppRouteHandler(options) {
|
|
|
46
58
|
async function executeAppRouteHandler(options) {
|
|
47
59
|
const previousHeadersPhase = options.setHeadersAccessPhase("route-handler");
|
|
48
60
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
let handlerResult;
|
|
62
|
+
try {
|
|
63
|
+
handlerResult = await runAppRouteHandler({
|
|
64
|
+
...options,
|
|
65
|
+
dynamicConfig: options.handler.dynamic
|
|
66
|
+
});
|
|
67
|
+
} finally {
|
|
68
|
+
await _drainPendingRevalidations();
|
|
69
|
+
}
|
|
70
|
+
const { dynamicUsedInHandler, response } = handlerResult;
|
|
53
71
|
assertSupportedAppRouteHandlerResponse(response);
|
|
54
72
|
const handlerSetCacheControl = response.headers.has("cache-control");
|
|
55
73
|
if (dynamicUsedInHandler) markKnownDynamicAppRoute(options.routePattern);
|
|
74
|
+
const pendingCookies = options.getAndClearPendingCookies();
|
|
75
|
+
const handlerDraftCookie = options.getDraftModeCookieHeader();
|
|
76
|
+
const draftCookie = handlerDraftCookie ?? options.initialDraftModeCookie;
|
|
77
|
+
const shouldApplyDraftPolicy = (options.getActiveDraftModeState?.() ?? options.isDraftMode === true) || draftCookie != null;
|
|
78
|
+
if (handlerDraftCookie != null) markKnownDynamicAppRoute(options.routePattern);
|
|
56
79
|
const routeTags = options.buildPageCacheTags(options.cleanPathname, options.getCollectedFetchTags());
|
|
57
80
|
if (shouldApplyAppRouteHandlerRevalidateHeader({
|
|
58
81
|
dynamicUsedInHandler,
|
|
59
82
|
handlerSetCacheControl,
|
|
60
83
|
isAutoHead: options.isAutoHead,
|
|
84
|
+
isDraftMode: shouldApplyDraftPolicy,
|
|
61
85
|
method: options.method,
|
|
62
86
|
revalidateSeconds: options.revalidateSeconds
|
|
63
87
|
})) {
|
|
@@ -70,6 +94,7 @@ async function executeAppRouteHandler(options) {
|
|
|
70
94
|
dynamicUsedInHandler,
|
|
71
95
|
handlerSetCacheControl,
|
|
72
96
|
isAutoHead: options.isAutoHead,
|
|
97
|
+
isDraftMode: shouldApplyDraftPolicy,
|
|
73
98
|
isProduction: options.isProduction,
|
|
74
99
|
method: options.method,
|
|
75
100
|
revalidateSeconds: options.revalidateSeconds
|
|
@@ -90,29 +115,30 @@ async function executeAppRouteHandler(options) {
|
|
|
90
115
|
})();
|
|
91
116
|
options.executionContext?.waitUntil(routeWritePromise);
|
|
92
117
|
}
|
|
93
|
-
const pendingCookies = options.getAndClearPendingCookies();
|
|
94
|
-
const draftCookie = options.getDraftModeCookieHeader();
|
|
95
118
|
options.clearRequestContext();
|
|
96
|
-
return applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(response, {
|
|
119
|
+
return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(response, {
|
|
97
120
|
pendingCookies,
|
|
98
121
|
draftCookie,
|
|
99
122
|
isHead: options.isAutoHead
|
|
100
|
-
}), options.middlewareContext);
|
|
123
|
+
}), options.middlewareContext), shouldApplyDraftPolicy);
|
|
101
124
|
} catch (error) {
|
|
102
125
|
const pendingCookies = options.getAndClearPendingCookies();
|
|
103
|
-
const
|
|
126
|
+
const handlerDraftCookie = options.getDraftModeCookieHeader();
|
|
127
|
+
const draftCookie = handlerDraftCookie ?? options.initialDraftModeCookie;
|
|
128
|
+
const shouldApplyDraftPolicy = (options.getActiveDraftModeState?.() ?? options.isDraftMode === true) || draftCookie != null;
|
|
129
|
+
if (handlerDraftCookie != null) markKnownDynamicAppRoute(options.routePattern);
|
|
104
130
|
const specialError = resolveAppRouteHandlerSpecialError(error, options.request.url, { isAction: isPossibleAppRouteActionRequest(options.request) });
|
|
105
131
|
options.clearRequestContext();
|
|
106
132
|
if (specialError) {
|
|
107
|
-
if (specialError.kind === "redirect") return applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(new Response(null, {
|
|
133
|
+
if (specialError.kind === "redirect") return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(new Response(null, {
|
|
108
134
|
status: specialError.statusCode,
|
|
109
135
|
headers: { Location: specialError.location }
|
|
110
136
|
}), {
|
|
111
137
|
pendingCookies,
|
|
112
138
|
draftCookie,
|
|
113
139
|
isHead: options.isAutoHead
|
|
114
|
-
}), options.middlewareContext);
|
|
115
|
-
return applyRouteHandlerMiddlewareContext(new Response(null, { status: specialError.statusCode }), options.middlewareContext);
|
|
140
|
+
}), options.middlewareContext), shouldApplyDraftPolicy);
|
|
141
|
+
return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(new Response(null, { status: specialError.statusCode }), options.middlewareContext), shouldApplyDraftPolicy);
|
|
116
142
|
}
|
|
117
143
|
console.error("[vinext] Route handler error:", error);
|
|
118
144
|
options.reportRequestError(error instanceof Error ? error : new Error(String(error)), {
|
|
@@ -124,10 +150,10 @@ async function executeAppRouteHandler(options) {
|
|
|
124
150
|
routePath: options.routePattern,
|
|
125
151
|
routeType: "route"
|
|
126
152
|
});
|
|
127
|
-
return applyRouteHandlerMiddlewareContext(new Response(null, { status: 500 }), options.middlewareContext);
|
|
153
|
+
return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(new Response(null, { status: 500 }), options.middlewareContext), shouldApplyDraftPolicy);
|
|
128
154
|
} finally {
|
|
129
155
|
options.setHeadersAccessPhase(previousHeadersPhase);
|
|
130
156
|
}
|
|
131
157
|
}
|
|
132
158
|
//#endregion
|
|
133
|
-
export { executeAppRouteHandler, runAppRouteHandler };
|
|
159
|
+
export { applyDraftModeCachePolicy, executeAppRouteHandler, runAppRouteHandler };
|
|
@@ -20,6 +20,7 @@ type AppRouteHandlerCacheReadOptions = {
|
|
|
20
20
|
handlerFn: unknown;
|
|
21
21
|
isAutoHead: boolean;
|
|
22
22
|
isKnownDynamic: boolean;
|
|
23
|
+
isDraftMode?: boolean;
|
|
23
24
|
isProduction: boolean;
|
|
24
25
|
method: string;
|
|
25
26
|
revalidateSeconds: number | null;
|
|
@@ -29,6 +30,7 @@ type AppRouteHandlerResponseCacheOptions = {
|
|
|
29
30
|
dynamicUsedInHandler: boolean;
|
|
30
31
|
handlerSetCacheControl: boolean;
|
|
31
32
|
isAutoHead: boolean;
|
|
33
|
+
isDraftMode?: boolean;
|
|
32
34
|
isProduction: boolean;
|
|
33
35
|
method: string;
|
|
34
36
|
revalidateSeconds: number | null;
|
|
@@ -30,13 +30,13 @@ function resolveAppRouteHandlerMethod(handler, method) {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
function shouldReadAppRouteHandlerCache(options) {
|
|
33
|
-
return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && !options.isKnownDynamic && (options.method === "GET" || options.isAutoHead) && typeof options.handlerFn === "function";
|
|
33
|
+
return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && !options.isDraftMode && !options.isKnownDynamic && (options.method === "GET" || options.isAutoHead) && typeof options.handlerFn === "function";
|
|
34
34
|
}
|
|
35
35
|
function shouldApplyAppRouteHandlerRevalidateHeader(options) {
|
|
36
|
-
return options.revalidateSeconds !== null && !options.dynamicUsedInHandler && (options.method === "GET" || options.isAutoHead) && !options.handlerSetCacheControl;
|
|
36
|
+
return options.revalidateSeconds !== null && !options.isDraftMode && !options.dynamicUsedInHandler && (options.method === "GET" || options.isAutoHead) && !options.handlerSetCacheControl;
|
|
37
37
|
}
|
|
38
38
|
function shouldWriteAppRouteHandlerCache(options) {
|
|
39
|
-
return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && shouldApplyAppRouteHandlerRevalidateHeader(options);
|
|
39
|
+
return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && !options.isDraftMode && shouldApplyAppRouteHandlerRevalidateHeader(options);
|
|
40
40
|
}
|
|
41
41
|
function resolveAppRouteHandlerSpecialError(error, requestUrl, options) {
|
|
42
42
|
if (!(error && typeof error === "object" && "digest" in error)) return null;
|
|
@@ -39,12 +39,14 @@ type LazyLoadableSlot = {
|
|
|
39
39
|
configLayouts?: readonly unknown[];
|
|
40
40
|
loading?: unknown;
|
|
41
41
|
error?: unknown;
|
|
42
|
+
notFound?: unknown;
|
|
42
43
|
__loadPage?: LazyModuleThunk | null;
|
|
43
44
|
__loadDefault?: LazyModuleThunk | null;
|
|
44
45
|
__loadLayout?: LazyModuleThunk | null;
|
|
45
46
|
__loadConfigLayouts?: LazyModuleLoaderArray | null;
|
|
46
47
|
__loadLoading?: LazyModuleThunk | null;
|
|
47
|
-
__loadError?: LazyModuleThunk | null;
|
|
48
|
+
__loadError?: LazyModuleThunk | null;
|
|
49
|
+
__loadNotFound?: LazyModuleThunk | null; /** Hydrated only after an intercept matches, not with the slot's base modules. */
|
|
48
50
|
intercepts?: LazyLoadableIntercept[];
|
|
49
51
|
};
|
|
50
52
|
type LazyLoadableRoute = {
|
|
@@ -64,6 +64,7 @@ function ensureAppRouteModulesLoaded(route) {
|
|
|
64
64
|
pushArrayLoads(loads, slot.configLayouts, slot.__loadConfigLayouts);
|
|
65
65
|
pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
|
|
66
66
|
pushFieldLoad(loads, slot, "error", slot.__loadError);
|
|
67
|
+
pushFieldLoad(loads, slot, "notFound", slot.__loadNotFound);
|
|
67
68
|
}
|
|
68
69
|
if (loads.length === 0) {
|
|
69
70
|
route.__loaded = true;
|
|
@@ -34,7 +34,7 @@ declare function getDigestForWellKnownError(error: unknown): string | undefined;
|
|
|
34
34
|
* djb2 hash matching Next.js's string-hash package for RSC error digests.
|
|
35
35
|
*/
|
|
36
36
|
declare function errorDigest(input: string): string;
|
|
37
|
-
declare function sanitizeErrorForClient(error: unknown, nodeEnv?:
|
|
37
|
+
declare function sanitizeErrorForClient(error: unknown, nodeEnv?: "development" | "production" | "test"): unknown;
|
|
38
38
|
declare function createRscOnErrorHandler(options: CreateRscOnErrorHandlerOptions): (error: unknown) => string | undefined;
|
|
39
39
|
//#endregion
|
|
40
40
|
export { createRscOnErrorHandler, errorDigest, getDigestForWellKnownError, hasDigest, sanitizeErrorForClient };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
2
2
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
3
3
|
//#region src/server/app-rsc-errors.ts
|
|
4
|
+
const ORIGINAL_SERVER_ERROR = Symbol.for("vinext.originalServerError");
|
|
4
5
|
function hasDigest(error) {
|
|
5
6
|
return Boolean(error && typeof error === "object" && "digest" in error);
|
|
6
7
|
}
|
|
@@ -39,7 +40,13 @@ function sanitizeErrorForClient(error, nodeEnv = process.env.NODE_ENV) {
|
|
|
39
40
|
if (resolveAppPageSpecialError(error)) return error;
|
|
40
41
|
if (nodeEnv !== "production") return error;
|
|
41
42
|
const sanitized = /* @__PURE__ */ new Error("An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.");
|
|
42
|
-
sanitized.digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
|
|
43
|
+
sanitized.digest = hasDigest(error) ? String(error.digest) : errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
|
|
44
|
+
Object.defineProperty(sanitized, ORIGINAL_SERVER_ERROR, {
|
|
45
|
+
configurable: false,
|
|
46
|
+
enumerable: false,
|
|
47
|
+
value: error,
|
|
48
|
+
writable: false
|
|
49
|
+
});
|
|
43
50
|
return sanitized;
|
|
44
51
|
}
|
|
45
52
|
function createRscOnErrorHandler(options) {
|
|
@@ -51,7 +58,10 @@ function createRscOnErrorHandler(options) {
|
|
|
51
58
|
console.error("[vinext] RSC serialization error: a non-plain object was passed from a Server Component to a Client Component.\n\nCommon causes:\n * Passing a module namespace (import * as X) directly as a prop.\n Unlike Next.js (webpack), Vite produces real ESM module namespace objects\n which are not serializable. Fix: pass individual values instead,\n e.g. <Comp value={module.value} />\n * Passing a class instance (new Foo()) as a prop.\n Fix: convert to a plain object, e.g. { id: foo.id, name: foo.name }\n * Passing a Date, Map, or Set. Use .toISOString(), [...map.entries()], etc.\n * Passing Object.create(null). Use { ...obj } to restore a prototype.\n\nOriginal error:", error.message);
|
|
52
59
|
return;
|
|
53
60
|
}
|
|
54
|
-
if (options.requestInfo && options.errorContext && error)
|
|
61
|
+
if (options.requestInfo && options.errorContext && error) {
|
|
62
|
+
const reportableError = typeof error === "object" && ORIGINAL_SERVER_ERROR in error ? Reflect.get(error, ORIGINAL_SERVER_ERROR) : error;
|
|
63
|
+
options.reportRequestError(reportableError instanceof Error ? reportableError : new Error(getThrownValueMessage(reportableError)), options.requestInfo, options.errorContext);
|
|
64
|
+
}
|
|
55
65
|
if (hasDigest(error)) return String(error.digest);
|
|
56
66
|
if (error) {
|
|
57
67
|
const digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config/next-config.js";
|
|
2
2
|
import { ImageConfig } from "./image-optimization.js";
|
|
3
3
|
import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
|
|
4
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
4
5
|
import { RootParams } from "../shims/root-params.js";
|
|
5
6
|
import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware.js";
|
|
6
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
7
7
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
8
8
|
import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
|
|
9
9
|
import { AppRouteTreePrefetchRoute, PrefetchInliningConfig } from "./app-route-tree-prefetch.js";
|
|
@@ -48,6 +48,7 @@ type DispatchMatchedPageOptions<TRoute> = {
|
|
|
48
48
|
actionFailed?: boolean;
|
|
49
49
|
handlerStart: number;
|
|
50
50
|
interceptionContext: string | null;
|
|
51
|
+
interceptionPathname: string;
|
|
51
52
|
isProgressiveActionRender: boolean;
|
|
52
53
|
isRscRequest: boolean;
|
|
53
54
|
middlewareContext: AppRscMiddlewareContext;
|
|
@@ -87,12 +88,13 @@ type DispatchMatchedRouteHandlerOptions<TRoute> = {
|
|
|
87
88
|
route: TRoute;
|
|
88
89
|
searchParams: URLSearchParams;
|
|
89
90
|
};
|
|
90
|
-
type HandleProgressiveActionRequestOptions = {
|
|
91
|
+
type HandleProgressiveActionRequestOptions<TRoute> = {
|
|
91
92
|
actionId: string | null;
|
|
92
93
|
cleanPathname: string;
|
|
93
94
|
contentType: string;
|
|
94
95
|
middlewareContext: AppRscMiddlewareContext;
|
|
95
96
|
request: Request;
|
|
97
|
+
routeMatch: AppRscRouteMatch<TRoute> | null;
|
|
96
98
|
};
|
|
97
99
|
/**
|
|
98
100
|
* Side-effect headers captured during a progressive (no-JS) server action's
|
|
@@ -114,7 +116,7 @@ type ProgressiveActionFormStateResult = ({
|
|
|
114
116
|
formState: null;
|
|
115
117
|
kind: "form-state";
|
|
116
118
|
} & ProgressiveActionSideEffects);
|
|
117
|
-
type HandleServerActionRequestOptions = {
|
|
119
|
+
type HandleServerActionRequestOptions<TRoute> = {
|
|
118
120
|
actionId: string | null;
|
|
119
121
|
cleanPathname: string;
|
|
120
122
|
contentType: string;
|
|
@@ -123,6 +125,8 @@ type HandleServerActionRequestOptions = {
|
|
|
123
125
|
middlewareContext: AppRscMiddlewareContext;
|
|
124
126
|
mountedSlotsHeader: string | null;
|
|
125
127
|
request: Request;
|
|
128
|
+
routeMatch: AppRscRouteMatch<TRoute> | null;
|
|
129
|
+
routePathname: string;
|
|
126
130
|
searchParams: URLSearchParams;
|
|
127
131
|
};
|
|
128
132
|
type RenderNotFoundOptions<TRoute> = {
|
|
@@ -183,15 +187,16 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
|
|
|
183
187
|
* Node server and dev included, not just the Cloudflare worker entry.
|
|
184
188
|
*/
|
|
185
189
|
registerCacheAdapters: (env?: Record<string, unknown>) => void;
|
|
186
|
-
handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions) => Promise<Response | ProgressiveActionFormStateResult | null>;
|
|
190
|
+
handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions<TRoute>) => Promise<Response | ProgressiveActionFormStateResult | null>;
|
|
187
191
|
handleMetadataRouteRequest?: (cleanPathname: string) => Promise<Response | null>;
|
|
188
192
|
createPprFallbackShells?: (route: Pick<AppRscHandlerRoute, "params" | "pattern" | "rootParamNames">, params: AppPageParams) => AppPagePprFallbackCacheShell[];
|
|
189
|
-
handleServerActionRequest?: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
|
|
193
|
+
handleServerActionRequest?: (options: HandleServerActionRequestOptions<TRoute>) => Promise<Response | null>;
|
|
190
194
|
i18nConfig: NextI18nConfig | null;
|
|
191
195
|
imageConfig?: ImageConfig;
|
|
192
196
|
isDev: boolean;
|
|
193
197
|
loadPrerenderPagesRoutes?: () => Promise<unknown>;
|
|
194
198
|
matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
|
|
199
|
+
matchRequestRoute?: (pathname: string) => AppRscRouteMatch<TRoute> | null;
|
|
195
200
|
runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
|
|
196
201
|
publicFiles: ReadonlySet<string>;
|
|
197
202
|
prefetchInlining?: PrefetchInliningConfig;
|
|
@@ -3,9 +3,10 @@ import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base
|
|
|
3
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
4
|
import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
5
5
|
import { ACTION_REVALIDATED_HEADER } from "./headers.js";
|
|
6
|
-
import {
|
|
6
|
+
import { requestContextFromRequest } from "../config/request-context.js";
|
|
7
|
+
import { isExternalUrl } from "../utils/external-url.js";
|
|
7
8
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
8
|
-
import {
|
|
9
|
+
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
|
|
9
10
|
import { headersContextFromRequest } from "../shims/headers.js";
|
|
10
11
|
import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
|
|
11
12
|
import { mergeRewriteQuery } from "../utils/query.js";
|
|
@@ -19,17 +20,20 @@ import "./app-page-response.js";
|
|
|
19
20
|
import { parseNextHttpErrorDigest } from "./next-error-digest.js";
|
|
20
21
|
import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
21
22
|
import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
|
|
22
|
-
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
23
|
-
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
24
23
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
|
|
25
24
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
26
25
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
26
|
+
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
27
27
|
import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
|
|
28
|
+
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
28
29
|
import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
|
|
29
30
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
30
31
|
import { runWithPrerenderWorkUnit } from "./prerender-work-unit-setup.js";
|
|
31
32
|
//#region src/server/app-rsc-handler.ts
|
|
32
33
|
const STATIC_METADATA_CONFIG_HEADER_OVERRIDES = /* @__PURE__ */ new Set(["cache-control"]);
|
|
34
|
+
const HAS_CONFIG_HEADERS = process.env.__VINEXT_HAS_CONFIG_HEADERS !== "false";
|
|
35
|
+
const HAS_CONFIG_REDIRECTS = process.env.__VINEXT_HAS_CONFIG_REDIRECTS !== "false";
|
|
36
|
+
const HAS_CONFIG_REWRITES = process.env.__VINEXT_HAS_CONFIG_REWRITES !== "false";
|
|
33
37
|
function applyMiddlewareContextToResponse(response, middlewareContext) {
|
|
34
38
|
if (!middlewareContext.headers && middlewareContext.status == null) return response;
|
|
35
39
|
const headers = new Headers(response.headers);
|
|
@@ -61,12 +65,14 @@ function redirectDestinationWithBasePath(destination, basePath, hadBasePath) {
|
|
|
61
65
|
return basePath + destination;
|
|
62
66
|
}
|
|
63
67
|
async function applyRewrite(options, cleanPathname) {
|
|
64
|
-
if (!options.rewrites.length) return null;
|
|
65
|
-
const
|
|
68
|
+
if (!HAS_CONFIG_REWRITES || !options.rewrites.length) return null;
|
|
69
|
+
const sourcePathname = options.paramsPathname ?? cleanPathname;
|
|
70
|
+
const configMatchers = await import("../config/config-matchers.js");
|
|
71
|
+
const rewritten = configMatchers.matchRewrite(sourcePathname, options.rewrites, options.requestContext, options.basePathState, options.paramsPathname);
|
|
66
72
|
if (!rewritten) return null;
|
|
67
73
|
if (isExternalUrl(rewritten)) {
|
|
68
74
|
options.clearRequestContext();
|
|
69
|
-
return proxyExternalRequest(options.request, rewritten);
|
|
75
|
+
return configMatchers.proxyExternalRequest(options.request, rewritten);
|
|
70
76
|
}
|
|
71
77
|
return rewritten;
|
|
72
78
|
}
|
|
@@ -81,9 +87,10 @@ function requestContextForResolvedUrl(requestContext, resolvedUrl, baseUrl) {
|
|
|
81
87
|
function pathnameForResolvedUrl(resolvedUrl) {
|
|
82
88
|
return resolvedUrl.split("#", 1)[0].split("?", 1)[0];
|
|
83
89
|
}
|
|
84
|
-
function applyConfigHeadersToMiddlewareRedirect(response, options) {
|
|
90
|
+
async function applyConfigHeadersToMiddlewareRedirect(response, options) {
|
|
85
91
|
if (response.status < 300 || response.status >= 400) return response;
|
|
86
|
-
if (!options.configHeaders.length) return response;
|
|
92
|
+
if (!HAS_CONFIG_HEADERS || !options.configHeaders.length) return response;
|
|
93
|
+
const { applyConfigHeadersToResponse } = await import("./config-headers.js");
|
|
87
94
|
const headers = new Headers();
|
|
88
95
|
applyConfigHeadersToResponse(headers, {
|
|
89
96
|
configHeaders: options.configHeaders,
|
|
@@ -130,6 +137,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
130
137
|
const normalized = normalizeRscRequest(request, options.basePath, canHandleOutsideBasePath);
|
|
131
138
|
if (normalized instanceof Response) return normalized;
|
|
132
139
|
const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode, clientReuseManifest, hadBasePath } = normalized;
|
|
140
|
+
const { requestCleanPathname } = normalized;
|
|
133
141
|
let { pathname, cleanPathname } = normalized;
|
|
134
142
|
let resolvedUrl = cleanPathname + url.search;
|
|
135
143
|
const originalResolvedUrl = resolvedUrl;
|
|
@@ -139,6 +147,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
139
147
|
basePath: options.basePath,
|
|
140
148
|
hadBasePath
|
|
141
149
|
};
|
|
150
|
+
let cleanPathnameIsRequestPathname = true;
|
|
151
|
+
const matchCleanPathname = () => cleanPathnameIsRequestPathname && options.matchRequestRoute ? options.matchRequestRoute(requestCleanPathname) : options.matchRoute(cleanPathname);
|
|
142
152
|
if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths") {
|
|
143
153
|
const { handleAppPrerenderEndpoint } = await import("./app-prerender-endpoints.js");
|
|
144
154
|
const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {
|
|
@@ -152,13 +162,15 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
152
162
|
});
|
|
153
163
|
if (prerenderEndpointResponse) return prerenderEndpointResponse;
|
|
154
164
|
}
|
|
155
|
-
const trailingSlashRedirect = normalizeTrailingSlash(
|
|
165
|
+
const trailingSlashRedirect = normalizeTrailingSlash(requestCleanPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
|
|
156
166
|
if (trailingSlashRedirect) return trailingSlashRedirect;
|
|
157
167
|
const matchPathname = (p) => normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
168
|
+
const redirectPathname = matchPathname(requestCleanPathname);
|
|
169
|
+
const configMatchers = HAS_CONFIG_REDIRECTS && options.configRedirects.length ? await import("../config/config-matchers.js") : null;
|
|
170
|
+
const redirect = configMatchers ? configMatchers.matchRedirect(redirectPathname, options.configRedirects, preMiddlewareRequestContext, basePathState) : null;
|
|
171
|
+
if (configMatchers && redirect) {
|
|
172
|
+
const destination = configMatchers.sanitizeDestination(redirectDestinationWithBasePath(redirect.destination, options.basePath, hadBasePath));
|
|
173
|
+
const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : configMatchers.preserveRedirectDestinationQuery(destination, url.search);
|
|
162
174
|
return new Response(null, {
|
|
163
175
|
status: redirect.permanent ? 308 : 307,
|
|
164
176
|
headers: { Location: location }
|
|
@@ -189,11 +201,12 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
189
201
|
if (middlewareResult.kind === "response") return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {
|
|
190
202
|
basePathState,
|
|
191
203
|
configHeaders: options.configHeaders,
|
|
192
|
-
pathname: matchPathname(
|
|
204
|
+
pathname: matchPathname(requestCleanPathname),
|
|
193
205
|
requestContext: preMiddlewareRequestContext
|
|
194
206
|
});
|
|
195
207
|
cleanPathname = middlewareResult.cleanPathname;
|
|
196
208
|
didMiddlewareRewrite = middlewareResult.rewritten;
|
|
209
|
+
if (didMiddlewareRewrite || cleanPathname !== normalized.cleanPathname) cleanPathnameIsRequestPathname = false;
|
|
197
210
|
didMiddlewareRewritePathname = cleanPathname !== normalized.cleanPathname;
|
|
198
211
|
if (middlewareResult.search !== null) url.search = middlewareResult.search;
|
|
199
212
|
resolvedUrl = cleanPathname + url.search;
|
|
@@ -214,12 +227,14 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
214
227
|
clearRequestContext: options.clearRequestContext,
|
|
215
228
|
request: normalizedUserlandRequest,
|
|
216
229
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
230
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
|
|
217
231
|
rewrites: [rewrite]
|
|
218
232
|
}, matchPathname(cleanPathname));
|
|
219
233
|
if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;
|
|
220
234
|
if (beforeFilesRewrite) {
|
|
221
235
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, beforeFilesRewrite);
|
|
222
236
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
237
|
+
cleanPathnameIsRequestPathname = false;
|
|
223
238
|
filesystemRouteEligible = true;
|
|
224
239
|
}
|
|
225
240
|
}
|
|
@@ -238,14 +253,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
238
253
|
clearRequestContext: options.clearRequestContext,
|
|
239
254
|
request: normalizedUserlandRequest,
|
|
240
255
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
256
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
|
|
241
257
|
rewrites: [rewrite]
|
|
242
258
|
}, matchPathname(cleanPathname));
|
|
243
259
|
if (rewritten instanceof Response) return rewritten;
|
|
244
260
|
if (!rewritten) continue;
|
|
245
261
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
246
262
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
263
|
+
cleanPathnameIsRequestPathname = false;
|
|
247
264
|
filesystemRouteEligible = true;
|
|
248
|
-
actionMatch =
|
|
265
|
+
actionMatch = matchCleanPathname();
|
|
249
266
|
if (actionMatch) break;
|
|
250
267
|
}
|
|
251
268
|
if (!actionMatch) for (const rewrite of options.configRewrites.fallback) {
|
|
@@ -254,14 +271,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
254
271
|
clearRequestContext: options.clearRequestContext,
|
|
255
272
|
request: normalizedUserlandRequest,
|
|
256
273
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
274
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
|
|
257
275
|
rewrites: [rewrite]
|
|
258
276
|
}, matchPathname(cleanPathname));
|
|
259
277
|
if (rewritten instanceof Response) return rewritten;
|
|
260
278
|
if (!rewritten) continue;
|
|
261
279
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
262
280
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
281
|
+
cleanPathnameIsRequestPathname = false;
|
|
263
282
|
filesystemRouteEligible = true;
|
|
264
|
-
actionMatch =
|
|
283
|
+
actionMatch = matchCleanPathname();
|
|
265
284
|
if (actionMatch) break;
|
|
266
285
|
}
|
|
267
286
|
resolvedLateRewritesForAction = filesystemRouteEligible;
|
|
@@ -275,16 +294,17 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
275
294
|
}
|
|
276
295
|
if (filesystemRouteEligible && options.handleMetadataRouteRequest) {
|
|
277
296
|
const metadataRouteResponse = await options.handleMetadataRouteRequest(cleanPathname);
|
|
278
|
-
if (metadataRouteResponse) {
|
|
297
|
+
if (metadataRouteResponse && HAS_CONFIG_HEADERS && options.configHeaders.length) {
|
|
298
|
+
const { applyConfigHeadersToResponse } = await import("./config-headers.js");
|
|
279
299
|
applyConfigHeadersToResponse(metadataRouteResponse.headers, {
|
|
280
300
|
basePathState,
|
|
281
301
|
configHeaders: options.configHeaders,
|
|
282
302
|
overwriteExisting: STATIC_METADATA_CONFIG_HEADER_OVERRIDES,
|
|
283
|
-
pathname: matchPathname(cleanPathname),
|
|
303
|
+
pathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
|
|
284
304
|
requestContext: preMiddlewareRequestContext
|
|
285
305
|
});
|
|
286
|
-
return applyMiddlewareContextToResponse(metadataRouteResponse, middlewareContext);
|
|
287
306
|
}
|
|
307
|
+
if (metadataRouteResponse) return applyMiddlewareContextToResponse(metadataRouteResponse, middlewareContext);
|
|
288
308
|
}
|
|
289
309
|
const publicFileResponse = filesystemRouteEligible ? resolvePublicFileRoute({
|
|
290
310
|
cleanPathname,
|
|
@@ -306,7 +326,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
306
326
|
searchParams: getResolvedSearchParams(),
|
|
307
327
|
params: {}
|
|
308
328
|
});
|
|
309
|
-
const preActionMatch = filesystemRouteEligible ?
|
|
329
|
+
const preActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
|
|
310
330
|
if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
|
|
311
331
|
if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch) {
|
|
312
332
|
const headers = new Headers();
|
|
@@ -327,7 +347,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
327
347
|
cleanPathname,
|
|
328
348
|
contentType,
|
|
329
349
|
middlewareContext,
|
|
330
|
-
request
|
|
350
|
+
request,
|
|
351
|
+
routeMatch: preActionMatch
|
|
331
352
|
});
|
|
332
353
|
else if (preActionMatch?.route.__loadPage && !preActionMatch.route.__loadRouteHandler) return createMissingServerActionResponse(options, null);
|
|
333
354
|
}
|
|
@@ -351,6 +372,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
351
372
|
middlewareContext,
|
|
352
373
|
mountedSlotsHeader,
|
|
353
374
|
request,
|
|
375
|
+
routeMatch: preActionMatch,
|
|
376
|
+
routePathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
|
|
354
377
|
searchParams: getResolvedSearchParams()
|
|
355
378
|
}) : null;
|
|
356
379
|
if (serverActionResponse) return serverActionResponse;
|
|
@@ -390,16 +413,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
390
413
|
clearRequestContext: options.clearRequestContext,
|
|
391
414
|
request: normalizedUserlandRequest,
|
|
392
415
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
416
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
|
|
393
417
|
rewrites: [rewrite]
|
|
394
418
|
}, matchPathname(cleanPathname));
|
|
395
419
|
if (afterFilesRewrite instanceof Response) return afterFilesRewrite;
|
|
396
420
|
if (!afterFilesRewrite) continue;
|
|
397
421
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, afterFilesRewrite);
|
|
398
422
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
423
|
+
cleanPathnameIsRequestPathname = false;
|
|
399
424
|
filesystemRouteEligible = true;
|
|
400
425
|
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
401
426
|
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
402
|
-
match =
|
|
427
|
+
match = matchCleanPathname();
|
|
403
428
|
const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
|
|
404
429
|
if (rewrittenStaticPagesResponse) {
|
|
405
430
|
options.clearRequestContext();
|
|
@@ -423,16 +448,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
423
448
|
clearRequestContext: options.clearRequestContext,
|
|
424
449
|
request: normalizedUserlandRequest,
|
|
425
450
|
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
451
|
+
paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
|
|
426
452
|
rewrites: [rewrite]
|
|
427
453
|
}, matchPathname(cleanPathname));
|
|
428
454
|
if (fallbackRewrite instanceof Response) return fallbackRewrite;
|
|
429
455
|
if (!fallbackRewrite) continue;
|
|
430
456
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
431
457
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
458
|
+
cleanPathnameIsRequestPathname = false;
|
|
432
459
|
filesystemRouteEligible = true;
|
|
433
460
|
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
434
461
|
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
435
|
-
match =
|
|
462
|
+
match = matchCleanPathname();
|
|
436
463
|
const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
|
|
437
464
|
if (rewrittenStaticPagesResponse) {
|
|
438
465
|
options.clearRequestContext();
|
|
@@ -536,6 +563,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
536
563
|
actionFailed,
|
|
537
564
|
handlerStart,
|
|
538
565
|
interceptionContext: interceptionContextHeader,
|
|
566
|
+
interceptionPathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
|
|
539
567
|
isProgressiveActionRender,
|
|
540
568
|
isRscRequest,
|
|
541
569
|
middlewareContext,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
|
|
2
|
-
import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
|
|
3
2
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
3
|
+
import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
|
|
4
4
|
|
|
5
5
|
//#region src/server/app-rsc-request-normalization.d.ts
|
|
6
6
|
type NormalizedRscRequest = {
|
|
7
7
|
/** Parsed URL. Callers may mutate `url.search` after middleware runs. */url: URL; /** Normalized pathname with basePath stripped. Used for all internal routing. */
|
|
8
8
|
pathname: string; /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */
|
|
9
|
-
cleanPathname: string; /**
|
|
9
|
+
cleanPathname: string; /** Original encoded request pathname with basePath and `.rsc` removed. */
|
|
10
|
+
requestCleanPathname: string; /** True when the request targets a canonical `.rsc` payload URL. */
|
|
10
11
|
isRscRequest: boolean; /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */
|
|
11
12
|
interceptionContextHeader: string | null; /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */
|
|
12
13
|
mountedSlotsHeader: string | null; /** Semantic RSC payload mode. HTML requests always normalize to "navigation". */
|
|
@@ -50,14 +50,19 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
|
|
|
50
50
|
return badRequestResponse();
|
|
51
51
|
}
|
|
52
52
|
let pathname = normalizePath(decoded);
|
|
53
|
+
let requestPathname = url.pathname;
|
|
53
54
|
let hadBasePath = true;
|
|
54
55
|
if (basePath) {
|
|
55
|
-
hadBasePath = hasBasePath(
|
|
56
|
+
hadBasePath = hasBasePath(requestPathname, basePath);
|
|
56
57
|
if (!hadBasePath && !pathname.startsWith("/__vinext/") && !allowOutsideBasePath) return notFoundResponse();
|
|
57
|
-
if (hadBasePath)
|
|
58
|
+
if (hadBasePath) {
|
|
59
|
+
pathname = stripBasePath(pathname, basePath);
|
|
60
|
+
requestPathname = stripBasePath(requestPathname, basePath);
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("RSC") === "1";
|
|
60
64
|
const cleanPathname = stripRscSuffix(pathname);
|
|
65
|
+
const requestCleanPathname = stripRscSuffix(requestPathname);
|
|
61
66
|
const interceptionContextHeader = normalizeInterceptionContextHeader(request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER));
|
|
62
67
|
const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER));
|
|
63
68
|
const renderMode = isRscRequest ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) : APP_RSC_RENDER_MODE_NAVIGATION;
|
|
@@ -67,6 +72,7 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
|
|
|
67
72
|
url,
|
|
68
73
|
pathname,
|
|
69
74
|
cleanPathname,
|
|
75
|
+
requestCleanPathname,
|
|
70
76
|
isRscRequest,
|
|
71
77
|
interceptionContextHeader,
|
|
72
78
|
mountedSlotsHeader,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextHeader, NextI18nConfig } from "../config/next-config.js";
|
|
2
|
-
import { RequestContext } from "../config/
|
|
2
|
+
import { RequestContext } from "../config/request-context.js";
|
|
3
3
|
|
|
4
4
|
//#region src/server/app-rsc-response-finalizer.d.ts
|
|
5
5
|
type FinalizeAppRscResponseOptions = {
|
|
@@ -32,6 +32,6 @@ type FinalizeAppRscResponseOptions = {
|
|
|
32
32
|
* headers that throw on mutation, and Next.js does not apply config headers
|
|
33
33
|
* to redirects regardless.
|
|
34
34
|
*/
|
|
35
|
-
declare function finalizeAppRscResponse(response: Response, request: Request, options: FinalizeAppRscResponseOptions): Response
|
|
35
|
+
declare function finalizeAppRscResponse(response: Response, request: Request, options: FinalizeAppRscResponseOptions): Promise<Response>;
|
|
36
36
|
//#endregion
|
|
37
37
|
export { finalizeAppRscResponse };
|