vinext 1.0.1 → 1.1.0
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 +72 -1
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- package/dist/build/prerender-paths.js +3 -78
- package/dist/build/prerender.js +33 -8
- package/dist/build/server-manifest.d.ts +7 -0
- package/dist/build/server-manifest.js +11 -1
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +3 -3
- package/dist/client/navigation-runtime.d.ts +11 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +3 -1
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +18 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -43
- package/dist/index.d.ts +4 -1
- package/dist/index.js +59 -30
- package/dist/plugins/cache-flight-codec.d.ts +19 -0
- package/dist/plugins/cache-flight-codec.js +68 -0
- package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
- package/dist/plugins/commonjs-esm-facade.js +80 -0
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- package/dist/routing/file-matcher.d.ts +1 -0
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/api-handler.js +17 -7
- package/dist/server/app-browser-entry.js +11 -7
- package/dist/server/app-browser-history-controller.d.ts +2 -0
- package/dist/server/app-browser-history-controller.js +8 -0
- package/dist/server/app-browser-interception-context.js +26 -2
- package/dist/server/app-browser-navigation-controller.d.ts +7 -1
- package/dist/server/app-browser-navigation-controller.js +93 -10
- package/dist/server/app-fallback-renderer.d.ts +2 -0
- package/dist/server/app-fallback-renderer.js +1 -0
- package/dist/server/app-history-state.d.ts +3 -0
- package/dist/server/app-history-state.js +7 -0
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +5 -0
- package/dist/server/app-page-boundary-render.js +6 -4
- package/dist/server/app-page-cache-finalizer.d.ts +11 -0
- package/dist/server/app-page-cache-finalizer.js +41 -7
- package/dist/server/app-page-cache-render.d.ts +18 -0
- package/dist/server/app-page-cache-render.js +63 -43
- package/dist/server/app-page-cache.d.ts +5 -0
- package/dist/server/app-page-cache.js +27 -7
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +47 -30
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +27 -42
- package/dist/server/app-page-execution.d.ts +15 -12
- package/dist/server/app-page-execution.js +30 -40
- package/dist/server/app-page-head.d.ts +5 -0
- package/dist/server/app-page-head.js +9 -3
- package/dist/server/app-page-probe.d.ts +0 -109
- package/dist/server/app-page-probe.js +3 -136
- package/dist/server/app-page-render-identity.d.ts +0 -1
- package/dist/server/app-page-render-identity.js +1 -1
- package/dist/server/app-page-render-observation.js +2 -2
- package/dist/server/app-page-render.d.ts +13 -5
- package/dist/server/app-page-render.js +219 -119
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +1 -2
- package/dist/server/app-page-response.d.ts +4 -3
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-route-wiring.d.ts +17 -5
- package/dist/server/app-page-route-wiring.js +55 -33
- package/dist/server/app-page-rsc-render-status.d.ts +48 -0
- package/dist/server/app-page-rsc-render-status.js +54 -0
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +6 -0
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +4 -4
- package/dist/server/app-response-header-provenance.d.ts +2 -0
- package/dist/server/app-response-header-provenance.js +10 -4
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-router-entry.js +3 -3
- package/dist/server/app-rsc-handler.d.ts +4 -0
- package/dist/server/app-rsc-handler.js +212 -96
- package/dist/server/app-rsc-request-normalization.d.ts +3 -1
- package/dist/server/app-rsc-request-normalization.js +4 -2
- package/dist/server/app-rsc-response-stage.d.ts +1 -1
- package/dist/server/app-rsc-response-stage.js +6 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -1
- package/dist/server/app-rsc-route-matching.js +36 -19
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -2
- package/dist/server/app-ssr-entry.js +6 -4
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +34 -15
- package/dist/server/app-worker-stages.d.ts +2 -2
- package/dist/server/app-worker-stages.js +3 -3
- package/dist/server/cacheability-request.js +9 -5
- package/dist/server/config-headers.js +2 -0
- package/dist/server/dev-server.js +12 -2
- package/dist/server/headers.d.ts +14 -0
- package/dist/server/headers.js +15 -1
- package/dist/server/image-optimization.d.ts +16 -0
- package/dist/server/image-optimization.js +26 -6
- package/dist/server/isr-cache.js +2 -2
- package/dist/server/middleware-matcher-pattern.js +8 -4
- package/dist/server/middleware-response-headers.js +2 -0
- package/dist/server/multi-stage.d.ts +8 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/node-response-signal.d.ts +16 -0
- package/dist/server/node-response-signal.js +26 -0
- package/dist/server/open-redirect.d.ts +47 -0
- package/dist/server/open-redirect.js +74 -1
- package/dist/server/pages-page-handler.js +21 -4
- package/dist/server/pages-request-stage-entry.js +8 -4
- package/dist/server/prod-server.d.ts +8 -7
- package/dist/server/prod-server.js +153 -69
- package/dist/server/request-pipeline.d.ts +20 -8
- package/dist/server/request-pipeline.js +21 -7
- package/dist/server/response-compression.d.ts +43 -0
- package/dist/server/response-compression.js +111 -0
- package/dist/server/seed-cache.js +10 -7
- package/dist/server/socket-error-backstop.d.ts +14 -0
- package/dist/server/socket-error-backstop.js +27 -4
- package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
- package/dist/shims/cache-adapter-instantiate.js +118 -0
- package/dist/shims/cache-callable-runtime.d.ts +2 -40
- package/dist/shims/cache-callable-runtime.js +50 -168
- package/dist/shims/cache-flight-arguments.d.ts +22 -0
- package/dist/shims/cache-flight-arguments.js +56 -0
- package/dist/shims/cache-request-state.d.ts +15 -0
- package/dist/shims/cache-request-state.js +31 -8
- package/dist/shims/cache-runtime.d.ts +6 -19
- package/dist/shims/cache-runtime.js +165 -225
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +5 -4
- package/dist/shims/cacheability-classification.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.js +19 -1
- package/dist/shims/error-boundary.d.ts +10 -10
- package/dist/shims/error-boundary.js +26 -7
- package/dist/shims/fetch-cache.d.ts +6 -0
- package/dist/shims/fetch-cache.js +19 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/headers.d.ts +13 -0
- package/dist/shims/headers.js +47 -4
- package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
- package/dist/shims/internal/app-page-props-cache-key.js +24 -15
- package/dist/shims/internal/headers-state.d.ts +0 -1
- package/dist/shims/metadata.js +3 -3
- package/dist/shims/navigation-errors.d.ts +6 -0
- package/dist/shims/navigation-errors.js +11 -1
- package/dist/shims/navigation.d.ts +7 -0
- package/dist/shims/navigation.js +14 -4
- package/dist/shims/request-context.d.ts +9 -0
- package/dist/shims/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/mdx-scan.d.ts +5 -0
- package/dist/utils/mdx-scan.js +8 -1
- package/dist/utils/regex-safety.d.ts +10 -0
- package/dist/utils/regex-safety.js +70 -18
- package/package.json +3 -3
|
@@ -21,11 +21,15 @@ export type AppPageCacheOutcomeMetric = Readonly<{
|
|
|
21
21
|
type AppPageCacheOutcomeRecorder = (metric: AppPageCacheOutcomeMetric) => void;
|
|
22
22
|
type AppPageCacheRenderResult = {
|
|
23
23
|
cacheControl?: CacheControlMetadata;
|
|
24
|
+
/** Response headers stored with both entries, such as a redirect's `location`. */
|
|
25
|
+
headers?: Record<string, string>;
|
|
24
26
|
html: string;
|
|
25
27
|
htmlRenderObservation: RenderObservation;
|
|
26
28
|
linkHeader?: string;
|
|
27
29
|
rscData: ArrayBuffer;
|
|
28
30
|
rscRenderObservation: RenderObservation;
|
|
31
|
+
/** The status of a render whose shell ended in a special error. */
|
|
32
|
+
status?: number;
|
|
29
33
|
/**
|
|
30
34
|
* The route-level revalidate of the route this render regenerated, or null
|
|
31
35
|
* when it has none and the render's cacheLife sets it. Undefined keeps the
|
|
@@ -40,6 +44,7 @@ type BuildAppPageCachedResponseOptions = {
|
|
|
40
44
|
cacheState: "HIT" | "STALE";
|
|
41
45
|
expireSeconds?: number;
|
|
42
46
|
isEdgeRuntime?: boolean;
|
|
47
|
+
isRoutePPREnabled?: boolean;
|
|
43
48
|
isRscRequest: boolean;
|
|
44
49
|
middlewareHeaders?: Headers | null;
|
|
45
50
|
middlewareStatus?: number | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_VARY_HEADER } from "./app-rsc-vary.js";
|
|
2
|
-
import { VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
|
|
2
|
+
import { VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
|
|
3
3
|
import { applyCdnResponseHeaders } from "./cache-control.js";
|
|
4
4
|
import { decideIsr } from "./isr-decision.js";
|
|
5
5
|
import { buildAppPageCacheValue, isrCacheControl, resolveRouteExpireSeconds } from "./isr-cache.js";
|
|
@@ -53,6 +53,10 @@ function buildAppPageCachedHeaders(options) {
|
|
|
53
53
|
if (options.params && Object.keys(options.params).length > 0) headers.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(options.params)));
|
|
54
54
|
if (options.mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);
|
|
55
55
|
applyClientStaleTimeHeader(headers, options.staleTimeSeconds);
|
|
56
|
+
for (const [name, value] of Object.entries(options.storedHeaders ?? {})) {
|
|
57
|
+
if (name.toLowerCase() === "link") continue;
|
|
58
|
+
for (const item of Array.isArray(value) ? value : [value]) headers.append(name, item);
|
|
59
|
+
}
|
|
56
60
|
mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
|
|
57
61
|
if (options.linkHeader) {
|
|
58
62
|
if (Array.isArray(options.linkHeader)) for (const value of options.linkHeader) headers.append("Link", value);
|
|
@@ -88,8 +92,15 @@ function resolveRegenerationFailureCacheControl(previous) {
|
|
|
88
92
|
...previous.stale === void 0 ? {} : { stale: previous.stale }
|
|
89
93
|
};
|
|
90
94
|
}
|
|
95
|
+
function isRedirectStatus(status) {
|
|
96
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
97
|
+
}
|
|
91
98
|
function buildAppPageCachedResponse(cachedValue, options) {
|
|
92
|
-
const
|
|
99
|
+
const storedStatus = cachedValue.status || 200;
|
|
100
|
+
const isRedirect = isRedirectStatus(storedStatus);
|
|
101
|
+
const isHttpErrorFallbackStatus = storedStatus === 401 || storedStatus === 403 || storedStatus === 404;
|
|
102
|
+
const replayStatus = options.isRscRequest && (isRedirect || options.isRoutePPREnabled === true) ? 200 : storedStatus;
|
|
103
|
+
const status = isRedirect || isHttpErrorFallbackStatus ? replayStatus : options.middlewareStatus ?? replayStatus;
|
|
93
104
|
const { cacheControl } = decideIsr({
|
|
94
105
|
cacheState: options.cacheState,
|
|
95
106
|
kind: "app-page",
|
|
@@ -108,17 +119,19 @@ function buildAppPageCachedResponse(cachedValue, options) {
|
|
|
108
119
|
middlewareHeaders: options.middlewareHeaders,
|
|
109
120
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
110
121
|
params: options.params,
|
|
111
|
-
staleTimeSeconds
|
|
122
|
+
staleTimeSeconds,
|
|
123
|
+
storedHeaders: cachedValue.headers
|
|
112
124
|
});
|
|
113
125
|
if (options.renderedPathAndSearch) rscHeaders.set(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, encodeURIComponent(options.renderedPathAndSearch));
|
|
114
126
|
applyRscCompatibilityIdHeader(rscHeaders);
|
|
115
127
|
applyRscDeploymentIdHeader(rscHeaders);
|
|
128
|
+
if (isHttpErrorFallbackStatus && status === storedStatus) rscHeaders.set(VINEXT_SPECIAL_ERROR_STATUS_HEADER, String(storedStatus));
|
|
116
129
|
return new Response(cachedValue.rscData, {
|
|
117
130
|
status,
|
|
118
131
|
headers: rscHeaders
|
|
119
132
|
});
|
|
120
133
|
}
|
|
121
|
-
if (typeof cachedValue.html !== "string" || cachedValue.html.length === 0) return null;
|
|
134
|
+
if (typeof cachedValue.html !== "string" || cachedValue.html.length === 0 && !isRedirect) return null;
|
|
122
135
|
const htmlHeaders = buildAppPageCachedHeaders({
|
|
123
136
|
cacheControl,
|
|
124
137
|
cacheState: options.cacheState,
|
|
@@ -126,7 +139,8 @@ function buildAppPageCachedResponse(cachedValue, options) {
|
|
|
126
139
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
127
140
|
linkHeader: cachedValue.headers?.link,
|
|
128
141
|
middlewareHeaders: options.middlewareHeaders,
|
|
129
|
-
staleTimeSeconds
|
|
142
|
+
staleTimeSeconds,
|
|
143
|
+
storedHeaders: cachedValue.headers
|
|
130
144
|
});
|
|
131
145
|
const response = new Response(cachedValue.html, {
|
|
132
146
|
status,
|
|
@@ -218,6 +232,7 @@ async function readAppPageCacheResponse(options) {
|
|
|
218
232
|
cacheControl: cached?.value.cacheControl,
|
|
219
233
|
expireSeconds: options.expireSeconds,
|
|
220
234
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
235
|
+
isRoutePPREnabled: options.isRoutePPREnabled,
|
|
221
236
|
isRscRequest: options.isRscRequest,
|
|
222
237
|
middlewareHeaders: options.middlewareHeaders,
|
|
223
238
|
middlewareStatus: options.middlewareStatus,
|
|
@@ -287,9 +302,13 @@ see more here https://nextjs.org/docs/messages/app-static-to-dynamic-error`);
|
|
|
287
302
|
return false;
|
|
288
303
|
}
|
|
289
304
|
};
|
|
290
|
-
|
|
305
|
+
const status = revalidatedPage.status ?? 200;
|
|
306
|
+
if (!await store(rscKey, buildAppPageCacheValue("", revalidatedPage.rscData, status, revalidatedPage.rscRenderObservation, revalidatedPage.headers))) return;
|
|
291
307
|
if (!options.isRscRequest) {
|
|
292
|
-
if (!await store(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0,
|
|
308
|
+
if (!await store(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, status, revalidatedPage.htmlRenderObservation, revalidatedPage.linkHeader ? {
|
|
309
|
+
...revalidatedPage.headers,
|
|
310
|
+
link: revalidatedPage.linkHeader
|
|
311
|
+
} : revalidatedPage.headers))) return;
|
|
293
312
|
}
|
|
294
313
|
options.isrDebug?.("regen complete", options.cleanPathname);
|
|
295
314
|
};
|
|
@@ -306,6 +325,7 @@ see more here https://nextjs.org/docs/messages/app-static-to-dynamic-error`);
|
|
|
306
325
|
cacheControl: cached.value.cacheControl,
|
|
307
326
|
expireSeconds: options.expireSeconds,
|
|
308
327
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
328
|
+
isRoutePPREnabled: options.isRoutePPREnabled,
|
|
309
329
|
isRscRequest: options.isRscRequest,
|
|
310
330
|
middlewareHeaders: options.middlewareHeaders,
|
|
311
331
|
middlewareStatus: options.middlewareStatus,
|
|
@@ -142,6 +142,7 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
142
142
|
observeMetadataSearchParamsAccess?: boolean;
|
|
143
143
|
observePageSearchParamsAccess?: boolean;
|
|
144
144
|
serveStreamingMetadata?: boolean;
|
|
145
|
+
placeStreamedMetadataInHead?: boolean;
|
|
145
146
|
}) => Promise<AppPageElement>;
|
|
146
147
|
clientReuseManifest?: ClientReuseManifestParseResult;
|
|
147
148
|
cleanPathname: string;
|
|
@@ -221,13 +222,14 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
221
222
|
staticParamsValidationParams?: AppPageParams;
|
|
222
223
|
rootParams?: RootParams;
|
|
223
224
|
probeLayoutAt: (layoutIndex: number, layoutParamAccess?: AppLayoutParamAccessTracker) => unknown;
|
|
224
|
-
probePage: (searchParams?: URLSearchParams) => unknown;
|
|
225
225
|
expireSeconds?: number;
|
|
226
226
|
renderErrorBoundaryPage: (error: unknown, errorOrigin?: "rsc" | "ssr") => Promise<Response | null>;
|
|
227
227
|
renderHttpAccessFallbackPage: (statusCode: number, opts: {
|
|
228
228
|
boundaryComponent?: unknown;
|
|
229
229
|
boundaryModule?: AppPageModule | null;
|
|
230
230
|
intercept?: AppPageDispatchInterceptOptions | null;
|
|
231
|
+
/** The document may be stored, so it must not carry the request's query. */
|
|
232
|
+
isCacheCandidate?: boolean;
|
|
231
233
|
layouts?: readonly AppPageModule[];
|
|
232
234
|
matchedParams: AppPageParams;
|
|
233
235
|
}, middlewareContext: AppPageMiddlewareContext | null) => Promise<Response | null>;
|
|
@@ -268,6 +270,12 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
268
270
|
searchParams: URLSearchParams;
|
|
269
271
|
}) => void;
|
|
270
272
|
renderMode?: AppRscRenderMode;
|
|
273
|
+
/**
|
|
274
|
+
* Render the document whole before its first byte, with streamed metadata in
|
|
275
|
+
* `<head>`, as a background regeneration does. The adapter sets this for a
|
|
276
|
+
* render no client is waiting on, such as its regeneration or a warm-up.
|
|
277
|
+
*/
|
|
278
|
+
renderWholeDocument?: boolean;
|
|
271
279
|
};
|
|
272
280
|
export declare function shouldReadAppPageCache(options: {
|
|
273
281
|
isProgressiveActionRender: boolean;
|
|
@@ -5,27 +5,28 @@ import { VINEXT_INTERCEPTION_ID_HEADER, VINEXT_RSC_VARY_HEADER } from "./app-rsc
|
|
|
5
5
|
import "./headers.js";
|
|
6
6
|
import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, markRouteCacheabilityPatternDynamic, readRouteCacheabilityState } from "../shims/cacheability-classification.js";
|
|
7
7
|
import { APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL } from "./app-rsc-render-mode.js";
|
|
8
|
-
import { AppElementsWire } from "./app-elements-wire.js";
|
|
9
|
-
import "./app-elements.js";
|
|
10
8
|
import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersContext, isDraftModeRequest, peekDynamicUsage, peekRenderRequestApiUsage, runWithIsolatedDynamicUsage, setHeadersContext } from "../shims/headers.js";
|
|
11
9
|
import { _captureRequestScopedCacheLifeAccessors } from "../shims/cache-request-state.js";
|
|
12
10
|
import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchRevalidate, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, setRefreshStaleFetchesInForeground } from "../shims/fetch-cache.js";
|
|
13
11
|
import { cacheabilityManifestPageState } from "./cacheability-manifest.js";
|
|
12
|
+
import { isAppPageStaticEligible } from "./app-segment-config.js";
|
|
13
|
+
import { AppElementsWire } from "./app-elements-wire.js";
|
|
14
|
+
import "./app-elements.js";
|
|
14
15
|
import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
15
16
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
17
|
+
import { getFrameworkLinkHeader } from "./app-response-header-provenance.js";
|
|
16
18
|
import { resolveUncacheableCacheControl } from "./app-page-response.js";
|
|
17
19
|
import { buildRscRedirectFlightStream } from "./app-rsc-redirect-flight.js";
|
|
18
|
-
import { buildAppPageSpecialErrorResponse,
|
|
20
|
+
import { buildAppPageSpecialErrorResponse, resolveAppPageShellSpecialError, resolveAppPageSpecialError, resolveAppPageSpecialErrorStoredHeaders } from "./app-page-execution.js";
|
|
19
21
|
import { resolveAppPageTraceOperation } from "./app-page-tracing.js";
|
|
20
22
|
import { createAppPageTreePath } from "./app-page-route-wiring.js";
|
|
21
23
|
import { traceResponseStart } from "./response-start-tracing.js";
|
|
22
24
|
import { buildAppPageTags } from "./implicit-tags.js";
|
|
23
25
|
import { consumeAppPageRenderObservationState, discardAppPageRenderState } from "./app-page-render-observation.js";
|
|
24
|
-
import {
|
|
26
|
+
import { createAppPageRscErrorTracker } from "./app-page-stream.js";
|
|
25
27
|
import { resolveAppPageParentHttpAccessBoundary, resolveAppPageParentHttpAccessBoundaryModule } from "./app-page-boundary.js";
|
|
26
28
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
27
29
|
import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
|
|
28
|
-
import { createAppPageRscErrorTracker } from "./app-page-stream.js";
|
|
29
30
|
import { createAppLayoutParamAccessTracker, isAppLayoutObservationUnsafeForStaticReuse } from "./app-layout-param-observation.js";
|
|
30
31
|
import { resolveAppPageMethodResponse } from "./app-page-method.js";
|
|
31
32
|
import { buildAppPageElement, resolveAppPageIntercept, resolveAppPageInterceptionRerenderTarget, validateAppPageDynamicParams } from "./app-page-request.js";
|
|
@@ -255,7 +256,6 @@ async function dispatchAppPageInner(options) {
|
|
|
255
256
|
const pageSearchParams = shouldUseEmptySearchParams ? new URLSearchParams() : options.searchParams;
|
|
256
257
|
const layoutParamAccess = createAppLayoutParamAccessTracker();
|
|
257
258
|
const activeLoadingTreePositions = getActiveLoadingTreePositions(route);
|
|
258
|
-
const hasActiveLoadingBoundary = activeLoadingTreePositions.length > 0;
|
|
259
259
|
setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
|
|
260
260
|
setCurrentFetchCacheMode(options.fetchCache ?? null);
|
|
261
261
|
setCurrentFetchRevalidate(currentRevalidateSeconds);
|
|
@@ -396,14 +396,16 @@ async function dispatchAppPageInner(options) {
|
|
|
396
396
|
isForceStatic: revalidationDynamicConfig === "force-static",
|
|
397
397
|
observeMetadataSearchParamsAccess: revalidationDynamicConfig !== "force-static",
|
|
398
398
|
observePageSearchParamsAccess: revalidationDynamicConfig !== "force-static",
|
|
399
|
-
serveStreamingMetadata:
|
|
399
|
+
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
400
|
+
placeStreamedMetadataInHead: true
|
|
400
401
|
});
|
|
401
402
|
const baseRevalidatedOnError = options.createRscOnErrorHandler(options.cleanPathname, revalidationTarget.route.pattern, { revalidateReason: "stale" });
|
|
402
403
|
const baseRevalidatedOnSsrError = options.createRscOnErrorHandler(options.cleanPathname, revalidationTarget.route.pattern, {
|
|
403
404
|
renderSource: "server-rendering",
|
|
404
405
|
revalidateReason: "stale"
|
|
405
406
|
});
|
|
406
|
-
|
|
407
|
+
const rscErrorTracker = createAppPageRscErrorTracker(baseRevalidatedOnError);
|
|
408
|
+
revalidationRscErrorTracker = rscErrorTracker;
|
|
407
409
|
const rendered = await renderAppPageCacheArtifacts({
|
|
408
410
|
basePath: options.basePath,
|
|
409
411
|
captureRscData: true,
|
|
@@ -416,14 +418,36 @@ async function dispatchAppPageInner(options) {
|
|
|
416
418
|
getNavigationContext: options.getNavigationContext,
|
|
417
419
|
loadSsrHandler: options.loadSsrHandler,
|
|
418
420
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
421
|
+
mirrorNextFlight: () => rscErrorTracker.getCapturedSpecialError() !== null,
|
|
419
422
|
navigationParams: revalidationTarget.navigationParams,
|
|
420
|
-
isCapturedRscError:
|
|
421
|
-
onError:
|
|
423
|
+
isCapturedRscError: rscErrorTracker.isCapturedError,
|
|
424
|
+
onError: rscErrorTracker.onRenderError,
|
|
422
425
|
onSsrError(error) {
|
|
423
426
|
reportedSsrRevalidationErrors.add(error);
|
|
424
427
|
return baseRevalidatedOnSsrError(error, void 0, void 0);
|
|
425
428
|
},
|
|
426
429
|
reactMaxHeadersLength: options.reactMaxHeadersLength,
|
|
430
|
+
async renderShellSpecialError(error) {
|
|
431
|
+
const specialError = resolveAppPageShellSpecialError(error, rscErrorTracker.getCapturedSpecialErrors(error));
|
|
432
|
+
if (!specialError) return null;
|
|
433
|
+
if (options.isRscRequest) {
|
|
434
|
+
if (specialError.fromMetadata === true) return null;
|
|
435
|
+
return {
|
|
436
|
+
headers: resolveAppPageSpecialErrorStoredHeaders(specialError, options.basePath),
|
|
437
|
+
html: "",
|
|
438
|
+
status: specialError.statusCode
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
if (revalidationTarget.route !== route) return null;
|
|
442
|
+
const document = await renderPageSpecialError(options, specialError, false, revalidationTarget.interceptOpts, true);
|
|
443
|
+
if (document.status !== specialError.statusCode) return null;
|
|
444
|
+
return {
|
|
445
|
+
headers: resolveAppPageSpecialErrorStoredHeaders(specialError, options.basePath),
|
|
446
|
+
html: await document.text(),
|
|
447
|
+
linkHeader: getFrameworkLinkHeader(document.headers) ?? void 0,
|
|
448
|
+
status: specialError.statusCode
|
|
449
|
+
};
|
|
450
|
+
},
|
|
427
451
|
renderToReadableStream: options.renderToReadableStream,
|
|
428
452
|
rootParams: options.rootParams,
|
|
429
453
|
route: revalidationTarget.route,
|
|
@@ -432,6 +456,7 @@ async function dispatchAppPageInner(options) {
|
|
|
432
456
|
});
|
|
433
457
|
options.clearRequestContext();
|
|
434
458
|
return {
|
|
459
|
+
headers: rendered.headers,
|
|
435
460
|
html: rendered.html,
|
|
436
461
|
htmlRenderObservation: rendered.htmlRenderObservation,
|
|
437
462
|
linkHeader: rendered.linkHeader,
|
|
@@ -440,6 +465,7 @@ async function dispatchAppPageInner(options) {
|
|
|
440
465
|
tags: rendered.tags,
|
|
441
466
|
cacheControl: rendered.cacheControl,
|
|
442
467
|
revalidateSeconds: revalidationRouteRevalidateSeconds,
|
|
468
|
+
status: rendered.status,
|
|
443
469
|
usedDynamicApi: rendered.usedDynamicApi
|
|
444
470
|
};
|
|
445
471
|
});
|
|
@@ -465,6 +491,7 @@ async function dispatchAppPageInner(options) {
|
|
|
465
491
|
if (dynamicParamsResponse) {
|
|
466
492
|
const renderedNotFound = await options.renderHttpAccessFallbackPage(404, { matchedParams: options.params }, options.middlewareContext);
|
|
467
493
|
const cachePolicy = {
|
|
494
|
+
dynamicStaleTimeSeconds: options.dynamicStaleTimeSeconds,
|
|
468
495
|
isDraftMode,
|
|
469
496
|
isDynamicError,
|
|
470
497
|
isForceDynamic,
|
|
@@ -510,7 +537,8 @@ async function dispatchAppPageInner(options) {
|
|
|
510
537
|
isForceStatic: sourceDynamicConfig === "force-static",
|
|
511
538
|
observeMetadataSearchParamsAccess: sourceDynamicConfig !== "force-static",
|
|
512
539
|
observePageSearchParamsAccess: sourceDynamicConfig !== "force-static",
|
|
513
|
-
serveStreamingMetadata: placeGeneratedMetadataInBody
|
|
540
|
+
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
541
|
+
placeStreamedMetadataInHead: options.renderWholeDocument === true
|
|
514
542
|
});
|
|
515
543
|
},
|
|
516
544
|
cleanPathname: options.cleanPathname,
|
|
@@ -565,19 +593,10 @@ async function dispatchAppPageInner(options) {
|
|
|
565
593
|
isForceStatic,
|
|
566
594
|
observeMetadataSearchParamsAccess: !isForceStatic,
|
|
567
595
|
observePageSearchParamsAccess: !isForceStatic,
|
|
568
|
-
serveStreamingMetadata: placeGeneratedMetadataInBody
|
|
596
|
+
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
597
|
+
placeStreamedMetadataInHead: options.renderWholeDocument === true
|
|
569
598
|
});
|
|
570
599
|
},
|
|
571
|
-
async probePageSpecialError() {
|
|
572
|
-
if (hasActiveLoadingBoundary) return null;
|
|
573
|
-
const pageError = await probeAppPageThrownError({
|
|
574
|
-
probePage: () => options.probePage(pageSearchParams),
|
|
575
|
-
runWithSuppressedHookWarning(probe) {
|
|
576
|
-
return options.runWithSuppressedHookWarning(probe);
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
return resolveAppPageSpecialError(pageError);
|
|
580
|
-
},
|
|
581
600
|
renderErrorBoundaryPage(buildError) {
|
|
582
601
|
return options.renderErrorBoundaryPage(buildError);
|
|
583
602
|
},
|
|
@@ -645,7 +664,6 @@ async function dispatchAppPageInner(options) {
|
|
|
645
664
|
return requestCacheLife.peek();
|
|
646
665
|
},
|
|
647
666
|
handlerStart: options.handlerStart,
|
|
648
|
-
hasLoadingBoundary: hasActiveLoadingBoundary,
|
|
649
667
|
omitPendingDynamicCacheState: hasRequestSearchParams && !(isCacheCandidate && !options.isRscRequest),
|
|
650
668
|
formState: options.formState ?? null,
|
|
651
669
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
@@ -657,7 +675,9 @@ async function dispatchAppPageInner(options) {
|
|
|
657
675
|
isStaticEligible,
|
|
658
676
|
isCacheCandidate,
|
|
659
677
|
isPrerender,
|
|
678
|
+
isRoutePPREnabled: options.pprRuntime !== void 0,
|
|
660
679
|
isSpeculativePrerender,
|
|
680
|
+
renderWholeDocument: options.renderWholeDocument === true && !options.isRscRequest,
|
|
661
681
|
isProduction: options.isProduction,
|
|
662
682
|
isRscRequest: options.isRscRequest,
|
|
663
683
|
traceOperation,
|
|
@@ -690,10 +710,6 @@ async function dispatchAppPageInner(options) {
|
|
|
690
710
|
probeLayoutAt(layoutIndex) {
|
|
691
711
|
return options.probeLayoutAt(layoutIndex, layoutParamAccess);
|
|
692
712
|
},
|
|
693
|
-
probePage() {
|
|
694
|
-
return options.probePage(pageSearchParams);
|
|
695
|
-
},
|
|
696
|
-
probePageBeforeRender: options.isRscRequest,
|
|
697
713
|
classification: {
|
|
698
714
|
getLayoutId(index) {
|
|
699
715
|
const treePosition = route.layoutTreePositions?.[index] ?? 0;
|
|
@@ -719,8 +735,8 @@ async function dispatchAppPageInner(options) {
|
|
|
719
735
|
renderLayoutSpecialError(specialError, layoutIndex) {
|
|
720
736
|
return renderLayoutSpecialError(options, specialError, layoutIndex, serveStreamingMetadata);
|
|
721
737
|
},
|
|
722
|
-
renderPageSpecialError(specialError) {
|
|
723
|
-
return renderPageSpecialError(options, specialError, serveStreamingMetadata, interceptResult.interceptOpts);
|
|
738
|
+
renderPageSpecialError(specialError, renderOptions) {
|
|
739
|
+
return renderPageSpecialError(options, specialError, serveStreamingMetadata, interceptResult.interceptOpts, renderOptions?.isCacheCandidate === true);
|
|
724
740
|
},
|
|
725
741
|
renderToReadableStream: options.renderToReadableStream,
|
|
726
742
|
hasCustomGlobalError: options.hasCustomGlobalError,
|
|
@@ -773,7 +789,7 @@ async function renderLayoutSpecialError(options, specialError, layoutIndex, serv
|
|
|
773
789
|
specialError
|
|
774
790
|
});
|
|
775
791
|
}
|
|
776
|
-
async function renderPageSpecialError(options, specialError, serveStreamingMetadata, intercept) {
|
|
792
|
+
async function renderPageSpecialError(options, specialError, serveStreamingMetadata, intercept, isCacheCandidate = false) {
|
|
777
793
|
return buildAppPageSpecialErrorResponse({
|
|
778
794
|
basePath: options.basePath,
|
|
779
795
|
buildRscRedirectFlightStream: (rscOptions) => buildRscRedirectFlightStream({
|
|
@@ -802,6 +818,7 @@ async function renderPageSpecialError(options, specialError, serveStreamingMetad
|
|
|
802
818
|
const useLayoutAlignedBoundary = boundaryLayoutIndex !== null && (routeBoundaryModule === null || routeBoundaryModule === parentBoundaryModule);
|
|
803
819
|
const fallbackOptions = {
|
|
804
820
|
intercept,
|
|
821
|
+
...isCacheCandidate ? { isCacheCandidate } : {},
|
|
805
822
|
matchedParams: options.params
|
|
806
823
|
};
|
|
807
824
|
if (useLayoutAlignedBoundary && boundaryLayoutIndex !== null) {
|
|
@@ -61,6 +61,13 @@ export type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> =
|
|
|
61
61
|
observeMetadataSearchParamsAccess?: boolean;
|
|
62
62
|
/** Whether generated metadata may stream into the response body. */
|
|
63
63
|
serveStreamingMetadata?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Wait for streamed metadata in `<head>`, for a document rendered whole
|
|
66
|
+
* before it's written, such as a background regeneration. Next.js does this
|
|
67
|
+
* for every static or ISR render. Its errors still reach the route's
|
|
68
|
+
* boundaries through the outlet.
|
|
69
|
+
*/
|
|
70
|
+
placeStreamedMetadataInHead?: boolean;
|
|
64
71
|
/** Whether streamed render errors must be sanitized for client transport. */
|
|
65
72
|
isProduction?: boolean;
|
|
66
73
|
};
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { isPromiseLike } from "../utils/promise.js";
|
|
2
2
|
import { APP_RSC_RENDER_MODE_NAVIGATION } from "./app-rsc-render-mode.js";
|
|
3
|
+
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
3
4
|
import { createAppPageRenderDependency, invokeAppComponent, isAppClientReference, isAppRenderSuspension, isReactOwnedAppComponent, renderAfterAppDependencies } from "./app-render-dependency.js";
|
|
4
5
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
5
6
|
import "./app-elements.js";
|
|
6
|
-
import {
|
|
7
|
-
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
7
|
+
import { withUseCacheLayoutMarker, withUseCachePageMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
8
8
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
9
|
-
import { withUseCachePageMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
10
9
|
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
11
10
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
12
|
-
import { prepareAppPageHead, resolveActiveParallelRouteHeadInputs } from "./app-page-head.js";
|
|
13
|
-
import { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
14
11
|
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPagePatternStateKey, resolveAppPageRouteStateKey } from "./app-page-segment-state.js";
|
|
15
12
|
import { sanitizeErrorForClient } from "./app-rsc-errors.js";
|
|
16
13
|
import { resolveAppPageModuleTraceSegment, traceCreateComponentTree, traceGetLayoutOrPageModule } from "./app-page-tracing.js";
|
|
17
14
|
import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath, resolveAppPageLoadingModuleAtOrAbove } from "./app-page-route-wiring.js";
|
|
15
|
+
import { collectAppPageSearchParams, hasAppPageDynamicMetadata, prepareAppPageHead, resolveActiveParallelRouteHeadInputs } from "./app-page-head.js";
|
|
18
16
|
import { resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport } from "./app-page-http-access-fallback-metadata.js";
|
|
19
17
|
import { ClientPageRoot } from "../shims/client-page-root.js";
|
|
20
18
|
import "./app-rsc-route-matching.js";
|
|
21
19
|
import { resolveAppPageParentHttpAccessBoundary } from "./app-page-boundary.js";
|
|
22
20
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
21
|
+
import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
22
|
+
import { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
23
23
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
24
|
-
import { Suspense, createElement } from "react";
|
|
24
|
+
import { Suspense, cache, createElement } from "react";
|
|
25
25
|
//#region src/server/app-page-element-builder.ts
|
|
26
26
|
function resolveInterceptLayoutParams(branchSegments, layoutSegments, params) {
|
|
27
27
|
return resolveAppPageBranchParams(branchSegments, layoutSegments.length, params, layoutSegments);
|
|
@@ -60,7 +60,7 @@ function traceAppPageInterceptLayoutModules(modules, branchSegments, layoutSegme
|
|
|
60
60
|
async function buildPageElements(options) {
|
|
61
61
|
const { route, params, routePath, displayPathname = routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
|
|
62
62
|
const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
|
|
63
|
-
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, isForceStatic = false, serveStreamingMetadata, isProduction = process.env.NODE_ENV === "production" } = pageRequest;
|
|
63
|
+
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, isForceStatic = false, serveStreamingMetadata, placeStreamedMetadataInHead = false, isProduction = process.env.NODE_ENV === "production" } = pageRequest;
|
|
64
64
|
const pageModule = route.page;
|
|
65
65
|
const isSiblingIntercept = opts?.interceptSlotKey === "__vinext_page_intercept" && !!opts?.interceptPage;
|
|
66
66
|
const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
|
|
@@ -140,7 +140,7 @@ async function buildPageElements(options) {
|
|
|
140
140
|
} : null;
|
|
141
141
|
const parallelRoutes = [...primaryParallelRouteHeadInput ? [primaryParallelRouteHeadInput.head] : [], ...activeParallelRouteHeadInputs.map((input) => input.head)];
|
|
142
142
|
const metadataSearchParamsObserver = observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0;
|
|
143
|
-
const
|
|
143
|
+
const headOptions = {
|
|
144
144
|
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
145
145
|
basePath: options.basePath ?? "",
|
|
146
146
|
layoutModules: route.layouts,
|
|
@@ -153,15 +153,11 @@ async function buildPageElements(options) {
|
|
|
153
153
|
routeSegments: route.routeSegments ?? null,
|
|
154
154
|
searchParams,
|
|
155
155
|
searchParamsObserver: metadataSearchParamsObserver
|
|
156
|
-
}
|
|
157
|
-
const
|
|
156
|
+
};
|
|
157
|
+
const hasDynamicMetadata = hasAppPageDynamicMetadata(headOptions);
|
|
158
|
+
const { pageSearchParams } = collectAppPageSearchParams(searchParams);
|
|
158
159
|
const streamGeneratedHead = serveStreamingMetadata ?? shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots);
|
|
159
|
-
const metadataPlacement = hasDynamicMetadata && streamGeneratedHead ? "body" : "head";
|
|
160
|
-
const shouldDeferMetadata = metadataPlacement === "body";
|
|
161
|
-
const streamingMetadata = shouldDeferMetadata ? isProduction ? preparedHead.metadata.catch((error) => {
|
|
162
|
-
throw sanitizeErrorForClient(error, "production");
|
|
163
|
-
}) : preparedHead.metadata : null;
|
|
164
|
-
streamingMetadata?.catch(() => null);
|
|
160
|
+
const metadataPlacement = hasDynamicMetadata && streamGeneratedHead && !placeStreamedMetadataInHead ? "body" : "head";
|
|
165
161
|
const resolveNotFoundFallbackPlanOptions = () => {
|
|
166
162
|
const routeBoundaryModule = route.notFound;
|
|
167
163
|
const parentBoundary = resolveAppPageParentHttpAccessBoundary({
|
|
@@ -189,8 +185,6 @@ async function buildPageElements(options) {
|
|
|
189
185
|
routeSegments: route.routeSegments ?? null
|
|
190
186
|
};
|
|
191
187
|
};
|
|
192
|
-
let viewportErrorOutlet = null;
|
|
193
|
-
let metadataErrorOutlet = null;
|
|
194
188
|
const resolveMetadataErrorTags = async (error) => {
|
|
195
189
|
if (resolveAppPageSpecialError(error)?.kind !== "http-access-fallback") return null;
|
|
196
190
|
return resolveHttpAccessFallbackMetadata({
|
|
@@ -201,24 +195,19 @@ async function buildPageElements(options) {
|
|
|
201
195
|
routePath: route.pattern
|
|
202
196
|
}).catch(() => null);
|
|
203
197
|
};
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
metadataErrorOutlet,
|
|
218
|
-
viewportErrorOutlet
|
|
219
|
-
].filter((promise) => promise !== null).map((promise) => Promise.resolve(promise));
|
|
220
|
-
const streamingMetadataOutlet = streamingMetadataOutletInputs.length > 0 ? Promise.all(streamingMetadataOutletInputs).then(() => null) : null;
|
|
221
|
-
streamingMetadataOutlet?.catch(() => null);
|
|
198
|
+
const toClientError = (error) => isProduction ? sanitizeErrorForClient(error, "production") : error;
|
|
199
|
+
const resolveHead = cache(() => {
|
|
200
|
+
const preparedHead = prepareAppPageHead(headOptions);
|
|
201
|
+
const outlet = Promise.all([preparedHead.metadata, preparedHead.viewport]).then(() => null, (error) => {
|
|
202
|
+
throw toClientError(error);
|
|
203
|
+
});
|
|
204
|
+
outlet.catch(() => null);
|
|
205
|
+
return {
|
|
206
|
+
metadata: preparedHead.metadata.catch(resolveMetadataErrorTags),
|
|
207
|
+
outlet,
|
|
208
|
+
viewport: preparedHead.viewport.catch((error) => resolveAppPageSpecialError(error)?.kind === "http-access-fallback" ? resolveHttpAccessFallbackViewport(resolveNotFoundFallbackPlanOptions()).catch(() => ({})) : {})
|
|
209
|
+
};
|
|
210
|
+
});
|
|
222
211
|
const pageProps = { params: makeThenableParams(effectiveParams) };
|
|
223
212
|
const pageTreePosition = (sourcePageSegments ?? route.routeSegments ?? []).length;
|
|
224
213
|
const hasPageLoadingBoundary = resolveAppPageLoadingModuleAtOrAbove(route, pageTreePosition) !== null || isSiblingIntercept && resolveAppPageLoadingModuleAtOrAbove({
|
|
@@ -299,7 +288,7 @@ async function buildPageElements(options) {
|
|
|
299
288
|
const LayoutComponent = traceGetLayoutOrPageModule(resolveInterceptLayoutTraceSegment(opts?.interceptBranchSegments, interceptLayoutSegments), () => layoutModule.default);
|
|
300
289
|
if (!LayoutComponent) continue;
|
|
301
290
|
const interceptLayoutParams = resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? interceptLayoutSegments, interceptLayoutSegments, effectiveParams);
|
|
302
|
-
element = createElement(LayoutComponent, { params: makeThenableParams(interceptLayoutParams) }, element);
|
|
291
|
+
element = createElement(LayoutComponent, withUseCacheLayoutMarker(LayoutComponent, { params: makeThenableParams(interceptLayoutParams) }), element);
|
|
303
292
|
}
|
|
304
293
|
}
|
|
305
294
|
return element;
|
|
@@ -319,14 +308,10 @@ async function buildPageElements(options) {
|
|
|
319
308
|
matchedParams: params,
|
|
320
309
|
pageRenderDependency,
|
|
321
310
|
metadataPlacement,
|
|
322
|
-
|
|
311
|
+
resolveHead,
|
|
323
312
|
resolvedMetadataPathname: routePath,
|
|
324
|
-
resolvedViewport,
|
|
325
313
|
scriptNonce: options.scriptNonce,
|
|
326
|
-
streamingMetadata,
|
|
327
|
-
streamingMetadataOutlet,
|
|
328
314
|
streamingMetadataOutletSuspended: streamGeneratedHead,
|
|
329
|
-
streamingMetadataTags,
|
|
330
315
|
renderIdentity,
|
|
331
316
|
routePath,
|
|
332
317
|
semanticPageIdentity,
|
|
@@ -123,22 +123,25 @@ type ProbeAppPageLayoutsOptions = {
|
|
|
123
123
|
/** When provided, enables per-layout static/dynamic classification. */
|
|
124
124
|
classification?: LayoutClassificationOptions | null;
|
|
125
125
|
};
|
|
126
|
-
type ProbeAppPageComponentOptions = {
|
|
127
|
-
awaitAsyncResult: boolean;
|
|
128
|
-
onError: (error: unknown) => Promise<Response | null>;
|
|
129
|
-
probePage: () => unknown;
|
|
130
|
-
runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;
|
|
131
|
-
};
|
|
132
|
-
type ProbeAppPageThrownErrorOptions = {
|
|
133
|
-
probePage: () => unknown;
|
|
134
|
-
runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;
|
|
135
|
-
};
|
|
136
126
|
export declare function resolveAppPageSpecialError(error: unknown): AppPageSpecialError | null;
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the special error that rejected an SSR shell. An error from the RSC
|
|
129
|
+
* render reaches the shell decoded from its Flight digest, so whether
|
|
130
|
+
* generateMetadata() threw it comes from the errors the RSC render threw with
|
|
131
|
+
* that digest. When the page threw one too, the page's decides. An error a
|
|
132
|
+
* client component threw during SSR is the page's, since generateMetadata()
|
|
133
|
+
* runs only in the RSC render.
|
|
134
|
+
*/
|
|
135
|
+
export declare function resolveAppPageShellSpecialError(error: unknown, renderedSpecialErrors: readonly unknown[]): AppPageSpecialError | null;
|
|
136
|
+
/**
|
|
137
|
+
* The response headers stored with a page's special-error entries: a
|
|
138
|
+
* redirect's own `location`, not the response's, which middleware may have
|
|
139
|
+
* replaced for this request.
|
|
140
|
+
*/
|
|
141
|
+
export declare function resolveAppPageSpecialErrorStoredHeaders(specialError: AppPageSpecialError, basePath: string | undefined): Record<string, string> | undefined;
|
|
137
142
|
export declare function buildAppPageSpecialErrorResponse(options: BuildAppPageSpecialErrorResponseOptions): Promise<Response>;
|
|
138
143
|
/** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */
|
|
139
144
|
export declare function probeAppPageLayouts(options: ProbeAppPageLayoutsOptions): Promise<ProbeAppPageLayoutsResult>;
|
|
140
|
-
export declare function probeAppPageComponent(options: ProbeAppPageComponentOptions): Promise<Response | null>;
|
|
141
|
-
export declare function probeAppPageThrownError(options: ProbeAppPageThrownErrorOptions): Promise<unknown>;
|
|
142
145
|
export declare function readAppPageBinaryStream(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer>;
|
|
143
146
|
export declare function bufferAppPageBinaryStream(stream: ReadableStream<Uint8Array>): Promise<ReadableStream<Uint8Array>>;
|
|
144
147
|
export declare function teeAppPageRscStreamForCapture(stream: ReadableStream<Uint8Array>, shouldCapture: boolean): AppPageRscStreamCapture;
|