vinext 1.0.0 → 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/THIRD_PARTY_LICENSES.md +26 -0
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- package/dist/build/lifecycle.js +10 -10
- package/dist/build/pages-client-assets-module.js +6 -1
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender-paths.js +6 -85
- package/dist/build/prerender.d.ts +8 -1
- package/dist/build/prerender.js +167 -46
- package/dist/build/run-prerender.js +4 -3
- package/dist/build/server-entry.d.ts +2 -0
- package/dist/build/server-entry.js +7 -1
- 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/browser-globals.d.ts +4 -0
- package/dist/client/browser-globals.js +5 -0
- package/dist/client/navigation-runtime.d.ts +11 -1
- package/dist/client/navigation-runtime.js +3 -3
- package/dist/config/config-matchers.js +3 -1
- package/dist/config/dotenv.js +14 -3
- 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 +67 -45
- package/dist/index.d.ts +4 -1
- package/dist/index.js +200 -100
- package/dist/init-cloudflare.d.ts +1 -1
- package/dist/init-cloudflare.js +6 -6
- package/dist/init-platform.js +1 -1
- package/dist/init.js +4 -2
- 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/commonjs-syntax.d.ts +16 -0
- package/dist/plugins/commonjs-syntax.js +22 -0
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
- package/dist/plugins/ignore-dynamic-requests.js +54 -3
- package/dist/plugins/import-meta-url.js +6 -6
- package/dist/plugins/og-asset-ownership.d.ts +2 -0
- package/dist/plugins/og-asset-ownership.js +24 -13
- package/dist/plugins/og-assets.d.ts +18 -0
- package/dist/plugins/og-assets.js +50 -8
- package/dist/plugins/og-harfbuzz.js +38 -27
- package/dist/plugins/optimize-imports.js +2 -1
- package/dist/plugins/require-context.d.ts +1 -0
- package/dist/plugins/require-context.js +28 -1
- package/dist/plugins/scan-build-css.d.ts +12 -0
- package/dist/plugins/scan-build-css.js +39 -0
- package/dist/plugins/strip-server-exports.d.ts +2 -0
- package/dist/plugins/strip-server-exports.js +3 -1
- package/dist/plugins/transform-result.d.ts +18 -0
- package/dist/plugins/transform-result.js +23 -2
- package/dist/plugins/typeof-window.d.ts +10 -0
- package/dist/plugins/typeof-window.js +33 -9
- package/dist/routing/app-route-graph.d.ts +0 -1
- package/dist/routing/app-route-graph.js +2 -4
- package/dist/routing/app-route-ids.d.ts +3 -0
- package/dist/routing/app-route-ids.js +6 -0
- 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-bfcache-id.d.ts +1 -0
- package/dist/server/app-bfcache-id.js +7 -1
- package/dist/server/app-bfcache-identity.js +1 -2
- package/dist/server/app-browser-entry.js +15 -9
- 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-hydration.d.ts +1 -1
- package/dist/server/app-browser-hydration.js +2 -2
- 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 +94 -11
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-stream.d.ts +1 -1
- 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 -1
- package/dist/server/app-history-state.js +9 -5
- 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 +65 -44
- 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 -118
- 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-search-params-observation.js +1 -1
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +7 -1
- package/dist/server/app-page-tracing.js +2 -1
- package/dist/server/app-pages-bridge.js +3 -2
- package/dist/server/app-render-abort-error.d.ts +3 -0
- package/dist/server/app-render-abort-error.js +8 -0
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +8 -11
- 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-cache.d.ts +2 -1
- package/dist/server/app-route-handler-cache.js +11 -7
- package/dist/server/app-route-handler-dispatch.js +11 -4
- package/dist/server/app-route-handler-execution.d.ts +9 -1
- package/dist/server/app-route-handler-execution.js +28 -13
- package/dist/server/app-route-handler-policy.js +2 -2
- package/dist/server/app-route-handler-response.d.ts +1 -1
- package/dist/server/app-route-handler-response.js +14 -5
- package/dist/server/app-router-entry.d.ts +2 -1
- package/dist/server/app-router-entry.js +8 -12
- package/dist/server/app-rsc-errors.d.ts +0 -1
- package/dist/server/app-rsc-errors.js +2 -6
- package/dist/server/app-rsc-handler.d.ts +5 -0
- package/dist/server/app-rsc-handler.js +229 -102
- package/dist/server/app-rsc-request-normalization.d.ts +4 -2
- package/dist/server/app-rsc-request-normalization.js +7 -4
- package/dist/server/app-rsc-response-finalizer.js +4 -1
- 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 +37 -20
- package/dist/server/app-server-action-execution.d.ts +2 -1
- 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 +9 -7
- package/dist/server/app-ssr-search-params-gate.js +1 -1
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +35 -16
- package/dist/server/app-worker-stages.d.ts +2 -2
- package/dist/server/app-worker-stages.js +3 -3
- package/dist/server/cache-control.js +3 -11
- package/dist/server/cacheability-request.js +56 -52
- package/dist/server/config-headers.js +3 -1
- package/dist/server/dev-server.js +23 -5
- package/dist/server/headers.d.ts +16 -0
- package/dist/server/headers.js +19 -1
- package/dist/server/http-error-responses.js +1 -0
- package/dist/server/image-optimization.d.ts +16 -0
- package/dist/server/image-optimization.js +26 -6
- package/dist/server/isr-cache.d.ts +2 -0
- package/dist/server/isr-cache.js +8 -3
- package/dist/server/metadata-route-response.js +94 -37
- 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-api-route.js +8 -2
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +73 -22
- package/dist/server/pages-client-assets.d.ts +2 -0
- package/dist/server/pages-page-data.d.ts +6 -1
- package/dist/server/pages-page-data.js +71 -65
- package/dist/server/pages-page-handler.js +50 -15
- package/dist/server/pages-page-response.js +3 -1
- package/dist/server/pages-request-pipeline.d.ts +2 -1
- package/dist/server/pages-request-pipeline.js +20 -5
- package/dist/server/pages-request-stage-entry.js +14 -8
- package/dist/server/prerender-manifest.d.ts +6 -0
- package/dist/server/prerender-manifest.js +1 -1
- package/dist/server/prod-server.d.ts +8 -7
- package/dist/server/prod-server.js +152 -78
- 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/response-stage-cacheability.js +1 -1
- 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/server/worker-revalidation-context.d.ts +2 -1
- package/dist/server/worker-revalidation-context.js +1 -0
- package/dist/server/workers-tracing.d.ts +17 -0
- package/dist/server/workers-tracing.js +48 -8
- 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 +18 -14
- package/dist/shims/cache-request-state.js +33 -21
- package/dist/shims/cache-runtime.d.ts +6 -19
- package/dist/shims/cache-runtime.js +168 -226
- package/dist/shims/cache.d.ts +3 -2
- package/dist/shims/cache.js +8 -5
- package/dist/shims/cacheability-classification.d.ts +8 -1
- package/dist/shims/cacheability-classification.js +2 -2
- package/dist/shims/cdn-cache.d.ts +10 -1
- package/dist/shims/cdn-cache.js +16 -9
- 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/error.d.ts +4 -18
- package/dist/shims/error.js +17 -10
- package/dist/shims/error.react-server.d.ts +4 -6
- package/dist/shims/error.react-server.js +4 -1
- package/dist/shims/fetch-cache.d.ts +6 -0
- package/dist/shims/fetch-cache.js +23 -4
- package/dist/shims/form.js +1 -1
- package/dist/shims/headers.d.ts +19 -69
- package/dist/shims/headers.js +82 -183
- 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/cache-context-accessor.d.ts +16 -0
- package/dist/shims/internal/cache-context-accessor.js +15 -0
- package/dist/shims/internal/headers-state.d.ts +73 -0
- package/dist/shims/internal/headers-state.js +157 -0
- 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 +16 -6
- package/dist/shims/request-context.d.ts +9 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/root-params.js +1 -1
- package/dist/shims/server.js +52 -2
- package/dist/shims/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/encode-cache-tag.d.ts +1 -0
- package/dist/utils/encode-cache-tag.js +11 -1
- 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/dist/utils/vite-cli-invocation.js +8 -1
- package/package.json +8 -4
- package/dist/server/metadata-route-cache-policy.d.ts +0 -5
- package/dist/server/metadata-route-cache-policy.js +0 -6
|
@@ -23,6 +23,13 @@ type AppPageRequestCacheLife = {
|
|
|
23
23
|
stale?: number;
|
|
24
24
|
};
|
|
25
25
|
type AppPageRenderableElement = ReactNode | Readonly<Record<string, ReactNode>>;
|
|
26
|
+
type AppPageSpecialErrorRenderOptions = {
|
|
27
|
+
/**
|
|
28
|
+
* The document may be stored in place of the page's, so like a cache
|
|
29
|
+
* candidate's render it must not carry the request's query.
|
|
30
|
+
*/
|
|
31
|
+
isCacheCandidate?: boolean;
|
|
32
|
+
};
|
|
26
33
|
type PreparedAppPageElement = {
|
|
27
34
|
element: AppPageRenderableElement;
|
|
28
35
|
response?: never;
|
|
@@ -63,7 +70,6 @@ type RenderAppPageLifecycleOptionsBase = {
|
|
|
63
70
|
getDraftModeCookieHeader: () => string | null | undefined;
|
|
64
71
|
handlerStart: number;
|
|
65
72
|
hasCustomGlobalError?: boolean;
|
|
66
|
-
hasLoadingBoundary: boolean;
|
|
67
73
|
dynamicStaleTimeSeconds?: number;
|
|
68
74
|
isDynamicError: boolean;
|
|
69
75
|
isDraftMode: boolean;
|
|
@@ -83,9 +89,12 @@ type RenderAppPageLifecycleOptionsBase = {
|
|
|
83
89
|
isCacheCandidate?: boolean;
|
|
84
90
|
isProgressiveActionRender?: boolean;
|
|
85
91
|
isPrerender?: boolean;
|
|
92
|
+
/** PPR routes send every RSC response as a 200. */
|
|
93
|
+
isRoutePPREnabled?: boolean;
|
|
86
94
|
isSpeculativePrerender?: boolean;
|
|
95
|
+
/** Wait for the whole document before its first byte, as a prerender does. */
|
|
96
|
+
renderWholeDocument?: boolean;
|
|
87
97
|
isProduction: boolean;
|
|
88
|
-
probePageBeforeRender?: boolean;
|
|
89
98
|
omitPendingDynamicCacheState?: boolean;
|
|
90
99
|
isRscRequest: boolean;
|
|
91
100
|
traceOperation?: "prerender" | "render";
|
|
@@ -107,13 +116,12 @@ type RenderAppPageLifecycleOptionsBase = {
|
|
|
107
116
|
rootParams?: RootParams;
|
|
108
117
|
peekRenderObservationState?: () => AppPageRenderObservationState;
|
|
109
118
|
probeLayoutAt: (layoutIndex: number) => unknown;
|
|
110
|
-
probePage: () => unknown;
|
|
111
119
|
expireSeconds?: number;
|
|
112
120
|
formState?: ReactFormState | null;
|
|
113
121
|
revalidateSeconds: number | null;
|
|
114
122
|
renderErrorBoundaryResponse: (error: unknown, errorOrigin: "rsc" | "ssr") => Promise<Response | null>;
|
|
115
123
|
renderLayoutSpecialError: (specialError: AppPageSpecialError, layoutIndex: number) => Promise<Response>;
|
|
116
|
-
renderPageSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;
|
|
124
|
+
renderPageSpecialError: (specialError: AppPageSpecialError, renderOptions?: AppPageSpecialErrorRenderOptions) => Promise<Response>;
|
|
117
125
|
renderToReadableStream: (element: ReactNode | AppOutgoingElements, options: {
|
|
118
126
|
onError: AppPageBoundaryOnError;
|
|
119
127
|
signal?: AbortSignal;
|
|
@@ -150,6 +158,6 @@ type RenderAppPageLifecycleOptions = RenderAppPageLifecycleOptionsBase & ({
|
|
|
150
158
|
* its response policy, such as error boundaries and special errors, get the
|
|
151
159
|
* same header as the normal render.
|
|
152
160
|
*/
|
|
153
|
-
export declare function applyIneligibleRouteCachePolicy(response: Response, options: Pick<RenderAppPageLifecycleOptions, "isDraftMode" | "isDynamicError" | "isForceDynamic" | "isForceStatic" | "isProduction" | "isProgressiveActionRender" | "isRscRequest" | "isStaticEligible" | "middlewareContext" | "peekDynamicUsage" | "revalidateSeconds" | "scriptNonce"
|
|
161
|
+
export declare function applyIneligibleRouteCachePolicy(response: Response, options: Pick<RenderAppPageLifecycleOptions, "dynamicStaleTimeSeconds" | "isDraftMode" | "isDynamicError" | "isForceDynamic" | "isForceStatic" | "isProduction" | "isProgressiveActionRender" | "isRscRequest" | "isStaticEligible" | "middlewareContext" | "peekDynamicUsage" | "revalidateSeconds" | "scriptNonce">, probeCacheLife?: AppPageRequestCacheLife | null): Response;
|
|
154
162
|
export declare function renderAppPageLifecycle(options: RenderAppPageLifecycleOptions): Promise<Response>;
|
|
155
163
|
//#endregion
|
|
@@ -1,31 +1,36 @@
|
|
|
1
1
|
import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
|
|
2
2
|
import { bindRequestContext } from "../shims/unified-request-context.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
|
+
import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_RSC_COMPLETION_METADATA_HEADER } from "./headers.js";
|
|
4
5
|
import { internalServerErrorResponse } from "./http-error-responses.js";
|
|
5
6
|
import { isRouteCacheabilityEvaluation, recordRouteCacheabilityClientTraceMetadataMarker } from "../shims/cacheability-classification.js";
|
|
6
7
|
import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders, isCdnResponsePolicyHeader } from "./cache-control.js";
|
|
7
|
-
import { createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion } from "./artifact-compatibility.js";
|
|
8
|
-
import { AppElementsWire, isAppElementsRecord } from "./app-elements-wire.js";
|
|
9
|
-
import "./app-elements.js";
|
|
10
8
|
import { resolveClientStaleTimeSeconds } from "../utils/cache-control-metadata.js";
|
|
11
|
-
import { isRenderDynamicLatched,
|
|
9
|
+
import { isRenderDynamicLatched, markDynamicUsage } from "../shims/internal/headers-state.js";
|
|
10
|
+
import { peekDynamicUsage, runWithDetachedDynamicUsage } from "../shims/headers.js";
|
|
12
11
|
import { runWithFetchDedupe } from "../shims/fetch-cache.js";
|
|
12
|
+
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
13
13
|
import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
|
|
14
|
+
import { createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion } from "./artifact-compatibility.js";
|
|
15
|
+
import { AppElementsWire, isAppElementsRecord } from "./app-elements-wire.js";
|
|
16
|
+
import "./app-elements.js";
|
|
14
17
|
import { isBailoutToCSRError } from "../shims/navigation-errors.js";
|
|
15
18
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
+
import { applyPrerenderCacheLifeHeader, applyPrerenderCacheTagsHeader } from "./prerender-cache-life-header.js";
|
|
20
|
+
import { copyLinkHeaderProvenance, getFrameworkLinkHeader } from "./app-response-header-provenance.js";
|
|
21
|
+
import { applyClientStaleTimeHeader, applyEdgeRuntimeHeader, buildAppPageHtmlResponse, buildAppPageRscResponse, resolveAppPageHtmlResponsePolicy, resolveAppPageRscResponsePolicy, resolveUncacheableCacheControl } from "./app-page-response.js";
|
|
22
|
+
import { buildAppPageFontLinkHeader, readAppPageBinaryStream, resolveAppPageShellSpecialError, resolveAppPageSpecialError, resolveAppPageSpecialErrorStoredHeaders, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
|
|
19
23
|
import { probeAppPageBeforeRender } from "./app-page-probe.js";
|
|
20
24
|
import { hasDigest } from "./app-rsc-errors.js";
|
|
21
25
|
import { recordAppPageRenderError, traceAppPageRender } from "./app-page-tracing.js";
|
|
22
26
|
import { traceResponseStartWithCompletion } from "./response-start-tracing.js";
|
|
23
27
|
import { DEFAULT_CACHE_VARIANT_BUDGET, buildCacheVariantWithRouteBudget, buildRenderObservation, buildRenderRequestApiObservations, createStaticLayoutArtifactReuseDecision } from "./cache-proof.js";
|
|
24
28
|
import { createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope } from "./app-page-render-observation.js";
|
|
29
|
+
import { buildAppPageLinkHeader, createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery } from "./app-page-stream.js";
|
|
30
|
+
import { createAppPageRscRenderStatusResolver } from "./app-page-rsc-render-status.js";
|
|
25
31
|
import { finalizeAppPageCacheabilityEvaluationResponse, finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse } from "./app-page-cache-finalizer.js";
|
|
26
32
|
import { createStaticLayoutClientReuseArtifactCompatibility, createStaticLayoutClientReusePayloadHash, createStaticLayoutClientReuseRouteId } from "./static-layout-client-reuse-proof.js";
|
|
27
33
|
import { appendRscCompletionMetadata } from "./rsc-completion-metadata.js";
|
|
28
|
-
import { buildAppPageLinkHeader, createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery } from "./app-page-stream.js";
|
|
29
34
|
import { getStaticLayoutObservationSkipRejection } from "./app-layout-param-observation.js";
|
|
30
35
|
import { createClientReuseSkipTransportPlan, crossCheckClientReuseManifestEntryWithCache } from "./skip-cache-proof.js";
|
|
31
36
|
//#region src/server/app-page-render.ts
|
|
@@ -69,15 +74,32 @@ function applyRequestCacheLife(options) {
|
|
|
69
74
|
* its response policy, such as error boundaries and special errors, get the
|
|
70
75
|
* same header as the normal render.
|
|
71
76
|
*/
|
|
72
|
-
function applyIneligibleRouteCachePolicy(response, options) {
|
|
77
|
+
function applyIneligibleRouteCachePolicy(response, options, probeCacheLife = null) {
|
|
73
78
|
const cacheControl = resolveEarlyResponseCacheControl(options);
|
|
74
|
-
|
|
79
|
+
const isRscRedirect = options.isRscRequest && response.headers.has("X-Vinext-Rsc-Redirect");
|
|
80
|
+
if (!cacheControl) {
|
|
81
|
+
const staleTimeSeconds = isRscRedirect ? resolveClientStaleTimeSeconds(probeCacheLife) : void 0;
|
|
82
|
+
if (staleTimeSeconds === void 0) return response;
|
|
83
|
+
const stamped = cloneForStamping(response);
|
|
84
|
+
applyClientStaleTimeHeader(stamped.headers, staleTimeSeconds);
|
|
85
|
+
return stamped;
|
|
86
|
+
}
|
|
87
|
+
const dynamicStaleTimeSeconds = isRscRedirect ? options.dynamicStaleTimeSeconds ?? resolveConfiguredDynamicStaleTimeSeconds() : void 0;
|
|
75
88
|
const middlewarePolicy = [...options.middlewareContext.headers ?? []].filter(([name, value]) => isCdnResponsePolicyHeader(name) && response.headers.get(name) === value);
|
|
76
|
-
|
|
89
|
+
const keepsMiddlewareCacheControl = middlewarePolicy.some(([name]) => name === "cache-control");
|
|
90
|
+
if (keepsMiddlewareCacheControl && dynamicStaleTimeSeconds === void 0) return response;
|
|
91
|
+
const stamped = cloneForStamping(response);
|
|
92
|
+
if (!keepsMiddlewareCacheControl) {
|
|
93
|
+
applyCdnResponseHeaders(stamped.headers, { cacheControl });
|
|
94
|
+
for (const [name, value] of middlewarePolicy) stamped.headers.set(name, value);
|
|
95
|
+
}
|
|
96
|
+
if (dynamicStaleTimeSeconds !== void 0) stamped.headers.set(VINEXT_DYNAMIC_STALE_TIME_HEADER, String(dynamicStaleTimeSeconds));
|
|
97
|
+
return stamped;
|
|
98
|
+
}
|
|
99
|
+
/** Some early responses have immutable headers, so stamp a copy. */
|
|
100
|
+
function cloneForStamping(response) {
|
|
77
101
|
const stamped = preserveFullyBufferedBodyMetadata(response, new Response(response.body, response));
|
|
78
102
|
copyLinkHeaderProvenance(response.headers, stamped.headers);
|
|
79
|
-
applyCdnResponseHeaders(stamped.headers, { cacheControl });
|
|
80
|
-
for (const [name, value] of middlewarePolicy) stamped.headers.set(name, value);
|
|
81
103
|
return stamped;
|
|
82
104
|
}
|
|
83
105
|
/** The known-dynamic branches of the RSC and HTML response policies, in their order. */
|
|
@@ -367,32 +389,26 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
367
389
|
}
|
|
368
390
|
return dynamicUsageObserved;
|
|
369
391
|
};
|
|
370
|
-
const
|
|
371
|
-
const probePageBeforeRender = options.isRscRequest || configuredProbePageBeforeRender && !(options.peekDynamicUsage?.() ?? false);
|
|
372
|
-
const preRenderResult = await probeAppPageBeforeRender({
|
|
373
|
-
hasLoadingBoundary: options.hasLoadingBoundary,
|
|
374
|
-
probePageBeforeRender,
|
|
392
|
+
const probeOutcome = await runWithDetachedDynamicUsage(() => probeAppPageBeforeRender({
|
|
375
393
|
skipProbes: options.pprFallbackShellSignal !== void 0,
|
|
376
394
|
layoutCount: options.layoutCount,
|
|
377
395
|
probeLayoutAt(layoutIndex) {
|
|
378
396
|
return options.probeLayoutAt(layoutIndex);
|
|
379
397
|
},
|
|
380
|
-
probePage() {
|
|
381
|
-
return options.probePage();
|
|
382
|
-
},
|
|
383
398
|
renderLayoutSpecialError(specialError, layoutIndex) {
|
|
384
399
|
return options.renderLayoutSpecialError(specialError, layoutIndex);
|
|
385
400
|
},
|
|
386
|
-
renderPageSpecialError(specialError) {
|
|
387
|
-
return options.renderPageSpecialError(specialError);
|
|
388
|
-
},
|
|
389
401
|
resolveSpecialError: resolveAppPageSpecialError,
|
|
390
402
|
runWithSuppressedHookWarning(probe) {
|
|
391
403
|
return options.runWithSuppressedHookWarning(probe);
|
|
392
404
|
},
|
|
393
405
|
classification: options.classification
|
|
394
|
-
});
|
|
395
|
-
|
|
406
|
+
}));
|
|
407
|
+
const preRenderResult = probeOutcome.result;
|
|
408
|
+
if (preRenderResult.response) {
|
|
409
|
+
if (probeOutcome.dynamicDetected) markDynamicUsage();
|
|
410
|
+
return applyIneligibleRouteCachePolicy(preRenderResult.response, options, probeOutcome.cacheLife);
|
|
411
|
+
}
|
|
396
412
|
const layoutFlags = preRenderResult.layoutFlags;
|
|
397
413
|
const artifactCompatibility = createAppPageArtifactCompatibility(options.element, options.routePattern);
|
|
398
414
|
const rootBoundaryId = artifactCompatibility?.rootBoundaryId ?? null;
|
|
@@ -457,7 +473,7 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
457
473
|
if (options.pprFallbackShellSignal) pprFallbackShellRsc = new Uint8Array(await readAppPageBinaryStream(rscStream));
|
|
458
474
|
let revalidateSeconds = options.revalidateSeconds;
|
|
459
475
|
let expireSeconds = options.expireSeconds;
|
|
460
|
-
const shouldWaitForAllReady = options.isPrerender === true && options.isSpeculativePrerender !== true;
|
|
476
|
+
const shouldWaitForAllReady = options.isPrerender === true && options.isSpeculativePrerender !== true || options.renderWholeDocument === true;
|
|
461
477
|
const shouldReadRequestCacheLifeForPrerender = options.isPrerender === true;
|
|
462
478
|
const mayResolveCacheLifeAfterHeaders = options.isProgressiveActionRender !== true && (revalidateSeconds === null || revalidateSeconds > 0) && !options.isDraftMode && !options.isForceDynamic && !shouldBypassRscCache;
|
|
463
479
|
const shouldCaptureRscForCacheMetadata = (options.isProduction || options.isPrerender === true) && mayResolveCacheLifeAfterHeaders && options.isStaticEligible;
|
|
@@ -473,6 +489,16 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
473
489
|
const capturedRscDataRef = { value: null };
|
|
474
490
|
if (rscCapture.sideStream && options.isRscRequest) capturedRscDataRef.value = readAppPageBinaryStream(rscCapture.sideStream);
|
|
475
491
|
if (options.isRscRequest) {
|
|
492
|
+
const resolveRscRenderStatus = options.isProduction && shouldCaptureRscForCacheMetadata && capturedRscDataRef.value !== null && options.isPrerender !== true && options.isRoutePPREnabled !== true ? createAppPageRscRenderStatusResolver({
|
|
493
|
+
basePath: options.basePath,
|
|
494
|
+
capturedRscData: capturedRscDataRef.value,
|
|
495
|
+
getCapturedSpecialError: rscErrorTracker.getCapturedSpecialError,
|
|
496
|
+
getCapturedSpecialErrors: rscErrorTracker.getCapturedSpecialErrors,
|
|
497
|
+
isForceStatic: options.isForceStatic,
|
|
498
|
+
loadSsrHandler: options.loadSsrHandler,
|
|
499
|
+
navigationContext: options.getNavigationContext(),
|
|
500
|
+
rootParams: options.rootParams
|
|
501
|
+
}) : void 0;
|
|
476
502
|
let requestCacheLifeForPrerender = null;
|
|
477
503
|
if (shouldWaitForAllReady) await settleCapturedRscRenderForCacheMetadata(capturedRscDataRef.value);
|
|
478
504
|
if (shouldReadRequestCacheLifeForPrerender) {
|
|
@@ -565,6 +591,7 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
565
591
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
566
592
|
omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
|
|
567
593
|
renderMode: options.renderMode,
|
|
594
|
+
resolveRscRenderStatus,
|
|
568
595
|
preserveClientResponseHeaders: rscResponsePolicy.cacheState !== "MISS",
|
|
569
596
|
expireSeconds,
|
|
570
597
|
isStaticEligible: options.isStaticEligible,
|
|
@@ -590,6 +617,145 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
590
617
|
let requestCacheLifeForPrerender = null;
|
|
591
618
|
let dynamicUsedDuringHtmlRender = false;
|
|
592
619
|
let renderEnd;
|
|
620
|
+
let shellSpecialError = null;
|
|
621
|
+
const resolveHtmlCacheWrite = (dynamicUsedDuringRender) => {
|
|
622
|
+
const htmlResponsePolicy = resolveAppPageHtmlResponsePolicy({
|
|
623
|
+
dynamicUsedDuringRender,
|
|
624
|
+
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
625
|
+
hasScriptNonce: Boolean(options.scriptNonce),
|
|
626
|
+
isDraftMode: options.isDraftMode,
|
|
627
|
+
isDynamicError: options.isDynamicError,
|
|
628
|
+
isForceDynamic: options.isForceDynamic,
|
|
629
|
+
isForceStatic: options.isForceStatic,
|
|
630
|
+
isProduction: options.isProduction,
|
|
631
|
+
isStaticEligible: options.isStaticEligible,
|
|
632
|
+
expireSeconds,
|
|
633
|
+
revalidateSeconds
|
|
634
|
+
});
|
|
635
|
+
const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && !options.isEdgeRuntime && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
|
|
636
|
+
return {
|
|
637
|
+
htmlResponsePolicy,
|
|
638
|
+
shouldWriteHtmlCache: htmlResponsePolicy.shouldWriteToCache || shouldSpeculativelyWriteCache
|
|
639
|
+
};
|
|
640
|
+
};
|
|
641
|
+
const finalizeHtmlCacheWrite = (response, write) => finalizeAppPageHtmlCacheResponse(response, {
|
|
642
|
+
bypassInterceptionContextCache: options.bypassInterceptionContextCache,
|
|
643
|
+
capturedDynamicUsageBeforeContextCleanup: write.capturedDynamicUsageBeforeContextCleanup,
|
|
644
|
+
capturedRscDataPromise: capturedRscDataRef.value,
|
|
645
|
+
cleanPathname: options.cleanPathname,
|
|
646
|
+
clientTraceMetadataMarker,
|
|
647
|
+
consumeDynamicUsage: consumeRenderDynamicUsage,
|
|
648
|
+
consumeRenderObservationState,
|
|
649
|
+
createHtmlRenderObservation(input) {
|
|
650
|
+
return createAppPageRenderObservation({
|
|
651
|
+
boundaryOutcome: { kind: "success" },
|
|
652
|
+
cacheability: "public",
|
|
653
|
+
cacheTags: input.cacheTags,
|
|
654
|
+
cleanPathname: options.cleanPathname,
|
|
655
|
+
completeness: "complete",
|
|
656
|
+
output: htmlOutputScope,
|
|
657
|
+
params: options.navigationParams,
|
|
658
|
+
state: input.state
|
|
659
|
+
});
|
|
660
|
+
},
|
|
661
|
+
createRscRenderObservation(input) {
|
|
662
|
+
return createAppPageRenderObservation({
|
|
663
|
+
boundaryOutcome: { kind: "success" },
|
|
664
|
+
cacheability: "public",
|
|
665
|
+
cacheTags: input.cacheTags,
|
|
666
|
+
cleanPathname: options.cleanPathname,
|
|
667
|
+
completeness: "complete",
|
|
668
|
+
output: rscOutputScope,
|
|
669
|
+
params: options.navigationParams,
|
|
670
|
+
state: input.state
|
|
671
|
+
});
|
|
672
|
+
},
|
|
673
|
+
getPageTags() {
|
|
674
|
+
return options.getPageTags();
|
|
675
|
+
},
|
|
676
|
+
getRequestCacheLife() {
|
|
677
|
+
return readRequestCacheLifeForCachePolicy(options);
|
|
678
|
+
},
|
|
679
|
+
headers: write.headers,
|
|
680
|
+
isrDebug: options.isrDebug,
|
|
681
|
+
isrHtmlKey: options.isrHtmlKey,
|
|
682
|
+
isrRscKey: options.isrRscKey,
|
|
683
|
+
isrSet: options.isrSet,
|
|
684
|
+
interceptionContext: options.interceptionContext,
|
|
685
|
+
interceptionId: options.interceptionId,
|
|
686
|
+
omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
|
|
687
|
+
preserveClientResponseHeaders: !write.htmlResponsePolicy.shouldWriteToCache,
|
|
688
|
+
expireSeconds,
|
|
689
|
+
isStaticEligible: options.isStaticEligible,
|
|
690
|
+
revalidateSeconds: resolveAppPageCacheWriteRevalidateSeconds({
|
|
691
|
+
isDynamicError: options.isDynamicError,
|
|
692
|
+
isForceStatic: options.isForceStatic,
|
|
693
|
+
isStaticEligible: options.isStaticEligible,
|
|
694
|
+
revalidateSeconds
|
|
695
|
+
}),
|
|
696
|
+
linkHeader: write.linkHeader,
|
|
697
|
+
status: write.status,
|
|
698
|
+
waitUntil(cachePromise) {
|
|
699
|
+
options.waitUntil?.(cachePromise);
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
const mayStoreShellSpecialError = () => options.isProduction && shouldCaptureRscForCacheMetadata && options.isPrerender !== true && capturedRscDataRef.value !== null && resolveEarlyResponseCacheControl(options) === null;
|
|
703
|
+
const mayPrerenderShellSpecialError = () => options.isPrerender === true && options.isSpeculativePrerender !== true && options.pprFallbackShellSignal === void 0 && shouldCaptureRscForCacheMetadata && capturedRscDataRef.value !== null && resolveEarlyResponseCacheControl(options) === null;
|
|
704
|
+
const readPrerenderCacheMetadata = () => ({
|
|
705
|
+
cacheTags: options.getPageTags(),
|
|
706
|
+
requestCacheLife: readRequestCacheLifeForPrerender(options)
|
|
707
|
+
});
|
|
708
|
+
let prerenderedSpecialError = null;
|
|
709
|
+
const finalizePrerenderedShellSpecialErrorResponse = async (response, specialError, prerendered) => {
|
|
710
|
+
if (response.status !== specialError.statusCode) return applyIneligibleRouteCachePolicy(response, options);
|
|
711
|
+
const body = await response.arrayBuffer();
|
|
712
|
+
const { cacheTags, requestCacheLife } = prerendered.redirectMetadata ?? readPrerenderCacheMetadata();
|
|
713
|
+
({expireSeconds, revalidateSeconds} = applyRequestCacheLife({
|
|
714
|
+
expireSeconds,
|
|
715
|
+
requestCacheLife,
|
|
716
|
+
revalidateSeconds
|
|
717
|
+
}));
|
|
718
|
+
const { htmlResponsePolicy } = resolveHtmlCacheWrite(prerendered.dynamicUsed || consumeRenderDynamicUsage());
|
|
719
|
+
const headers = new Headers(response.headers);
|
|
720
|
+
if (htmlResponsePolicy.cacheControl && !headers.has("cache-control")) headers.set("Cache-Control", htmlResponsePolicy.cacheControl);
|
|
721
|
+
applyPrerenderCacheLifeHeader(headers, requestCacheLife);
|
|
722
|
+
applyPrerenderCacheTagsHeader(headers, cacheTags);
|
|
723
|
+
getRequestExecutionContext()?.recordPrerenderSpecialError?.({
|
|
724
|
+
headers: resolveAppPageSpecialErrorStoredHeaders(specialError, options.basePath) ?? {},
|
|
725
|
+
status: response.status
|
|
726
|
+
});
|
|
727
|
+
const prerenderResponse = new Response(body, {
|
|
728
|
+
headers,
|
|
729
|
+
status: response.status,
|
|
730
|
+
statusText: response.statusText
|
|
731
|
+
});
|
|
732
|
+
copyLinkHeaderProvenance(response.headers, prerenderResponse.headers);
|
|
733
|
+
return prerenderResponse;
|
|
734
|
+
};
|
|
735
|
+
const finalizeShellSpecialErrorResponse = (response, specialError) => {
|
|
736
|
+
if (response.status !== specialError.statusCode) return applyIneligibleRouteCachePolicy(response, options);
|
|
737
|
+
const dynamicUsedDuringRender = consumeRenderDynamicUsage();
|
|
738
|
+
const { htmlResponsePolicy, shouldWriteHtmlCache } = resolveHtmlCacheWrite(dynamicUsedDuringRender);
|
|
739
|
+
const headers = new Headers(response.headers);
|
|
740
|
+
if (htmlResponsePolicy.cacheControl && !headers.has("cache-control")) headers.set("Cache-Control", htmlResponsePolicy.cacheControl);
|
|
741
|
+
if (htmlResponsePolicy.cacheState) setCacheStateHeaders(headers, htmlResponsePolicy.cacheState);
|
|
742
|
+
const policyResponse = new Response(response.body, {
|
|
743
|
+
headers,
|
|
744
|
+
status: response.status,
|
|
745
|
+
statusText: response.statusText
|
|
746
|
+
});
|
|
747
|
+
copyLinkHeaderProvenance(response.headers, policyResponse.headers);
|
|
748
|
+
if (!shouldWriteHtmlCache) return policyResponse;
|
|
749
|
+
const clientResponse = finalizeHtmlCacheWrite(policyResponse, {
|
|
750
|
+
capturedDynamicUsageBeforeContextCleanup: () => dynamicUsedDuringRender,
|
|
751
|
+
headers: resolveAppPageSpecialErrorStoredHeaders(specialError, options.basePath),
|
|
752
|
+
htmlResponsePolicy,
|
|
753
|
+
linkHeader: getFrameworkLinkHeader(response.headers),
|
|
754
|
+
status: response.status
|
|
755
|
+
});
|
|
756
|
+
copyLinkHeaderProvenance(response.headers, clientResponse.headers);
|
|
757
|
+
return clientResponse;
|
|
758
|
+
};
|
|
593
759
|
const htmlRender = await renderAppPageHtmlStreamWithRecovery({
|
|
594
760
|
onShellRendered() {
|
|
595
761
|
if (!options.isProduction) renderEnd = performance.now();
|
|
@@ -656,30 +822,34 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
656
822
|
isStaticGeneration: options.isPrerender === true,
|
|
657
823
|
isForceStatic: options.isForceStatic,
|
|
658
824
|
isCacheCandidate: isCacheCandidateHtmlRender,
|
|
659
|
-
onSsrError: createAppPageSsrErrorHandler(onSsrError, rscErrorTracker.isCapturedError)
|
|
825
|
+
onSsrError: createAppPageSsrErrorHandler(onSsrError, rscErrorTracker.isCapturedError),
|
|
826
|
+
mirrorNextFlight: () => rscErrorTracker.getCapturedSpecialError() !== null
|
|
660
827
|
});
|
|
661
828
|
},
|
|
662
|
-
renderSpecialErrorResponse(specialError) {
|
|
663
|
-
|
|
829
|
+
async renderSpecialErrorResponse(specialError) {
|
|
830
|
+
shellSpecialError = specialError;
|
|
831
|
+
const mayPrerender = mayPrerenderShellSpecialError();
|
|
832
|
+
if (mayStoreShellSpecialError() || mayPrerender) await settleCapturedRscRenderForCacheMetadata(capturedRscDataRef.value, peekRenderDynamicUsage);
|
|
833
|
+
if (mayPrerender) prerenderedSpecialError = {
|
|
834
|
+
dynamicUsed: consumeRenderDynamicUsage(),
|
|
835
|
+
redirectMetadata: specialError.kind === "redirect" ? readPrerenderCacheMetadata() : null
|
|
836
|
+
};
|
|
837
|
+
return options.renderPageSpecialError(specialError, { isCacheCandidate: isCacheCandidateHtmlRender });
|
|
664
838
|
},
|
|
665
|
-
resolveSpecialError
|
|
839
|
+
resolveSpecialError(error) {
|
|
840
|
+
return resolveAppPageShellSpecialError(error, rscErrorTracker.getCapturedSpecialErrors(error));
|
|
841
|
+
}
|
|
666
842
|
});
|
|
667
843
|
options.onRenderComplete?.(htmlRender.renderComplete);
|
|
668
|
-
if (htmlRender.response)
|
|
844
|
+
if (htmlRender.response) {
|
|
845
|
+
if (shellSpecialError && options.isProduction && options.isPrerender !== true && resolveEarlyResponseCacheControl(options) === null) return finalizeShellSpecialErrorResponse(htmlRender.response, shellSpecialError);
|
|
846
|
+
if (shellSpecialError && prerenderedSpecialError) return finalizePrerenderedShellSpecialErrorResponse(htmlRender.response, shellSpecialError, prerenderedSpecialError);
|
|
847
|
+
return applyIneligibleRouteCachePolicy(htmlRender.response, options);
|
|
848
|
+
}
|
|
669
849
|
let htmlStream = htmlRender.htmlStream;
|
|
670
850
|
if (!htmlStream) throw new Error("[vinext] Expected an HTML stream when no fallback response was returned");
|
|
671
851
|
const linkHeader = buildAppPageLinkHeader(htmlRender.linkHeader, fontLinkHeader, options.reactMaxHeadersLength);
|
|
672
852
|
if (options.isPrerender === true) await htmlRender.metadataReady;
|
|
673
|
-
if (options.hasLoadingBoundary || !probePageBeforeRender) {
|
|
674
|
-
const captured = rscErrorTracker.getCapturedSpecialError();
|
|
675
|
-
if (captured) {
|
|
676
|
-
const specialError = resolveAppPageSpecialError(captured);
|
|
677
|
-
if (specialError) {
|
|
678
|
-
htmlStream.cancel().catch(() => {});
|
|
679
|
-
return applyIneligibleRouteCachePolicy(await options.renderPageSpecialError(specialError), options);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
853
|
let dynamicUsedDuringRender = consumeRenderDynamicUsage();
|
|
684
854
|
dynamicUsedDuringHtmlRender = dynamicUsedDuringRender;
|
|
685
855
|
const stopSpeculativeMetadataWaitOnDynamicUsage = options.isSpeculativePrerender === true && shouldReadRequestCacheLifeForPrerender ? () => {
|
|
@@ -709,19 +879,7 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
709
879
|
dynamicUsedDuringHtmlRender = dynamicUsedBeforeContextCleanup;
|
|
710
880
|
options.clearRequestContext();
|
|
711
881
|
});
|
|
712
|
-
const htmlResponsePolicy =
|
|
713
|
-
dynamicUsedDuringRender,
|
|
714
|
-
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
715
|
-
hasScriptNonce: Boolean(options.scriptNonce),
|
|
716
|
-
isDraftMode: options.isDraftMode,
|
|
717
|
-
isDynamicError: options.isDynamicError,
|
|
718
|
-
isForceDynamic: options.isForceDynamic,
|
|
719
|
-
isForceStatic: options.isForceStatic,
|
|
720
|
-
isProduction: options.isProduction,
|
|
721
|
-
isStaticEligible: options.isStaticEligible,
|
|
722
|
-
expireSeconds,
|
|
723
|
-
revalidateSeconds
|
|
724
|
-
});
|
|
882
|
+
const { htmlResponsePolicy, shouldWriteHtmlCache } = resolveHtmlCacheWrite(dynamicUsedDuringRender);
|
|
725
883
|
const htmlResponseTiming = buildResponseTiming({
|
|
726
884
|
compileEnd,
|
|
727
885
|
handlerStart: options.handlerStart,
|
|
@@ -746,8 +904,7 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
746
904
|
applyCdnResponseHeaders(response.headers, { cacheControl: NEVER_CACHE_CONTROL });
|
|
747
905
|
return response;
|
|
748
906
|
}
|
|
749
|
-
|
|
750
|
-
if (htmlResponsePolicy.shouldWriteToCache || shouldSpeculativelyWriteCache) {
|
|
907
|
+
if (shouldWriteHtmlCache) {
|
|
751
908
|
const isrResponse = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
752
909
|
cacheTags: options.isPrerender === true ? options.getPageTags() : void 0,
|
|
753
910
|
draftCookie,
|
|
@@ -759,66 +916,10 @@ async function renderAppPageLifecycleImpl(options, renderSpan) {
|
|
|
759
916
|
timing: htmlResponseTiming
|
|
760
917
|
});
|
|
761
918
|
if (options.isPrerender === true) return isrResponse;
|
|
762
|
-
return
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
},
|
|
767
|
-
capturedRscDataPromise: capturedRscDataRef.value,
|
|
768
|
-
cleanPathname: options.cleanPathname,
|
|
769
|
-
clientTraceMetadataMarker,
|
|
770
|
-
consumeDynamicUsage: consumeRenderDynamicUsage,
|
|
771
|
-
consumeRenderObservationState,
|
|
772
|
-
createHtmlRenderObservation(input) {
|
|
773
|
-
return createAppPageRenderObservation({
|
|
774
|
-
boundaryOutcome: { kind: "success" },
|
|
775
|
-
cacheability: "public",
|
|
776
|
-
cacheTags: input.cacheTags,
|
|
777
|
-
cleanPathname: options.cleanPathname,
|
|
778
|
-
completeness: "complete",
|
|
779
|
-
output: htmlOutputScope,
|
|
780
|
-
params: options.navigationParams,
|
|
781
|
-
state: input.state
|
|
782
|
-
});
|
|
783
|
-
},
|
|
784
|
-
createRscRenderObservation(input) {
|
|
785
|
-
return createAppPageRenderObservation({
|
|
786
|
-
boundaryOutcome: { kind: "success" },
|
|
787
|
-
cacheability: "public",
|
|
788
|
-
cacheTags: input.cacheTags,
|
|
789
|
-
cleanPathname: options.cleanPathname,
|
|
790
|
-
completeness: "complete",
|
|
791
|
-
output: rscOutputScope,
|
|
792
|
-
params: options.navigationParams,
|
|
793
|
-
state: input.state
|
|
794
|
-
});
|
|
795
|
-
},
|
|
796
|
-
getPageTags() {
|
|
797
|
-
return options.getPageTags();
|
|
798
|
-
},
|
|
799
|
-
getRequestCacheLife() {
|
|
800
|
-
return readRequestCacheLifeForCachePolicy(options);
|
|
801
|
-
},
|
|
802
|
-
isrDebug: options.isrDebug,
|
|
803
|
-
isrHtmlKey: options.isrHtmlKey,
|
|
804
|
-
isrRscKey: options.isrRscKey,
|
|
805
|
-
isrSet: options.isrSet,
|
|
806
|
-
interceptionContext: options.interceptionContext,
|
|
807
|
-
interceptionId: options.interceptionId,
|
|
808
|
-
omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
|
|
809
|
-
preserveClientResponseHeaders: !htmlResponsePolicy.shouldWriteToCache,
|
|
810
|
-
expireSeconds,
|
|
811
|
-
isStaticEligible: options.isStaticEligible,
|
|
812
|
-
revalidateSeconds: resolveAppPageCacheWriteRevalidateSeconds({
|
|
813
|
-
isDynamicError: options.isDynamicError,
|
|
814
|
-
isForceStatic: options.isForceStatic,
|
|
815
|
-
isStaticEligible: options.isStaticEligible,
|
|
816
|
-
revalidateSeconds
|
|
817
|
-
}),
|
|
818
|
-
linkHeader: linkHeader ?? null,
|
|
819
|
-
waitUntil(cachePromise) {
|
|
820
|
-
options.waitUntil?.(cachePromise);
|
|
821
|
-
}
|
|
919
|
+
return finalizeHtmlCacheWrite(isrResponse, {
|
|
920
|
+
capturedDynamicUsageBeforeContextCleanup: () => dynamicUsedBeforeContextCleanup,
|
|
921
|
+
htmlResponsePolicy,
|
|
922
|
+
linkHeader: linkHeader ?? null
|
|
822
923
|
});
|
|
823
924
|
}
|
|
824
925
|
const response = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
@@ -49,7 +49,6 @@ type ResolveAppPageGenerateStaticParamsSourcesOptions = {
|
|
|
49
49
|
};
|
|
50
50
|
type BuildAppPageElementOptions<TElement> = {
|
|
51
51
|
buildPageElement: () => Promise<TElement>;
|
|
52
|
-
probePageSpecialError?: () => Promise<AppPageSpecialError | null>;
|
|
53
52
|
renderErrorBoundaryPage: (error: unknown) => Promise<Response | null>;
|
|
54
53
|
renderSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;
|
|
55
54
|
resolveSpecialError: (error: unknown) => AppPageSpecialError | null;
|
|
@@ -333,8 +333,7 @@ async function buildAppPageElement(options) {
|
|
|
333
333
|
response: null
|
|
334
334
|
};
|
|
335
335
|
} catch (error) {
|
|
336
|
-
const
|
|
337
|
-
const specialError = (buildSpecialError ? await options.probePageSpecialError?.() : null) ?? buildSpecialError;
|
|
336
|
+
const specialError = options.resolveSpecialError(error);
|
|
338
337
|
if (specialError) return {
|
|
339
338
|
element: null,
|
|
340
339
|
response: await options.renderSpecialError(specialError)
|
|
@@ -71,9 +71,10 @@ type BuildAppPageHtmlResponseOptions = {
|
|
|
71
71
|
timing?: AppPageResponseTiming;
|
|
72
72
|
};
|
|
73
73
|
/**
|
|
74
|
-
* Only ever set from a *completed* render's cacheLife (cache replay
|
|
75
|
-
* prerender seed) — `use cache` scopes
|
|
76
|
-
* so a streaming response can never
|
|
74
|
+
* Only ever set from a *completed* render's cacheLife (cache replay,
|
|
75
|
+
* prerender seed, or a layout probe's early redirect) — `use cache` scopes
|
|
76
|
+
* keep resolving after headers commit, so a streaming response can never
|
|
77
|
+
* carry it.
|
|
77
78
|
*/
|
|
78
79
|
export declare function applyClientStaleTimeHeader(headers: Headers, staleTimeSeconds: number | undefined): void;
|
|
79
80
|
/**
|
|
@@ -18,9 +18,10 @@ function applyDynamicStaleTimeHeader(headers, dynamicStaleTimeSeconds) {
|
|
|
18
18
|
if (dynamicStaleTimeSeconds !== void 0 && Number.isInteger(dynamicStaleTimeSeconds) && dynamicStaleTimeSeconds >= 0) headers.set(VINEXT_DYNAMIC_STALE_TIME_HEADER, String(dynamicStaleTimeSeconds));
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Only ever set from a *completed* render's cacheLife (cache replay
|
|
22
|
-
* prerender seed) — `use cache` scopes
|
|
23
|
-
* so a streaming response can never
|
|
21
|
+
* Only ever set from a *completed* render's cacheLife (cache replay,
|
|
22
|
+
* prerender seed, or a layout probe's early redirect) — `use cache` scopes
|
|
23
|
+
* keep resolving after headers commit, so a streaming response can never
|
|
24
|
+
* carry it.
|
|
24
25
|
*/
|
|
25
26
|
function applyClientStaleTimeHeader(headers, staleTimeSeconds) {
|
|
26
27
|
if (staleTimeSeconds === void 0) return;
|
|
@@ -140,14 +140,15 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
|
|
|
140
140
|
makeThenableParams: MakeThenableParams;
|
|
141
141
|
matchedParams: AppPageParams;
|
|
142
142
|
metadataPlacement?: "body" | "head";
|
|
143
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Starts resolving the page's head. The head, its streamed body tags and its
|
|
145
|
+
* error outlet each call this while Flight renders them, so callers memoise
|
|
146
|
+
* it per render with React's `cache()`. Without it the head has no metadata.
|
|
147
|
+
*/
|
|
148
|
+
resolveHead?: (() => AppPageRouteHead) | null;
|
|
144
149
|
resolvedMetadataPathname?: string;
|
|
145
|
-
resolvedViewport: Viewport;
|
|
146
150
|
scriptNonce?: string;
|
|
147
|
-
streamingMetadata?: Promise<Metadata | null> | null;
|
|
148
|
-
streamingMetadataOutlet?: Promise<unknown> | null;
|
|
149
151
|
streamingMetadataOutletSuspended?: boolean;
|
|
150
|
-
streamingMetadataTags?: Promise<Metadata | null> | null;
|
|
151
152
|
trailingSlash?: boolean;
|
|
152
153
|
rootForbiddenModule?: TModule | null;
|
|
153
154
|
rootNotFoundModule?: TModule | null;
|
|
@@ -158,6 +159,17 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
|
|
|
158
159
|
searchParams?: unknown;
|
|
159
160
|
slotOverrides?: Readonly<Record<string, AppPageSlotOverride<TModule>>> | null;
|
|
160
161
|
};
|
|
162
|
+
/**
|
|
163
|
+
* A page's head as Flight renders it. `metadata` and `viewport` hold the tags
|
|
164
|
+
* to render, including the HTTP access fallback's when resolution failed, so
|
|
165
|
+
* they never reject. `outlet` rejects with the resolution error so the route's
|
|
166
|
+
* boundaries can handle it.
|
|
167
|
+
*/
|
|
168
|
+
export type AppPageRouteHead = {
|
|
169
|
+
metadata: Promise<Metadata | null>;
|
|
170
|
+
outlet: Promise<null>;
|
|
171
|
+
viewport: Promise<Viewport>;
|
|
172
|
+
};
|
|
161
173
|
type MakeThenableParams = (params: AppPageParams, observer?: ThenableParamsObserver) => unknown;
|
|
162
174
|
type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule> = BuildAppPageRouteElementOptions<TModule, TErrorModule> & {
|
|
163
175
|
interception?: AppElementsInterception | null;
|