vinext 1.4.2 → 1.4.4
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/prerender-paths.d.ts +11 -1
- package/dist/build/prerender-paths.js +41 -11
- package/dist/cli.js +1 -1
- package/dist/client/dev-error-overlay.d.ts +2 -1
- package/dist/client/dev-error-overlay.js +8 -3
- package/dist/config/config-matchers.js +6 -2
- package/dist/config/next-config.d.ts +9 -0
- package/dist/entries/app-rsc-entry.js +24 -12
- package/dist/entries/pages-server-entry.js +17 -4
- package/dist/index.js +48 -39
- package/dist/init-platform.js +2 -2
- package/dist/init.js +42 -5
- package/dist/server/api-handler.js +8 -5
- package/dist/server/app-browser-entry.js +26 -47
- package/dist/server/app-browser-error.d.ts +1 -1
- package/dist/server/app-browser-error.js +13 -4
- package/dist/server/app-browser-navigation-controller.js +2 -2
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-state.js +2 -2
- package/dist/server/app-browser-supplemental-refresh.d.ts +13 -0
- package/dist/server/app-browser-supplemental-refresh.js +36 -4
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-history-state.js +1 -1
- package/dist/server/app-middleware.d.ts +2 -0
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-page-boundary-render.js +4 -2
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +5 -1
- package/dist/server/app-page-element-builder.d.ts +2 -0
- package/dist/server/app-page-element-builder.js +6 -5
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +7 -5
- package/dist/server/app-page-route-wiring.js +11 -9
- package/dist/server/app-pages-bridge.d.ts +6 -0
- package/dist/server/app-pages-bridge.js +8 -3
- package/dist/server/app-request-context.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +2 -3
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-route-handler-execution.js +1 -1
- package/dist/server/app-route-handler-response.d.ts +1 -0
- package/dist/server/app-route-handler-response.js +27 -2
- package/dist/server/app-router-entry.js +2 -3
- package/dist/server/app-rsc-cache-busting.d.ts +8 -0
- package/dist/server/app-rsc-cache-busting.js +13 -1
- package/dist/server/app-rsc-combined-handler.js +2 -1
- package/dist/server/app-rsc-handler.d.ts +4 -0
- package/dist/server/app-rsc-handler.js +41 -24
- package/dist/server/app-rsc-response-finalizer.d.ts +15 -3
- package/dist/server/app-rsc-response-finalizer.js +51 -7
- package/dist/server/app-rsc-response-stage.js +1 -1
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.js +18 -10
- package/dist/server/config-headers.d.ts +7 -0
- package/dist/server/config-headers.js +20 -1
- package/dist/server/edge-api-runtime.d.ts +6 -2
- package/dist/server/edge-api-runtime.js +21 -4
- package/dist/server/image-animation.d.ts +9 -0
- package/dist/server/image-animation.js +118 -0
- package/dist/server/image-optimization.d.ts +25 -5
- package/dist/server/image-optimization.js +305 -21
- package/dist/server/image-source-reader.d.ts +34 -0
- package/dist/server/image-source-reader.js +126 -0
- package/dist/server/metadata-route-response.d.ts +6 -1
- package/dist/server/metadata-route-response.js +24 -6
- package/dist/server/middleware-matcher.d.ts +1 -0
- package/dist/server/middleware-matcher.js +1 -1
- package/dist/server/middleware-runtime.d.ts +5 -0
- package/dist/server/middleware-runtime.js +48 -15
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +2 -1
- package/dist/server/navigation-planner.js +14 -6
- package/dist/server/nitro-request-target-plugin.d.ts +17 -0
- package/dist/server/nitro-request-target-plugin.js +22 -0
- package/dist/server/open-redirect.d.ts +2 -1
- package/dist/server/open-redirect.js +2 -1
- package/dist/server/pages-client-assets.d.ts +1 -0
- package/dist/server/pages-i18n.d.ts +7 -0
- package/dist/server/pages-i18n.js +14 -1
- package/dist/server/pages-node-compat.js +7 -3
- package/dist/server/pages-page-handler.js +4 -4
- package/dist/server/pages-request-pipeline.d.ts +9 -0
- package/dist/server/pages-request-pipeline.js +29 -10
- package/dist/server/pages-request-stage-entry.js +7 -2
- package/dist/server/pages-router-entry.js +3 -0
- package/dist/server/prod-server.d.ts +1 -1
- package/dist/server/prod-server.js +48 -54
- package/dist/server/remove-request-headers.d.ts +16 -0
- package/dist/server/remove-request-headers.js +23 -0
- package/dist/server/srvx-middleware-origin.d.ts +13 -0
- package/dist/server/srvx-middleware-origin.js +19 -0
- package/dist/server/srvx-request-target.d.ts +12 -0
- package/dist/server/srvx-request-target.js +20 -0
- package/dist/server/static-file-cache.js +10 -22
- package/dist/server/worker-image-optimization.d.ts +8 -1
- package/dist/server/worker-image-optimization.js +25 -6
- package/dist/server/worker-revalidation-context.js +1 -0
- package/dist/shims/cache-runtime.js +1 -1
- package/dist/shims/cache.js +6 -3
- package/dist/shims/client-page-root.js +2 -2
- package/dist/shims/error-boundary.d.ts +6 -2
- package/dist/shims/error-boundary.js +6 -4
- package/dist/shims/internal/navigation-untracked.js +1 -1
- package/dist/shims/metadata.js +1 -1
- package/dist/shims/navigation-server.js +1 -1
- package/dist/shims/navigation.js +4 -4
- package/dist/shims/navigation.react-server.js +3 -3
- package/dist/shims/request-context.d.ts +3 -1
- package/dist/shims/root-params.js +16 -2
- package/dist/shims/slot.js +3 -3
- package/dist/shims/url-utils.js +6 -1
- package/dist/utils/client-entry-manifest.d.ts +5 -0
- package/dist/utils/client-entry-manifest.js +1 -0
- package/dist/utils/client-runtime-metadata.d.ts +5 -0
- package/dist/utils/client-runtime-metadata.js +33 -7
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BrowserRouteManifest, BrowserRouteManifestInterception } from "../routing/browser-route-manifest.js";
|
|
1
2
|
import { AppElements } from "./app-elements-wire.js";
|
|
2
3
|
import "./app-elements.js";
|
|
3
4
|
import { AppRouterState } from "./app-browser-state.js";
|
|
@@ -31,6 +32,18 @@ export declare function resolvePersistedSourcePageRefreshes(options: {
|
|
|
31
32
|
refreshUrl: URL;
|
|
32
33
|
state: Pick<AppRouterState, "previousNextUrl" | "slotBindings">;
|
|
33
34
|
}): string[];
|
|
35
|
+
export type PersistedRefreshInterception = {
|
|
36
|
+
interception: BrowserRouteManifestInterception;
|
|
37
|
+
interceptionContext: string;
|
|
38
|
+
targetPathname: string;
|
|
39
|
+
};
|
|
40
|
+
export declare function resolvePersistedRefreshInterceptions(options: {
|
|
41
|
+
basePath: string;
|
|
42
|
+
refreshUrl: URL;
|
|
43
|
+
requestInterceptionContext: string | null;
|
|
44
|
+
routeManifest: BrowserRouteManifest | null;
|
|
45
|
+
state: Pick<AppRouterState, "interception" | "slotBindings">;
|
|
46
|
+
}): PersistedRefreshInterception[];
|
|
34
47
|
export declare function createSupplementalRefreshCoordinator(): {
|
|
35
48
|
abortAll(): void;
|
|
36
49
|
begin(options: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { normalizePathnameForRouteMatch } from "../routing/utils.js";
|
|
1
|
+
import { removeTrailingSlash, restoreBasePath, stripBasePath } from "../utils/base-path.js";
|
|
2
|
+
import { normalizePathnameForRouteMatch, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
3
3
|
import { normalizePath } from "./normalize-path.js";
|
|
4
|
+
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
4
5
|
import { APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_SLOT_BINDINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
5
6
|
import "./app-elements.js";
|
|
6
7
|
import { isNestedBfcacheSlotSegmentIdFor } from "./bfcache-identity.js";
|
|
@@ -131,7 +132,7 @@ function resolvePersistedSourcePageRefreshes(options) {
|
|
|
131
132
|
});
|
|
132
133
|
for (const activeRoutePath of activeRoutePaths) {
|
|
133
134
|
if (activeRoutePath !== refreshRoutePathname && (refreshRoutePathname === "/" || activeRoutePath.startsWith(refreshRoutePathname + "/"))) continue;
|
|
134
|
-
const pathname =
|
|
135
|
+
const pathname = restoreBasePath(activeRoutePath, options.basePath);
|
|
135
136
|
if (sourceUrlsByPathname.has(pathname)) continue;
|
|
136
137
|
const sourceUrl = new URL(pathname, options.refreshUrl);
|
|
137
138
|
sourceUrl.search = options.refreshUrl.search;
|
|
@@ -145,6 +146,37 @@ function resolvePersistedSourcePageRefreshes(options) {
|
|
|
145
146
|
}
|
|
146
147
|
return resolved;
|
|
147
148
|
}
|
|
149
|
+
function getMatchedUrlPathname(matchedUrl) {
|
|
150
|
+
return new URL(matchedUrl, "https://vinext.local").pathname;
|
|
151
|
+
}
|
|
152
|
+
function resolvePersistedRefreshInterceptions(options) {
|
|
153
|
+
const { basePath, refreshUrl, requestInterceptionContext, routeManifest, state } = options;
|
|
154
|
+
if (routeManifest === null) return [];
|
|
155
|
+
const refreshPathname = stripBasePath(refreshUrl.pathname, basePath);
|
|
156
|
+
const refreshPathParts = splitPathnameForRouteMatch(refreshPathname);
|
|
157
|
+
const resolved = [];
|
|
158
|
+
for (const binding of state.slotBindings) {
|
|
159
|
+
if (binding.state !== "active" || !binding.activeRouteId) continue;
|
|
160
|
+
if (!binding.interceptionId || !binding.interceptionSourceMatchedUrl) continue;
|
|
161
|
+
const activeRoute = AppElementsWire.parseElementKey(binding.activeRouteId);
|
|
162
|
+
if (activeRoute?.kind !== "route") continue;
|
|
163
|
+
const match = routeManifest.segmentGraph.interceptions.get(binding.interceptionId);
|
|
164
|
+
if (!match) continue;
|
|
165
|
+
const retainedInterception = state.interception?.slotId === binding.slotId && matchRoutePattern(splitPathnameForRouteMatch(getMatchedUrlPathname(state.interception.targetMatchedUrl)), match.targetPatternParts) !== null ? state.interception : null;
|
|
166
|
+
const targetPathname = retainedInterception?.targetMatchedUrl ?? activeRoute.path;
|
|
167
|
+
const targetParts = splitPathnameForRouteMatch(getMatchedUrlPathname(targetPathname));
|
|
168
|
+
if (requestInterceptionContext !== null && state.interception?.slotId === binding.slotId && matchRoutePattern(refreshPathParts, match.targetPatternParts) !== null && matchRoutePattern(targetParts, match.targetPatternParts) !== null) continue;
|
|
169
|
+
const targetUrl = new URL(targetPathname, refreshUrl);
|
|
170
|
+
targetUrl.pathname = restoreBasePath(targetUrl.pathname, basePath);
|
|
171
|
+
targetUrl.search = refreshUrl.search;
|
|
172
|
+
resolved.push({
|
|
173
|
+
interception: match,
|
|
174
|
+
interceptionContext: retainedInterception?.sourceMatchedUrl ?? binding.interceptionSourceMatchedUrl,
|
|
175
|
+
targetPathname: `${targetUrl.pathname}${targetUrl.search}`
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return resolved;
|
|
179
|
+
}
|
|
148
180
|
function createSupplementalRefreshCoordinator() {
|
|
149
181
|
const controllers = /* @__PURE__ */ new Set();
|
|
150
182
|
return {
|
|
@@ -202,4 +234,4 @@ async function resolveSupplementalRefreshes(options) {
|
|
|
202
234
|
}
|
|
203
235
|
}
|
|
204
236
|
//#endregion
|
|
205
|
-
export { SupplementalRefreshError, createSupplementalRefreshCoordinator, mergeRefreshedParallelSlot, requireCompleteSupplementalRefresh, resolvePersistedSourcePageRefreshes, resolveServerActionSupplementalRefresh, resolveSupplementalRefreshes };
|
|
237
|
+
export { SupplementalRefreshError, createSupplementalRefreshCoordinator, mergeRefreshedParallelSlot, requireCompleteSupplementalRefresh, resolvePersistedRefreshInterceptions, resolvePersistedSourcePageRefreshes, resolveServerActionSupplementalRefresh, resolveSupplementalRefreshes };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
2
2
|
import "./app-elements.js";
|
|
3
|
-
import { createBfcacheSegmentIdentityMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
|
|
4
3
|
import { NavigationTraceReasonCodes, NavigationTraceTransactionCodes, createNavigationTrace, prependNavigationTraceEntry } from "./navigation-trace.js";
|
|
5
4
|
import { mergeElements } from "../shims/slot.js";
|
|
5
|
+
import { createBfcacheSegmentIdentityMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
|
|
6
6
|
import { createPendingNavigationCommit, resolvePendingNavigationCommitDispositionDecision } from "./app-browser-state.js";
|
|
7
7
|
import { resolveAppPageRouteStateKey } from "./app-page-segment-state.js";
|
|
8
8
|
//#region src/server/app-browser-visible-commit.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { isNonNegativeSafeInteger } from "../utils/number.js";
|
|
1
2
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
2
3
|
import "./app-elements.js";
|
|
3
4
|
import { isBfcacheSegmentId } from "./app-bfcache-id.js";
|
|
4
|
-
import { isNonNegativeSafeInteger } from "../utils/number.js";
|
|
5
5
|
//#region src/server/app-history-state.ts
|
|
6
6
|
const VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY = "__vinext_previousNextUrl";
|
|
7
7
|
const VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY = "__vinext_historyIndex";
|
|
@@ -26,6 +26,8 @@ export type ApplyAppMiddlewareOptions = {
|
|
|
26
26
|
middlewareRequest?: Request;
|
|
27
27
|
module: MiddlewareModule;
|
|
28
28
|
request: Request;
|
|
29
|
+
/** Forwarded to `executeMiddleware`. */
|
|
30
|
+
restoreLocaleRootTrailingSlash?: boolean;
|
|
29
31
|
validateExternalRewriteRequest?: () => Promise<Response | null>;
|
|
30
32
|
/**
|
|
31
33
|
* Forwarded to `executeMiddleware` so the NextRequest exposes a NextURL with
|
|
@@ -203,6 +203,7 @@ async function applyAppMiddleware(options) {
|
|
|
203
203
|
},
|
|
204
204
|
requestBodyAlreadyIsolated: true,
|
|
205
205
|
request: middlewareRequest,
|
|
206
|
+
restoreLocaleRootTrailingSlash: options.restoreLocaleRootTrailingSlash,
|
|
206
207
|
skipTrailingSlashRedirect: options.skipTrailingSlashRedirect,
|
|
207
208
|
trailingSlash: options.trailingSlash
|
|
208
209
|
});
|
|
@@ -3,14 +3,14 @@ import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
|
3
3
|
import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
|
|
4
4
|
import { isRenderDynamicLatched, isStaticGenerationAccessError } from "../shims/internal/headers-state.js";
|
|
5
5
|
import { copyLinkHeaderProvenance } from "./app-response-header-provenance.js";
|
|
6
|
+
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
7
|
+
import { rewriteClientHookError } from "../shims/client-hook-error.js";
|
|
6
8
|
import { createArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
|
|
7
9
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
8
10
|
import "./app-elements.js";
|
|
9
11
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
10
12
|
import { ErrorBoundary, GlobalErrorBoundary, SerializedErrorBoundary } from "../shims/error-boundary.js";
|
|
11
|
-
import { rewriteClientHookError } from "../shims/client-hook-error.js";
|
|
12
13
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
13
|
-
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
14
14
|
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
15
15
|
import { buildRscRedirectFlightStream } from "./app-rsc-redirect-flight.js";
|
|
16
16
|
import { bufferAppPageBinaryStream, buildAppPageSpecialErrorResponse, resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
@@ -85,8 +85,10 @@ function wrapRenderedBoundaryElement(options) {
|
|
|
85
85
|
renderErrorBoundary(GlobalErrorComponent, children) {
|
|
86
86
|
return createElement(GlobalErrorBoundary, {
|
|
87
87
|
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
88
|
+
wrapsGlobalErrorBoundary: true,
|
|
88
89
|
children: createElement(ErrorBoundary, {
|
|
89
90
|
fallback: GlobalErrorComponent,
|
|
91
|
+
isGlobalErrorBoundary: true,
|
|
90
92
|
children
|
|
91
93
|
})
|
|
92
94
|
});
|
|
@@ -166,6 +166,7 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
166
166
|
buildPageElement: (route: TRoute, params: AppPageParams, opts: AppPageDispatchInterceptOptions | undefined, searchParams: URLSearchParams, options?: {
|
|
167
167
|
isForceStatic?: boolean;
|
|
168
168
|
isUncacheableRender?: boolean;
|
|
169
|
+
routeTreeOnlyPrefetchShell?: boolean;
|
|
169
170
|
/** Layouts the navigating client holds, which the render may leave out. */
|
|
170
171
|
mountedLayouts?: ReadonlySet<string> | null;
|
|
171
172
|
observeMetadataSearchParamsAccess?: boolean;
|
|
@@ -293,7 +293,8 @@ async function dispatchAppPageInner(options) {
|
|
|
293
293
|
const isOnDemandRevalidate = _isOnDemandRevalidate();
|
|
294
294
|
const shouldReadCache = isStoredRender && !isOnDemandRevalidate;
|
|
295
295
|
const isCacheCandidate = isCacheEligibleRender && isStaticEligible && options.pprFallbackShell === void 0 && !isNeverStoredPath;
|
|
296
|
-
const
|
|
296
|
+
const routeTreeOnlyPrefetchShell = options.pprFallbackShell === void 0 && (options.pprRuntime === void 0 || !options.isProduction);
|
|
297
|
+
const isUncacheableRender = !(isCacheEligibleRender && isStaticEligible) && routeTreeOnlyPrefetchShell;
|
|
297
298
|
const mountedLayouts = isUncacheableRender && options.isRscRequest && (options.renderMode ?? "navigation") === "navigation" && options.interceptionContext === null && options.isProgressiveActionRender !== true ? parseMountedLayoutsHeader(options.request.headers.get(VINEXT_MOUNTED_LAYOUTS_HEADER)) : null;
|
|
298
299
|
if (shouldReadCache && isStaticEligible) {
|
|
299
300
|
traceOperation = resolveAppPageTraceOperation({
|
|
@@ -387,6 +388,7 @@ async function dispatchAppPageInner(options) {
|
|
|
387
388
|
isForceStatic: revalidationDynamicConfig === "force-static",
|
|
388
389
|
observeMetadataSearchParamsAccess: revalidationDynamicConfig !== "force-static",
|
|
389
390
|
observePageSearchParamsAccess: revalidationDynamicConfig !== "force-static",
|
|
391
|
+
routeTreeOnlyPrefetchShell,
|
|
390
392
|
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
391
393
|
placeStreamedMetadataInHead: true,
|
|
392
394
|
onHeadPrepared(head) {
|
|
@@ -552,6 +554,7 @@ async function dispatchAppPageInner(options) {
|
|
|
552
554
|
observeMetadataSearchParamsAccess: interceptDynamicConfig !== "force-static",
|
|
553
555
|
observePageSearchParamsAccess: interceptDynamicConfig !== "force-static",
|
|
554
556
|
isUncacheableRender,
|
|
557
|
+
routeTreeOnlyPrefetchShell,
|
|
555
558
|
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
556
559
|
placeStreamedMetadataInHead: options.renderWholeDocument === true,
|
|
557
560
|
onHeadPrepared
|
|
@@ -611,6 +614,7 @@ async function dispatchAppPageInner(options) {
|
|
|
611
614
|
observeMetadataSearchParamsAccess: !isForceStatic,
|
|
612
615
|
observePageSearchParamsAccess: !isForceStatic,
|
|
613
616
|
isUncacheableRender,
|
|
617
|
+
routeTreeOnlyPrefetchShell,
|
|
614
618
|
mountedLayouts: interceptResult.interceptOpts ? null : mountedLayouts,
|
|
615
619
|
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
616
620
|
placeStreamedMetadataInHead: options.renderWholeDocument === true,
|
|
@@ -66,6 +66,8 @@ export type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> =
|
|
|
66
66
|
isForceStatic?: boolean;
|
|
67
67
|
/** The render can never be stored (see buildAppPageElements). */
|
|
68
68
|
isUncacheableRender?: boolean;
|
|
69
|
+
/** A loading shell without a loading boundary is the route tree (see buildAppPageElements). */
|
|
70
|
+
routeTreeOnlyPrefetchShell?: boolean;
|
|
69
71
|
/** Layouts the navigating client holds (see buildAppPageElements). */
|
|
70
72
|
mountedLayouts?: ReadonlySet<string> | null;
|
|
71
73
|
/** Observe page metadata `searchParams` access for cache-safety classification. */
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { isPromiseLike } from "../utils/promise.js";
|
|
2
2
|
import { APP_RSC_RENDER_MODE_NAVIGATION } from "./app-rsc-render-mode.js";
|
|
3
|
+
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
4
|
+
import { withUseCacheLayoutMarker, withUseCachePageMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
3
5
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
4
6
|
import "./app-elements.js";
|
|
5
|
-
import {
|
|
7
|
+
import { ClientPageRoot } from "../shims/client-page-root.js";
|
|
6
8
|
import { ErrorBoundary, ForbiddenBoundary, NotFoundBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
7
|
-
import {
|
|
8
|
-
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
9
|
+
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPagePatternStateKey, resolveAppPageRouteStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
9
10
|
import { tagAppPagePageError, tagAppPageSlotError } from "./app-page-execution.js";
|
|
10
11
|
import { createAppPageMetadataSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
11
12
|
import { resolveAppPageBranchParams } from "./app-page-params.js";
|
|
@@ -19,7 +20,6 @@ import { resolveAppPageModuleTraceSegment, traceCreateComponentTree, traceGetLay
|
|
|
19
20
|
import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath, resolveAppPageLoadingModuleAtOrAbove } from "./app-page-route-wiring.js";
|
|
20
21
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
21
22
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
22
|
-
import { ClientPageRoot } from "../shims/client-page-root.js";
|
|
23
23
|
import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
24
24
|
import { Fragment, Suspense, cache, createElement } from "react";
|
|
25
25
|
//#region src/server/app-page-element-builder.ts
|
|
@@ -107,7 +107,7 @@ function traceAppPageInterceptLayoutModules(modules, branchSegments, layoutSegme
|
|
|
107
107
|
async function buildPageElements(options) {
|
|
108
108
|
const { route, params, routePath, displayPathname = routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
|
|
109
109
|
const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
|
|
110
|
-
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, isForceStatic = false, isUncacheableRender = false, mountedLayouts = null, serveStreamingMetadata, placeStreamedMetadataInHead = false, isProduction = process.env.NODE_ENV === "production", onHeadPrepared } = pageRequest;
|
|
110
|
+
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, isForceStatic = false, isUncacheableRender = false, routeTreeOnlyPrefetchShell = false, mountedLayouts = null, serveStreamingMetadata, placeStreamedMetadataInHead = false, isProduction = process.env.NODE_ENV === "production", onHeadPrepared } = pageRequest;
|
|
111
111
|
const pageModule = route.page;
|
|
112
112
|
const isSiblingIntercept = opts?.interceptSlotKey === "__vinext_page_intercept" && !!opts?.interceptPage;
|
|
113
113
|
const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
|
|
@@ -414,6 +414,7 @@ async function buildPageElements(options) {
|
|
|
414
414
|
globalErrorModule: globalErrorModule ?? DEFAULT_GLOBAL_ERROR_MODULE,
|
|
415
415
|
isRscRequest,
|
|
416
416
|
isUncacheableRender,
|
|
417
|
+
routeTreeOnlyPrefetchShell,
|
|
417
418
|
interceptionId: opts?.interceptionId ?? null,
|
|
418
419
|
mountedLayouts,
|
|
419
420
|
mountedSlotIds,
|
|
@@ -17,11 +17,11 @@ import { applyPrerenderCacheLifeHeader, applyPrerenderCacheTagsHeader } from "./
|
|
|
17
17
|
import { copyLinkHeaderProvenance, getFrameworkLinkHeader } from "./app-response-header-provenance.js";
|
|
18
18
|
import { traceResponseStartWithCompletion } from "./response-start-tracing.js";
|
|
19
19
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
20
|
+
import { isBailoutToCSRError } from "../shims/navigation-errors.js";
|
|
20
21
|
import { createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion } from "./artifact-compatibility.js";
|
|
21
22
|
import { AppElementsWire, isAppElementsRecord } from "./app-elements-wire.js";
|
|
22
23
|
import "./app-elements.js";
|
|
23
24
|
import { appendRscCompletionMetadata } from "./rsc-completion-metadata.js";
|
|
24
|
-
import { isBailoutToCSRError } from "../shims/navigation-errors.js";
|
|
25
25
|
import { applyClientStaleTimeHeader, applyEdgeRuntimeHeader, buildAppPageHtmlResponse, buildAppPageRscResponse, resolveAppPageHtmlResponsePolicy, resolveAppPageRscResponsePolicy, resolveUncacheableCacheControl } from "./app-page-response.js";
|
|
26
26
|
import { buildAppPageFontLinkHeader, readAppPageBinaryStream, resolveAppPageCaughtNotFoundBoundaries, resolveAppPageShellSpecialError, resolveAppPageSpecialError, resolveAppPageSpecialErrorStoredHeaders, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
|
|
27
27
|
import { buildAppPageHtmlDocumentResponse, buildAppPageLinkHeader, createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery } from "./app-page-stream.js";
|
|
@@ -220,11 +220,7 @@ type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule,
|
|
|
220
220
|
isRscRequest?: boolean;
|
|
221
221
|
/**
|
|
222
222
|
* The render can never be stored and, in production, is never sent with
|
|
223
|
-
* static cache headers (see app-page-dispatch.ts)
|
|
224
|
-
* prefetch without a loading boundary may skip its layouts. A render that
|
|
225
|
-
* may be stored keeps them, so a layout's dynamic API read still keeps it
|
|
226
|
-
* out of the cache. An explicit CDN cache policy on a dynamic route can
|
|
227
|
-
* still store the route tree, as a CDN would store Next.js's.
|
|
223
|
+
* static cache headers (see app-page-dispatch.ts).
|
|
228
224
|
*/
|
|
229
225
|
isUncacheableRender?: boolean;
|
|
230
226
|
/**
|
|
@@ -236,6 +232,12 @@ type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule,
|
|
|
236
232
|
mountedLayouts?: ReadonlySet<string> | null;
|
|
237
233
|
mountedSlotIds?: ReadonlySet<string> | null;
|
|
238
234
|
renderIdentity?: AppPageRenderIdentity;
|
|
235
|
+
/**
|
|
236
|
+
* The render has no PPR (see app-page-dispatch.ts), so a loading-shell
|
|
237
|
+
* prefetch without a loading boundary sends only the route tree. Without it,
|
|
238
|
+
* the layouts render, as Next.js renders them with isRoutePPREnabled.
|
|
239
|
+
*/
|
|
240
|
+
routeTreeOnlyPrefetchShell?: boolean;
|
|
239
241
|
renderMode?: AppRscRenderMode;
|
|
240
242
|
routePath: string;
|
|
241
243
|
semanticPageIdentity?: Readonly<{
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "./app-rsc-render-mode.js";
|
|
2
2
|
import { fnv1a64 } from "../utils/hash.js";
|
|
3
3
|
import { createInlineScriptTag, escapeHtmlAttr } from "./html.js";
|
|
4
|
+
import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
|
|
5
|
+
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
4
6
|
import { APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
5
7
|
import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX } from "./app-elements.js";
|
|
6
8
|
import { createBfcacheChildSegmentStateKey } from "./bfcache-identity.js";
|
|
7
|
-
import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
|
|
8
|
-
import { hashMountedLayoutIdentity } from "./app-mounted-layouts.js";
|
|
9
9
|
import { BfcacheChildrenBoundary, BfcacheSegmentBoundary, Children as Children$1, ParallelSlot, Slot } from "../shims/slot.js";
|
|
10
|
-
import
|
|
10
|
+
import DefaultForbidden from "../shims/default-forbidden.js";
|
|
11
11
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
12
|
+
import DefaultNotFound from "../shims/default-not-found.js";
|
|
13
|
+
import DefaultUnauthorized from "../shims/default-unauthorized.js";
|
|
12
14
|
import { ErrorBoundary, ForbiddenBoundary, GlobalErrorBoundary, HttpAccessFallbackPassthrough, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
13
15
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
14
|
-
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
15
16
|
import { MetadataHead, ViewportHead, renderMetadataToHtml } from "../shims/metadata.js";
|
|
17
|
+
import { StreamedIconsInsertion } from "../shims/streamed-icons.js";
|
|
18
|
+
import { hashMountedLayoutIdentity } from "./app-mounted-layouts.js";
|
|
19
|
+
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPageSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
|
|
16
20
|
import { APP_PAGE_NOT_FOUND_BOUNDARY_ID, tagAppPageLayoutError, tagAppPageSlotError } from "./app-page-execution.js";
|
|
17
21
|
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
18
|
-
import DefaultForbidden from "../shims/default-forbidden.js";
|
|
19
|
-
import DefaultNotFound from "../shims/default-not-found.js";
|
|
20
|
-
import DefaultUnauthorized from "../shims/default-unauthorized.js";
|
|
21
|
-
import { StreamedIconsInsertion } from "../shims/streamed-icons.js";
|
|
22
22
|
import { createAppRenderDependency, invokeAppComponentMappingErrors, isReactOwnedAppComponent, renderAfterAppDependencies, renderAppComponentWithDependencyBarrier } from "./app-render-dependency.js";
|
|
23
23
|
import { createAppPageLayoutGate, registerAppPageLayoutGate } from "./app-page-layout-gate.js";
|
|
24
24
|
import { probeReactServerSubtree } from "./app-page-probe.js";
|
|
@@ -514,7 +514,7 @@ function buildAppPageElements(options) {
|
|
|
514
514
|
[pageElementId]: null,
|
|
515
515
|
[routeId]: null
|
|
516
516
|
};
|
|
517
|
-
if (isPrefetchLoadingShell && !shouldRenderPrefetchLoadingShell && options.
|
|
517
|
+
if (isPrefetchLoadingShell && !shouldRenderPrefetchLoadingShell && options.routeTreeOnlyPrefetchShell === true) return {
|
|
518
518
|
...metadataEntries,
|
|
519
519
|
...options.route.staticSiblings && options.route.staticSiblings.length > 0 ? { [APP_STATIC_SIBLINGS_KEY]: options.route.staticSiblings } : {},
|
|
520
520
|
[pageElementId]: null,
|
|
@@ -981,8 +981,10 @@ function buildAppPageElements(options) {
|
|
|
981
981
|
const globalErrorComponent = getErrorBoundaryExport(options.globalErrorModule);
|
|
982
982
|
routeChildren = /* @__PURE__ */ jsx(GlobalErrorBoundary, {
|
|
983
983
|
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
984
|
+
wrapsGlobalErrorBoundary: globalErrorComponent !== null,
|
|
984
985
|
children: globalErrorComponent ? /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
985
986
|
fallback: globalErrorComponent,
|
|
987
|
+
isGlobalErrorBoundary: true,
|
|
986
988
|
children: routeChildren
|
|
987
989
|
}) : routeChildren
|
|
988
990
|
});
|
|
@@ -57,6 +57,12 @@ type RenderPagesFallbackOptions = {
|
|
|
57
57
|
pathname?: string;
|
|
58
58
|
pagesDataRequest?: Request | null;
|
|
59
59
|
request: Request;
|
|
60
|
+
/**
|
|
61
|
+
* The basePath `request.url` still carries. The page renderer receives the
|
|
62
|
+
* URL without it, as in the Pages Router pipeline, so `req.url` and `asPath`
|
|
63
|
+
* leave it out like Next.js.
|
|
64
|
+
*/
|
|
65
|
+
requestBasePath?: string;
|
|
60
66
|
/** The shared cache entry answers every host; a request-time render is not stored. */
|
|
61
67
|
sharedAcrossHosts?: boolean;
|
|
62
68
|
url: URL;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { stripBasePath } from "../utils/base-path.js";
|
|
1
2
|
import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
|
|
2
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
|
+
import { isLocaleRedirect, markLocaleRedirect } from "./pages-i18n.js";
|
|
3
5
|
import { beginRouteCacheability, markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
|
|
4
6
|
import { mergeHeaders } from "./worker-utils.js";
|
|
5
7
|
import { pagesRouteHasPriorityOverAppRoute } from "./hybrid-route-priority.js";
|
|
@@ -18,7 +20,7 @@ function applyPagesMiddlewareContext(response, middlewareContext) {
|
|
|
18
20
|
* Fallback handler to route App Router requests to the Pages Router when no App Router route matches.
|
|
19
21
|
*/
|
|
20
22
|
async function renderPagesFallback(options, dependencies) {
|
|
21
|
-
const { allowRscDocumentFallback = false, appRouteMatch = null, isDataRequest = false, isRscRequest, initialResponseHeaders, matchKind, middlewareContext, pathname = options.url.pathname, pagesDataRequest = null, request, sharedAcrossHosts = false, url } = options;
|
|
23
|
+
const { allowRscDocumentFallback = false, appRouteMatch = null, isDataRequest = false, isRscRequest, initialResponseHeaders, matchKind, middlewareContext, pathname = options.url.pathname, pagesDataRequest = null, request, requestBasePath = "", sharedAcrossHosts = false, url } = options;
|
|
22
24
|
const { loadPagesEntry, buildRequestHeaders, applyRouteHandlerMiddlewareContext, getDraftModeCookieHeader } = dependencies;
|
|
23
25
|
if (isRscRequest && !allowRscDocumentFallback) return null;
|
|
24
26
|
const pagesEntry = await loadPagesEntry();
|
|
@@ -67,8 +69,10 @@ async function renderPagesFallback(options, dependencies) {
|
|
|
67
69
|
if (runtimeDataKind === "server" || runtimeDataKind === "initial") markRouteCacheabilityDynamic("getInitialProps render shares a cache entry across hosts");
|
|
68
70
|
}
|
|
69
71
|
const pagesRequest = claimPagesRequest();
|
|
72
|
+
const renderRequestUrl = new URL(pagesDataRequest?.url ?? pagesRequest.url);
|
|
73
|
+
if (!pagesDataRequest) renderRequestUrl.pathname = stripBasePath(renderRequestUrl.pathname, requestBasePath);
|
|
70
74
|
const renderArgs = [
|
|
71
|
-
|
|
75
|
+
renderRequestUrl.href === pagesRequest.url ? pagesRequest : cloneRequestWithUrl(pagesRequest, renderRequestUrl.href),
|
|
72
76
|
pagesUrl,
|
|
73
77
|
{},
|
|
74
78
|
getRequestExecutionContext() ?? void 0,
|
|
@@ -76,7 +80,8 @@ async function renderPagesFallback(options, dependencies) {
|
|
|
76
80
|
];
|
|
77
81
|
const pagesRes = isDataRequest ? await (initialResponseHeaders ? pagesEntry.renderPage(...renderArgs, { isDataReq: true }, initialResponseHeaders) : pagesEntry.renderPage(...renderArgs, { isDataReq: true })) : await (initialResponseHeaders ? pagesEntry.renderPage(...renderArgs, void 0, initialResponseHeaders) : pagesEntry.renderPage(...renderArgs));
|
|
78
82
|
if (pagesRes.status === 404 && pageMatch === null) return null;
|
|
79
|
-
|
|
83
|
+
const response = applyDraftModeCookie(applyPagesMiddlewareContext(pagesRes, middlewareContext), getDraftModeCookieHeader());
|
|
84
|
+
return isLocaleRedirect(pagesRes) ? markLocaleRedirect(response) : response;
|
|
80
85
|
}
|
|
81
86
|
/**
|
|
82
87
|
* Append a middleware-emitted `__prerender_bypass` Set-Cookie header to a Pages
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { setHeadersContext } from "../shims/headers.js";
|
|
2
|
+
import { setRootParams } from "../shims/root-params.js";
|
|
2
3
|
import { setNavigationContext } from "../shims/navigation-context-state.js";
|
|
3
4
|
import "../shims/navigation-server.js";
|
|
4
|
-
import { setRootParams } from "../shims/root-params.js";
|
|
5
5
|
//#region src/server/app-request-context.ts
|
|
6
6
|
/**
|
|
7
7
|
* Set navigation context in the ALS-backed store. "use client" components
|
|
@@ -9,7 +9,7 @@ import "./server-globals.js";
|
|
|
9
9
|
import { getExplicitCdnCacheAdapter } from "../shims/cdn-cache-state.js";
|
|
10
10
|
import { applyCdnResponseIdentityHeaders, validateCdnRequest } from "./cache-control.js";
|
|
11
11
|
import { registerLazyDataCacheHandler } from "../shims/cache-handler.js";
|
|
12
|
-
import {
|
|
12
|
+
import { readImageOptimizationSignal } from "./image-optimization.js";
|
|
13
13
|
import { consumeFrameworkRequestRoute, traceFrameworkRequest } from "./request-tracing.js";
|
|
14
14
|
import { createStaticAssetRequest, resolveStaticAssetSignal } from "./worker-utils.js";
|
|
15
15
|
import { readTrustedPrerenderStateFromHeaders } from "./prerender-route-params.js";
|
|
@@ -75,7 +75,6 @@ async function handleRequest(request, env, platformCtx, dispatchResponseStage, a
|
|
|
75
75
|
if (cdnValidationResponse) return cdnValidationResponse;
|
|
76
76
|
}
|
|
77
77
|
const url = new URL(request.url);
|
|
78
|
-
const servesImages = Boolean(assets) && getImageOptimizer() !== null;
|
|
79
78
|
const protocolRelativeGuard = guardProtocolRelativeUrl(url.pathname, url.search);
|
|
80
79
|
if (protocolRelativeGuard) return protocolRelativeGuard;
|
|
81
80
|
try {
|
|
@@ -104,7 +103,7 @@ async function handleRequest(request, env, platformCtx, dispatchResponseStage, a
|
|
|
104
103
|
};
|
|
105
104
|
const handle = () => requestRscHandler(request, ctx, trackedDispatchResponseStage, probeMode, ctx.isPrerenderPathDiscovery === true, trustedPrerenderState);
|
|
106
105
|
let response = await runWithExecutionContext(ctx, handle);
|
|
107
|
-
const imageSignal =
|
|
106
|
+
const imageSignal = assets ? readImageOptimizationSignal(response) : null;
|
|
108
107
|
if (imageSignal && assets) {
|
|
109
108
|
const { fetchSignalledPublicFile, serveWorkerImageOptimization } = await import("./worker-image-optimization.js");
|
|
110
109
|
response = await serveWorkerImageOptimization(request, imageSignal, __imageAllowedWidths, __imageConfig, {
|
|
@@ -14,9 +14,9 @@ import { ensureFetchPatch, getCollectedFetchTags, setCurrentFetchCacheMode, setC
|
|
|
14
14
|
import { resolveAppRouteHandlerFetchCacheMode } from "./app-segment-config.js";
|
|
15
15
|
import { traceResponseStart } from "./response-start-tracing.js";
|
|
16
16
|
import { applyRouteHandlerMiddlewareContext, finalizeRouteHandlerResponse } from "./app-route-handler-response.js";
|
|
17
|
+
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
17
18
|
import { setNavigationContext } from "../shims/navigation-context-state.js";
|
|
18
19
|
import "../shims/navigation.js";
|
|
19
|
-
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
20
20
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
21
21
|
import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
|
|
22
22
|
import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, hasNonStaticAppRouteHandlerMethods, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
@@ -10,8 +10,8 @@ import { isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
|
|
|
10
10
|
import { _drainPendingRevalidations } from "../shims/cache-request-state.js";
|
|
11
11
|
import { copyLinkHeaderProvenance } from "./app-response-header-provenance.js";
|
|
12
12
|
import { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss } from "./app-route-handler-response.js";
|
|
13
|
-
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
14
13
|
import { runWithRootParamsUsage } from "../shims/root-params.js";
|
|
14
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
15
15
|
import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
|
|
16
16
|
import { resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldCompleteAppRouteHandlerResponse, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
17
17
|
import { createStaticGenerationHeadersContext, getAppRouteStaticGenerationErrorMessage } from "./app-static-generation.js";
|
|
@@ -17,6 +17,7 @@ type FinalizeRouteHandlerResponseOptions = {
|
|
|
17
17
|
draftCookie?: string | null;
|
|
18
18
|
isHead: boolean;
|
|
19
19
|
};
|
|
20
|
+
export declare function stripRouteHandlerFramingHeaders(response: Response): Response;
|
|
20
21
|
export declare function applyRouteHandlerMiddlewareContext(response: Response, middlewareContext: RouteHandlerMiddlewareContext, options?: MiddlewareResponseMergeOptions & {
|
|
21
22
|
appendResponseLink?: boolean;
|
|
22
23
|
}): Response;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
|
|
1
2
|
import "../utils/protocol-headers.js";
|
|
2
3
|
import { NEXT_CACHE_TAGS_HEADER, VINEXT_METADATA_ROUTE_CACHE_HEADER } from "./headers.js";
|
|
3
4
|
import { processMiddlewareHeaders } from "./request-pipeline.js";
|
|
@@ -11,6 +12,28 @@ import { getSetCookieName } from "./cookie-utils.js";
|
|
|
11
12
|
//#region src/server/app-route-handler-response.ts
|
|
12
13
|
const APP_ROUTE_REWRITE_ERROR = "NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.";
|
|
13
14
|
const APP_ROUTE_NEXT_ERROR = "NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler";
|
|
15
|
+
const ROUTE_HANDLER_FRAMING_HEADERS = [
|
|
16
|
+
"content-length",
|
|
17
|
+
"content-encoding",
|
|
18
|
+
"transfer-encoding"
|
|
19
|
+
];
|
|
20
|
+
function shouldDropRouteHandlerFramingHeaders(headers) {
|
|
21
|
+
if ("WebSocketPair" in globalThis) return false;
|
|
22
|
+
return ROUTE_HANDLER_FRAMING_HEADERS.some((name) => headers.has(name));
|
|
23
|
+
}
|
|
24
|
+
function deleteRouteHandlerFramingHeaders(headers) {
|
|
25
|
+
for (const name of ROUTE_HANDLER_FRAMING_HEADERS) headers.delete(name);
|
|
26
|
+
}
|
|
27
|
+
function stripRouteHandlerFramingHeaders(response) {
|
|
28
|
+
if (!shouldDropRouteHandlerFramingHeaders(response.headers)) return response;
|
|
29
|
+
const headers = new Headers(response.headers);
|
|
30
|
+
deleteRouteHandlerFramingHeaders(headers);
|
|
31
|
+
return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
|
|
32
|
+
status: response.status,
|
|
33
|
+
statusText: response.statusText,
|
|
34
|
+
headers
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
14
37
|
function hasMiddlewareHeader(headers) {
|
|
15
38
|
for (const key of headers.keys()) if (key.startsWith("x-middleware-")) return true;
|
|
16
39
|
return false;
|
|
@@ -42,6 +65,7 @@ function buildRouteHandlerCachedResponse(cachedValue, options) {
|
|
|
42
65
|
else headers.set(key, value);
|
|
43
66
|
headers.delete(NEXT_CACHE_TAGS_HEADER);
|
|
44
67
|
headers.delete(VINEXT_METADATA_ROUTE_CACHE_HEADER);
|
|
68
|
+
if (shouldDropRouteHandlerFramingHeaders(headers)) deleteRouteHandlerFramingHeaders(headers);
|
|
45
69
|
setCacheStateHeaders(headers, options.cacheState);
|
|
46
70
|
const { cacheControl } = decideIsr({
|
|
47
71
|
cacheState: options.cacheState,
|
|
@@ -152,8 +176,9 @@ async function buildAppRouteCacheValue(response, browserCacheControl) {
|
|
|
152
176
|
}
|
|
153
177
|
function finalizeRouteHandlerResponse(response, options) {
|
|
154
178
|
const { pendingCookies, draftCookie, isHead } = options;
|
|
155
|
-
if (pendingCookies.length === 0 && !draftCookie && !isHead && !hasMiddlewareHeader(response.headers)) return response;
|
|
179
|
+
if (pendingCookies.length === 0 && !draftCookie && !isHead && !hasMiddlewareHeader(response.headers) && !shouldDropRouteHandlerFramingHeaders(response.headers)) return response;
|
|
156
180
|
const headers = new Headers(response.headers);
|
|
181
|
+
if (shouldDropRouteHandlerFramingHeaders(headers)) deleteRouteHandlerFramingHeaders(headers);
|
|
157
182
|
processMiddlewareHeaders(headers);
|
|
158
183
|
applyMutableCookieFallbacks(headers, pendingCookies);
|
|
159
184
|
if (draftCookie) headers.append("Set-Cookie", draftCookie);
|
|
@@ -164,4 +189,4 @@ function finalizeRouteHandlerResponse(response, options) {
|
|
|
164
189
|
});
|
|
165
190
|
}
|
|
166
191
|
//#endregion
|
|
167
|
-
export { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, buildRouteHandlerCachedResponse, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss };
|
|
192
|
+
export { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, buildRouteHandlerCachedResponse, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss, stripRouteHandlerFramingHeaders };
|
|
@@ -8,7 +8,7 @@ import { runWithExecutionContext } from "../shims/request-context.js";
|
|
|
8
8
|
import "./server-globals.js";
|
|
9
9
|
import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
|
|
10
10
|
import { applyCdnResponseIdentityHeaders, validateCdnRequest } from "./cache-control.js";
|
|
11
|
-
import {
|
|
11
|
+
import { readImageOptimizationSignal } from "./image-optimization.js";
|
|
12
12
|
import { traceFrameworkRequest } from "./request-tracing.js";
|
|
13
13
|
import { createStaticAssetRequest, resolveStaticAssetSignal } from "./worker-utils.js";
|
|
14
14
|
import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
@@ -83,7 +83,6 @@ async function handleRequest(request, env, platformCtx) {
|
|
|
83
83
|
const cdnValidationResponse = await validateCdnRequest(request);
|
|
84
84
|
if (cdnValidationResponse) return cdnValidationResponse;
|
|
85
85
|
const url = new URL(request.url);
|
|
86
|
-
const servesImages = Boolean(assets) && getImageOptimizer() !== null;
|
|
87
86
|
const protocolRelativeGuard = guardProtocolRelativeUrl(url.pathname, url.search);
|
|
88
87
|
if (protocolRelativeGuard) return protocolRelativeGuard;
|
|
89
88
|
try {
|
|
@@ -109,7 +108,7 @@ async function handleRequest(request, env, platformCtx) {
|
|
|
109
108
|
const result = await (ctx ? runWithExecutionContext(ctx, handleFn) : handleFn());
|
|
110
109
|
if (result instanceof Response) {
|
|
111
110
|
let response = result;
|
|
112
|
-
const imageSignal =
|
|
111
|
+
const imageSignal = assets ? readImageOptimizationSignal(response) : null;
|
|
113
112
|
if (imageSignal && assets) {
|
|
114
113
|
const { fetchSignalledPublicFile, serveWorkerImageOptimization } = await import("./worker-image-optimization.js");
|
|
115
114
|
response = await serveWorkerImageOptimization(request, imageSignal, __imageAllowedWidths, __imageConfig, {
|
|
@@ -78,6 +78,14 @@ export declare function createRscRequestHeaders(options?: CreateRscRequestHeader
|
|
|
78
78
|
* their bytes can legitimately differ from the destination's full route.
|
|
79
79
|
*/
|
|
80
80
|
export declare function canonicalizePrewarmableRscRequestHeaders(headers: Headers): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Convert a search-param shell prefetch to the canonical navigation of its
|
|
83
|
+
* page. The shell renders the page with an empty query (app-page-dispatch.ts),
|
|
84
|
+
* which is what the query-free navigation renders, as Next.js's static
|
|
85
|
+
* prefetch of a page segment never varies on search params. The caller drops
|
|
86
|
+
* the query from the URL.
|
|
87
|
+
*/
|
|
88
|
+
export declare function canonicalizeDynamicShellRscRequestHeaders(headers: Headers): boolean;
|
|
81
89
|
/**
|
|
82
90
|
* Convert an ordinary loading-boundary prefetch to the shared loading-shell
|
|
83
91
|
* variant. The payload is selected by the three retained mode headers; visible
|
|
@@ -199,6 +199,18 @@ function canonicalizePrewarmableRscRequestHeaders(headers) {
|
|
|
199
199
|
return true;
|
|
200
200
|
}
|
|
201
201
|
/**
|
|
202
|
+
* Convert a search-param shell prefetch to the canonical navigation of its
|
|
203
|
+
* page. The shell renders the page with an empty query (app-page-dispatch.ts),
|
|
204
|
+
* which is what the query-free navigation renders, as Next.js's static
|
|
205
|
+
* prefetch of a page segment never varies on search params. The caller drops
|
|
206
|
+
* the query from the URL.
|
|
207
|
+
*/
|
|
208
|
+
function canonicalizeDynamicShellRscRequestHeaders(headers) {
|
|
209
|
+
if (headers.get("X-Vinext-Rsc-Render-Mode") !== "prefetch-dynamic-shell" || headers.has("X-Vinext-Interception-Context") || headers.has("X-Vinext-Interception-Id") || headers.has("X-Vinext-Mounted-Slots")) return false;
|
|
210
|
+
headers.delete(VINEXT_RSC_RENDER_MODE_HEADER);
|
|
211
|
+
return canonicalizePrewarmableRscRequestHeaders(headers);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
202
214
|
* Convert an ordinary loading-boundary prefetch to the shared loading-shell
|
|
203
215
|
* variant. The payload is selected by the three retained mode headers; visible
|
|
204
216
|
* router state is transport context and must not fragment the shared response.
|
|
@@ -285,4 +297,4 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
285
297
|
});
|
|
286
298
|
}
|
|
287
299
|
//#endregion
|
|
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 };
|
|
300
|
+
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, canonicalizeDynamicShellRscRequestHeaders, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, toPathAbsolutePathname };
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { getRequestExecutionContext, runWithExecutionContext } from "../shims/request-context.js";
|
|
2
2
|
import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
|
|
3
3
|
import { createAppRscRequestHandler } from "./app-rsc-handler.js";
|
|
4
|
+
import { resolveSrvxMiddlewareOrigin } from "./srvx-middleware-origin.js";
|
|
4
5
|
//#region src/server/app-rsc-combined-handler.ts
|
|
5
6
|
/** Combined request/response handler used by default single-stage App entries. */
|
|
6
7
|
function createAppRscHandler(options) {
|
|
7
8
|
const appRscRequestHandler = createAppRscRequestHandler(options);
|
|
8
9
|
const appRscHandler = (request, ctx, ...rest) => {
|
|
9
10
|
if (ctx != null || getRequestExecutionContext()) return appRscRequestHandler(request, ctx, ...rest);
|
|
10
|
-
const executionContext = createWorkerRevalidationContext(
|
|
11
|
+
const executionContext = createWorkerRevalidationContext({ middlewareOrigin: resolveSrvxMiddlewareOrigin(request) }, (internalRequest, internalCtx) => runWithExecutionContext(internalCtx, () => appRscRequestHandler(internalRequest, internalCtx)), "node");
|
|
11
12
|
return runWithExecutionContext(executionContext, () => appRscRequestHandler(request, ctx, ...rest));
|
|
12
13
|
};
|
|
13
14
|
return Object.assign(appRscHandler, { handleResponseStage(request, ctx, props, stageOptions) {
|