vinext 0.1.6 → 0.1.8
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/dist/build/client-build-config.d.ts +4 -6
- package/dist/build/client-build-config.js +27 -7
- package/dist/build/prerender.js +1 -2
- package/dist/check.d.ts +18 -0
- package/dist/check.js +37 -17
- package/dist/cli.js +2 -2
- package/dist/config/next-config.d.ts +2 -1
- package/dist/config/next-config.js +3 -0
- package/dist/config/server-external-packages.d.ts +4 -0
- package/dist/config/server-external-packages.js +91 -0
- package/dist/deploy.d.ts +7 -0
- package/dist/deploy.js +25 -18
- package/dist/entries/app-rsc-entry.d.ts +2 -1
- package/dist/entries/app-rsc-entry.js +89 -20
- package/dist/entries/app-rsc-manifest.js +8 -0
- package/dist/entries/pages-client-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +1 -0
- package/dist/index.js +87 -34
- package/dist/init.js +2 -1
- package/dist/plugins/middleware-server-only.d.ts +8 -6
- package/dist/plugins/middleware-server-only.js +8 -7
- package/dist/plugins/og-assets.js +6 -6
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/remove-console.js +1 -1
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/routing/app-route-graph.d.ts +6 -2
- package/dist/routing/app-route-graph.js +61 -13
- package/dist/routing/app-router.d.ts +5 -0
- package/dist/routing/app-router.js +5 -0
- package/dist/routing/file-matcher.d.ts +5 -0
- package/dist/routing/file-matcher.js +7 -1
- package/dist/server/app-action-request.d.ts +4 -0
- package/dist/server/app-action-request.js +9 -0
- package/dist/server/app-bfcache-identity.d.ts +12 -2
- package/dist/server/app-bfcache-identity.js +52 -23
- package/dist/server/app-browser-entry.js +42 -147
- package/dist/server/app-browser-history-controller.d.ts +2 -1
- package/dist/server/app-browser-history-controller.js +6 -2
- package/dist/server/app-browser-server-action-client.d.ts +32 -0
- package/dist/server/app-browser-server-action-client.js +128 -0
- package/dist/server/app-fallback-renderer.d.ts +3 -1
- package/dist/server/app-fallback-renderer.js +6 -2
- package/dist/server/app-history-state.d.ts +1 -2
- package/dist/server/app-history-state.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +3 -0
- package/dist/server/app-page-boundary-render.js +14 -3
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +8 -2
- package/dist/server/app-page-dispatch.d.ts +33 -4
- package/dist/server/app-page-dispatch.js +62 -90
- package/dist/server/app-page-element-builder.d.ts +7 -1
- package/dist/server/app-page-element-builder.js +56 -19
- package/dist/server/app-page-head.d.ts +16 -1
- package/dist/server/app-page-head.js +44 -22
- package/dist/server/app-page-method.js +1 -1
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +8 -1
- package/dist/server/app-page-ppr-runtime.d.ts +7 -0
- package/dist/server/app-page-ppr-runtime.js +70 -0
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +1 -1
- package/dist/server/app-page-render.d.ts +4 -1
- package/dist/server/app-page-render.js +8 -3
- package/dist/server/app-page-request.d.ts +8 -1
- package/dist/server/app-page-request.js +23 -11
- package/dist/server/app-page-route-wiring.d.ts +6 -1
- package/dist/server/app-page-route-wiring.js +30 -8
- package/dist/server/app-page-search-params-observation.d.ts +4 -2
- package/dist/server/app-page-search-params-observation.js +11 -7
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
- package/dist/server/app-route-handler-cache.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +3 -2
- package/dist/server/app-route-handler-execution.js +5 -3
- package/dist/server/app-route-handler-policy.d.ts +1 -1
- package/dist/server/app-route-handler-policy.js +1 -6
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.js +7 -6
- package/dist/server/app-rsc-errors.d.ts +12 -1
- package/dist/server/app-rsc-errors.js +29 -3
- package/dist/server/app-rsc-handler.d.ts +15 -13
- package/dist/server/app-rsc-handler.js +28 -33
- package/dist/server/app-rsc-response-finalizer.js +5 -1
- package/dist/server/app-rsc-route-matching.d.ts +7 -0
- package/dist/server/app-rsc-route-matching.js +36 -3
- package/dist/server/app-segment-config.d.ts +1 -0
- package/dist/server/app-segment-config.js +32 -2
- package/dist/server/app-server-action-execution.d.ts +4 -0
- package/dist/server/app-server-action-execution.js +42 -11
- package/dist/server/app-ssr-entry.js +11 -6
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +1 -0
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/metadata-route-response.d.ts +1 -1
- package/dist/server/prod-server.js +15 -6
- package/dist/server/worker-utils.d.ts +2 -1
- package/dist/server/worker-utils.js +7 -1
- package/dist/shims/dynamic.js +1 -1
- package/dist/shims/error-boundary.d.ts +19 -1
- package/dist/shims/error-boundary.js +11 -1
- package/dist/shims/headers.d.ts +3 -1
- package/dist/shims/headers.js +16 -5
- package/dist/shims/link.js +16 -12
- package/dist/shims/metadata.d.ts +3 -2
- package/dist/shims/metadata.js +8 -4
- package/dist/shims/router.js +13 -2
- package/dist/typegen.js +6 -5
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +1 -1
- package/dist/utils/project.d.ts +4 -0
- package/dist/utils/project.js +5 -1
- package/package.json +7 -3
|
@@ -3,7 +3,7 @@ import { AppElementsWire } from "./app-elements-wire.js";
|
|
|
3
3
|
import "./app-elements.js";
|
|
4
4
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
5
5
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
6
|
-
import { ErrorBoundary, GlobalErrorBoundary } from "../shims/error-boundary.js";
|
|
6
|
+
import { ErrorBoundary, GlobalErrorBoundary, SerializedErrorBoundary } from "../shims/error-boundary.js";
|
|
7
7
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
8
8
|
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
9
9
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
@@ -152,6 +152,7 @@ async function renderAppPageHttpAccessFallback(options) {
|
|
|
152
152
|
const pathname = new URL(options.requestUrl).pathname;
|
|
153
153
|
const routeSegments = resolveHttpAccessFallbackHeadRouteSegments(options.route, layoutModules);
|
|
154
154
|
const { metadata, viewport } = await resolveAppPageHead({
|
|
155
|
+
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
155
156
|
basePath: options.basePath ?? "",
|
|
156
157
|
layoutModules,
|
|
157
158
|
layoutTreePositions: resolveHttpAccessFallbackHeadLayoutTreePositions(options.route, layoutModules),
|
|
@@ -214,7 +215,7 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
214
215
|
if (!errorBoundary.component) return null;
|
|
215
216
|
const rawError = options.error instanceof Error ? options.error : new Error(String(options.error));
|
|
216
217
|
rewriteClientHookError(rawError);
|
|
217
|
-
const errorObject = options.sanitizeErrorForClient(rawError);
|
|
218
|
+
const errorObject = options.errorOrigin === "ssr" ? rawError : options.sanitizeErrorForClient(rawError);
|
|
218
219
|
const matchedParams = options.matchedParams ?? options.route?.params ?? {};
|
|
219
220
|
const layoutModules = options.route?.layouts ?? options.rootLayouts;
|
|
220
221
|
const pathname = new URL(options.requestUrl).pathname;
|
|
@@ -224,6 +225,7 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
224
225
|
})];
|
|
225
226
|
if (!errorBoundary.isGlobalError) try {
|
|
226
227
|
const { metadata, viewport } = await resolveAppPageHead({
|
|
228
|
+
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
227
229
|
basePath: options.basePath ?? "",
|
|
228
230
|
fallbackOnFileMetadataError: true,
|
|
229
231
|
layoutModules,
|
|
@@ -247,7 +249,16 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
247
249
|
console.error(`[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`, error);
|
|
248
250
|
}
|
|
249
251
|
const buildElement = (BoundaryComponent) => {
|
|
250
|
-
const
|
|
252
|
+
const serializedError = {
|
|
253
|
+
digest: "digest" in errorObject ? String(errorObject.digest) : void 0,
|
|
254
|
+
message: errorObject.message,
|
|
255
|
+
name: errorObject.name,
|
|
256
|
+
stack: process.env.NODE_ENV !== "production" ? errorObject.stack : void 0
|
|
257
|
+
};
|
|
258
|
+
const boundaryElement = errorBoundary.isGlobalError && BoundaryComponent !== DEFAULT_GLOBAL_ERROR_COMPONENT ? createElement(SerializedErrorBoundary, {
|
|
259
|
+
error: serializedError,
|
|
260
|
+
fallback: BoundaryComponent
|
|
261
|
+
}) : createElement(BoundaryComponent, { error: errorObject });
|
|
251
262
|
return wrapRenderedBoundaryElement({
|
|
252
263
|
element: createElement(Fragment, null, ...headElements, errorBoundary.isGlobalError ? createElement(GlobalErrorBoundary, {
|
|
253
264
|
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
@@ -30,6 +30,7 @@ type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
|
30
30
|
isrRscKey: AppPageRscCacheKeyBuilder;
|
|
31
31
|
isrSet: AppPageCacheSetter;
|
|
32
32
|
interceptionContext?: string | null;
|
|
33
|
+
omitPendingDynamicCacheState?: boolean;
|
|
33
34
|
preserveClientResponseHeaders?: boolean;
|
|
34
35
|
expireSeconds?: number;
|
|
35
36
|
revalidateSeconds: number | null;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { NEXTJS_CACHE_HEADER, VINEXT_CACHE_HEADER } from "./headers.js";
|
|
1
2
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
2
3
|
import { applyCdnResponseHeaders } from "./cache-control.js";
|
|
3
4
|
import { buildAppPageCacheValue } from "./isr-cache.js";
|
|
4
5
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
5
6
|
import { createEmptyAppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
6
7
|
//#region src/server/app-page-cache-finalizer.ts
|
|
7
|
-
function applyPendingDynamicCdnHeaders(headers, tags) {
|
|
8
|
+
function applyPendingDynamicCdnHeaders(headers, tags, options = {}) {
|
|
8
9
|
applyCdnResponseHeaders(headers, {
|
|
9
10
|
cacheControl: headers.get("Cache-Control") ?? "",
|
|
10
11
|
pendingDynamicCheck: true,
|
|
11
12
|
tags
|
|
12
13
|
});
|
|
14
|
+
if (options.omitCacheState === true) {
|
|
15
|
+
headers.delete(VINEXT_CACHE_HEADER);
|
|
16
|
+
headers.delete(NEXTJS_CACHE_HEADER);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
13
19
|
setCacheStateHeaders(headers, "MISS");
|
|
14
20
|
}
|
|
15
21
|
function resolveAppPageCacheWritePolicy(options) {
|
|
@@ -30,7 +36,7 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
|
|
|
30
36
|
const htmlKey = options.isrHtmlKey(options.cleanPathname);
|
|
31
37
|
const rscKey = options.isrRscKey(options.cleanPathname, null, void 0, options.interceptionContext);
|
|
32
38
|
const clientHeaders = new Headers(response.headers);
|
|
33
|
-
if (options.preserveClientResponseHeaders !== true) applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags());
|
|
39
|
+
if (options.preserveClientResponseHeaders !== true) applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
|
|
34
40
|
const cachePromise = (async () => {
|
|
35
41
|
try {
|
|
36
42
|
const cachedHtml = await readStreamAsText(streamForCache);
|
|
@@ -10,8 +10,10 @@ import { AppPageSsrHandler } from "./app-page-stream.js";
|
|
|
10
10
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
11
11
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
12
12
|
import { ISRCacheEntry } from "./isr-cache.js";
|
|
13
|
+
import { PprFallbackShellState } from "../shims/ppr-fallback-shell.js";
|
|
13
14
|
import { FetchCacheMode } from "../shims/fetch-cache.js";
|
|
14
15
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
16
|
+
import { WarmPprFallbackShellCachesOptions } from "./app-ppr-fallback-shell-render.js";
|
|
15
17
|
import { ValidateAppPageDynamicParamsOptions } from "./app-page-request.js";
|
|
16
18
|
import { ReactNode } from "react";
|
|
17
19
|
import { ReactFormState } from "react-dom/client";
|
|
@@ -32,7 +34,10 @@ type AppPageBackgroundRegenerationErrorContext = {
|
|
|
32
34
|
type AppPageBackgroundRegenerator = (key: string, renderFn: () => Promise<void>, errorContext?: AppPageBackgroundRegenerationErrorContext) => void;
|
|
33
35
|
type AppPageDispatchIntercept<TPage = unknown> = {
|
|
34
36
|
interceptLayouts?: readonly unknown[] | null;
|
|
37
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
38
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
35
39
|
matchedParams: AppPageParams;
|
|
40
|
+
sourceMatchedParams?: AppPageParams;
|
|
36
41
|
page: TPage;
|
|
37
42
|
slotId?: string | null;
|
|
38
43
|
slotKey: string;
|
|
@@ -42,6 +47,8 @@ type AppPageDispatchIntercept<TPage = unknown> = {
|
|
|
42
47
|
type AppPageDispatchInterceptOptions<TPage = unknown> = {
|
|
43
48
|
interceptionContext: string | null;
|
|
44
49
|
interceptLayouts?: readonly unknown[] | null;
|
|
50
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
51
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
45
52
|
interceptPage: TPage;
|
|
46
53
|
interceptParams: AppPageParams;
|
|
47
54
|
interceptSlotId?: string | null;
|
|
@@ -80,6 +87,14 @@ type AppPageDispatchRoute = {
|
|
|
80
87
|
unauthorized?: AppPageModule | null;
|
|
81
88
|
unauthorizeds?: readonly (AppPageModule | null | undefined)[];
|
|
82
89
|
};
|
|
90
|
+
type AppPagePprRuntime<TRoute extends AppPageDispatchRoute> = {
|
|
91
|
+
beginFinalRender(state: AppPagePprState): void;
|
|
92
|
+
getState(): AppPagePprState | null;
|
|
93
|
+
run<T>(shell: NonNullable<DispatchAppPageOptions<TRoute>["pprFallbackShell"]>, fn: () => T): T;
|
|
94
|
+
tryServe(options: DispatchAppPageOptions<TRoute>, currentRevalidateSeconds: number | null, isDraftMode: boolean, isForceStatic: boolean, isForceDynamic: boolean): Promise<Response | null>;
|
|
95
|
+
warm(options: WarmPprFallbackShellCachesOptions): Promise<void>;
|
|
96
|
+
};
|
|
97
|
+
type AppPagePprState = PprFallbackShellState;
|
|
83
98
|
type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
84
99
|
/** Configured basePath (e.g. "/blog"). Used to prefix redirect Locations. */basePath?: string;
|
|
85
100
|
/**
|
|
@@ -94,7 +109,10 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
94
109
|
* `next.config`. Undefined falls back to the React default downstream.
|
|
95
110
|
*/
|
|
96
111
|
reactMaxHeadersLength?: number;
|
|
97
|
-
buildPageElement: (route: TRoute, params: AppPageParams, opts: AppPageDispatchInterceptOptions | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker
|
|
112
|
+
buildPageElement: (route: TRoute, params: AppPageParams, opts: AppPageDispatchInterceptOptions | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker, options?: {
|
|
113
|
+
observeMetadataSearchParamsAccess?: boolean;
|
|
114
|
+
observePageSearchParamsAccess?: boolean;
|
|
115
|
+
}) => Promise<AppPageElement>;
|
|
98
116
|
clientReuseManifest?: ClientReuseManifestParseResult;
|
|
99
117
|
cleanPathname: string;
|
|
100
118
|
displayPathname?: string;
|
|
@@ -147,6 +165,7 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
147
165
|
fallbackParamNames: readonly string[];
|
|
148
166
|
routePattern: string;
|
|
149
167
|
};
|
|
168
|
+
pprRuntime?: AppPagePprRuntime<TRoute>;
|
|
150
169
|
/**
|
|
151
170
|
* Set of concrete URL paths that were pre-rendered at build time for this
|
|
152
171
|
* route. When the exact cache entry for a known pregenerated path is absent
|
|
@@ -159,9 +178,9 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
159
178
|
staticParamsValidationParams?: AppPageParams;
|
|
160
179
|
rootParams?: RootParams;
|
|
161
180
|
probeLayoutAt: (layoutIndex: number, layoutParamAccess?: AppLayoutParamAccessTracker) => unknown;
|
|
162
|
-
probePage: () => unknown;
|
|
181
|
+
probePage: (searchParams?: URLSearchParams) => unknown;
|
|
163
182
|
expireSeconds?: number;
|
|
164
|
-
renderErrorBoundaryPage: (error: unknown) => Promise<Response | null>;
|
|
183
|
+
renderErrorBoundaryPage: (error: unknown, errorOrigin?: "rsc" | "ssr") => Promise<Response | null>;
|
|
165
184
|
renderHttpAccessFallbackPage: (statusCode: number, opts: {
|
|
166
185
|
boundaryComponent?: unknown;
|
|
167
186
|
boundaryModule?: AppPageModule | null;
|
|
@@ -197,6 +216,16 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
197
216
|
}) => void;
|
|
198
217
|
renderMode?: AppRscRenderMode;
|
|
199
218
|
};
|
|
219
|
+
declare function shouldReadAppPageCache(options: {
|
|
220
|
+
isProgressiveActionRender: boolean;
|
|
221
|
+
isDraftMode: boolean;
|
|
222
|
+
isForceDynamic: boolean;
|
|
223
|
+
isProduction: boolean;
|
|
224
|
+
isRscRequest: boolean;
|
|
225
|
+
revalidateSeconds: number | null;
|
|
226
|
+
scriptNonce?: string;
|
|
227
|
+
}): boolean;
|
|
228
|
+
declare function hasSearchParams(searchParams: URLSearchParams | null | undefined): boolean;
|
|
200
229
|
declare function dispatchAppPage<TRoute extends AppPageDispatchRoute>(options: DispatchAppPageOptions<TRoute>): Promise<Response>;
|
|
201
230
|
//#endregion
|
|
202
|
-
export { dispatchAppPage };
|
|
231
|
+
export { AppPageBoundaryOnError, AppPageDispatchRoute, AppPagePprRuntime, AppPagePprState, AppPageRenderableElement, DispatchAppPageOptions, dispatchAppPage, hasSearchParams, shouldReadAppPageCache };
|
|
@@ -3,8 +3,7 @@ import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
|
3
3
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
4
4
|
import { shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
|
|
5
5
|
import "./app-elements.js";
|
|
6
|
-
import {
|
|
7
|
-
import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, markDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
|
|
6
|
+
import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersContext, isDraftModeRequest, markDynamicUsage, peekDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
|
|
8
7
|
import { _consumeRequestScopedCacheLife, _peekRequestScopedCacheLife } from "../shims/cache-request-state.js";
|
|
9
8
|
import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
|
|
10
9
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
@@ -108,6 +107,7 @@ async function runAppPageRevalidationContext(options, renderFn) {
|
|
|
108
107
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
109
108
|
return runWithRequestContext(createRequestContext({
|
|
110
109
|
headersContext: createStaticGenerationHeadersContext({
|
|
110
|
+
draftModeEnabled: false,
|
|
111
111
|
draftModeSecret: options.draftModeSecret,
|
|
112
112
|
dynamicConfig: options.dynamicConfig,
|
|
113
113
|
routeKind: "page",
|
|
@@ -132,6 +132,8 @@ function toInterceptOptions(interceptionContext, intercept) {
|
|
|
132
132
|
return {
|
|
133
133
|
interceptionContext,
|
|
134
134
|
interceptLayouts: intercept.interceptLayouts,
|
|
135
|
+
interceptLayoutSegments: intercept.interceptLayoutSegments,
|
|
136
|
+
interceptBranchSegments: intercept.interceptBranchSegments,
|
|
135
137
|
interceptPage: intercept.page,
|
|
136
138
|
interceptParams: intercept.matchedParams,
|
|
137
139
|
interceptSlotId: intercept.slotId ?? null,
|
|
@@ -140,75 +142,10 @@ function toInterceptOptions(interceptionContext, intercept) {
|
|
|
140
142
|
interceptSourcePageSegments: intercept.sourcePageSegments ?? null
|
|
141
143
|
};
|
|
142
144
|
}
|
|
143
|
-
/**
|
|
144
|
-
* Request-phase fallback-shell gate. Callers must run the exact cache read and
|
|
145
|
-
* static-param validation before this classification step.
|
|
146
|
-
*/
|
|
147
|
-
function classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
|
|
148
|
-
if (options.renderedConcreteUrlPaths?.has(options.cleanPathname) === true) return { kind: "skip-known-pregenerated-route" };
|
|
149
|
-
const fallbackShells = options.pprFallbackCacheShells;
|
|
150
|
-
if (!fallbackShells || fallbackShells.length === 0) return { kind: "skip-no-fallback-shells" };
|
|
151
|
-
if (options.isRscRequest) return { kind: "skip-rsc-request" };
|
|
152
|
-
if (options.request.method !== "GET") return { kind: "skip-non-get" };
|
|
153
|
-
if (!isForceStatic && hasSearchParams(options.searchParams)) return { kind: "skip-search-params" };
|
|
154
|
-
if (!shouldReadAppPageCache({
|
|
155
|
-
isDraftMode,
|
|
156
|
-
isForceDynamic,
|
|
157
|
-
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
158
|
-
isProduction: options.isProduction,
|
|
159
|
-
isRscRequest: false,
|
|
160
|
-
revalidateSeconds: currentRevalidateSeconds,
|
|
161
|
-
scriptNonce: options.scriptNonce
|
|
162
|
-
})) return { kind: "skip-cache-disabled" };
|
|
163
|
-
return {
|
|
164
|
-
kind: "probe-fallback-shells",
|
|
165
|
-
fallbackShells
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
async function probePprFallbackShellCache(options, route, fallbackShells, currentRevalidateSeconds) {
|
|
169
|
-
const { readAppPageFallbackShellCacheResponse } = await import("./app-page-cache.js");
|
|
170
|
-
const { rewriteAppPprFallbackShellHtmlNavigation } = await import("./app-ppr-fallback-shell.js");
|
|
171
|
-
for (const fallbackShell of fallbackShells) {
|
|
172
|
-
const fallbackShellResponse = await readAppPageFallbackShellCacheResponse({
|
|
173
|
-
clearRequestContext: options.clearRequestContext,
|
|
174
|
-
expireSeconds: options.expireSeconds,
|
|
175
|
-
fallbackPathname: fallbackShell.pathname,
|
|
176
|
-
isEdgeRuntime: options.isEdgeRuntime,
|
|
177
|
-
isrDebug: options.isrDebug,
|
|
178
|
-
isrGet: options.isrGet,
|
|
179
|
-
isrHtmlKey: options.isrHtmlKey,
|
|
180
|
-
middlewareHeaders: options.middlewareContext.headers,
|
|
181
|
-
middlewareStatus: options.middlewareContext.status,
|
|
182
|
-
revalidateSeconds: currentRevalidateSeconds ?? 0,
|
|
183
|
-
rewriteHtml(html) {
|
|
184
|
-
return rewriteAppPprFallbackShellHtmlNavigation({
|
|
185
|
-
html,
|
|
186
|
-
params: options.params,
|
|
187
|
-
pathname: options.cleanPathname,
|
|
188
|
-
searchParams: options.searchParams
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
if (fallbackShellResponse) return fallbackShellResponse;
|
|
193
|
-
}
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
async function tryServePprFallbackShell(options, route, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
|
|
197
|
-
const decision = classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic);
|
|
198
|
-
switch (decision.kind) {
|
|
199
|
-
case "skip-known-pregenerated-route":
|
|
200
|
-
case "skip-no-fallback-shells":
|
|
201
|
-
case "skip-rsc-request":
|
|
202
|
-
case "skip-non-get":
|
|
203
|
-
case "skip-search-params":
|
|
204
|
-
case "skip-cache-disabled": return null;
|
|
205
|
-
case "probe-fallback-shells": return await probePprFallbackShellCache(options, route, decision.fallbackShells, currentRevalidateSeconds);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
145
|
async function dispatchAppPage(options) {
|
|
209
146
|
const dispatch = () => runWithFetchDedupe(() => dispatchAppPageInner(options));
|
|
210
|
-
if (!options.pprFallbackShell) return await dispatch();
|
|
211
|
-
return await
|
|
147
|
+
if (!options.pprFallbackShell || !options.pprRuntime) return await dispatch();
|
|
148
|
+
return await options.pprRuntime.run(options.pprFallbackShell, dispatch);
|
|
212
149
|
}
|
|
213
150
|
async function dispatchAppPageInner(options) {
|
|
214
151
|
const route = options.route;
|
|
@@ -218,7 +155,11 @@ async function dispatchAppPageInner(options) {
|
|
|
218
155
|
const isDynamicError = dynamicConfig === "error";
|
|
219
156
|
const isForceDynamic = dynamicConfig === "force-dynamic";
|
|
220
157
|
const isDraftMode = isDraftModeRequest(options.request, options.draftModeSecret);
|
|
158
|
+
const requestHeadersContext = getHeadersContext();
|
|
159
|
+
const hasRequestSearchParams = !isForceStatic && hasSearchParams(options.searchParams);
|
|
160
|
+
const pageSearchParams = isForceStatic ? new URLSearchParams() : options.searchParams;
|
|
221
161
|
const layoutParamAccess = createAppLayoutParamAccessTracker();
|
|
162
|
+
const hasActiveLoadingBoundary = shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") ? false : Boolean(route.loading?.default);
|
|
222
163
|
setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
|
|
223
164
|
setCurrentFetchCacheMode(options.fetchCache ?? null);
|
|
224
165
|
setCurrentForceDynamicFetchDefault(isForceDynamic);
|
|
@@ -238,9 +179,10 @@ async function dispatchAppPageInner(options) {
|
|
|
238
179
|
options.clearRequestContext();
|
|
239
180
|
return methodResponse;
|
|
240
181
|
}
|
|
241
|
-
if (
|
|
182
|
+
if (isForceStatic || isDynamicError) {
|
|
242
183
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
243
184
|
setHeadersContext(createStaticGenerationHeadersContext({
|
|
185
|
+
draftModeEnabled: isDraftMode,
|
|
244
186
|
draftModeSecret: options.draftModeSecret,
|
|
245
187
|
dynamicConfig,
|
|
246
188
|
routeKind: "page",
|
|
@@ -266,7 +208,7 @@ async function dispatchAppPageInner(options) {
|
|
|
266
208
|
const cachedPageResponse = await readAppPageCacheResponse({
|
|
267
209
|
cleanPathname: options.cleanPathname,
|
|
268
210
|
clearRequestContext: options.clearRequestContext,
|
|
269
|
-
hasRequestSearchParams
|
|
211
|
+
hasRequestSearchParams,
|
|
270
212
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
271
213
|
isRscRequest: options.isRscRequest,
|
|
272
214
|
isrDebug: options.isrDebug,
|
|
@@ -300,19 +242,23 @@ async function dispatchAppPageInner(options) {
|
|
|
300
242
|
});
|
|
301
243
|
revalidationTarget.navigationParams = resolveAppPageNavigationParams(revalidationTarget.route, revalidationTarget.navigationParams, options.cleanPathname, revalidationTarget.interceptOpts);
|
|
302
244
|
await options.ensureRouteLoaded?.(revalidationTarget.route);
|
|
245
|
+
const revalidationDynamicConfig = options.resolveRouteDynamicConfig?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? dynamicConfig : void 0);
|
|
303
246
|
return runAppPageRevalidationContext({
|
|
304
247
|
cleanPathname: options.cleanPathname,
|
|
305
248
|
displayPathname: options.displayPathname,
|
|
306
249
|
currentFetchCacheMode: options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
|
|
307
250
|
draftModeSecret: options.draftModeSecret,
|
|
308
|
-
dynamicConfig:
|
|
251
|
+
dynamicConfig: revalidationDynamicConfig,
|
|
309
252
|
params: revalidationTarget.navigationParams,
|
|
310
253
|
routePattern: revalidationTarget.route.pattern,
|
|
311
254
|
routeSegments: revalidationTarget.route.routeSegments,
|
|
312
255
|
setNavigationContext: options.setNavigationContext
|
|
313
256
|
}, async () => {
|
|
314
257
|
const { renderAppPageCacheArtifacts } = await import("./app-page-cache-render.js");
|
|
315
|
-
const revalidatedElement = await options.buildPageElement(revalidationTarget.route, revalidationTarget.params, revalidationTarget.interceptOpts, new URLSearchParams()
|
|
258
|
+
const revalidatedElement = await options.buildPageElement(revalidationTarget.route, revalidationTarget.params, revalidationTarget.interceptOpts, new URLSearchParams(), void 0, {
|
|
259
|
+
observeMetadataSearchParamsAccess: revalidationDynamicConfig !== "force-static",
|
|
260
|
+
observePageSearchParamsAccess: revalidationDynamicConfig !== "force-static"
|
|
261
|
+
});
|
|
316
262
|
const revalidatedOnError = options.createRscOnErrorHandler(options.cleanPathname, revalidationTarget.route.pattern);
|
|
317
263
|
const rendered = await renderAppPageCacheArtifacts({
|
|
318
264
|
basePath: options.basePath,
|
|
@@ -365,14 +311,29 @@ async function dispatchAppPageInner(options) {
|
|
|
365
311
|
});
|
|
366
312
|
if (dynamicParamsResponse) return dynamicParamsResponse;
|
|
367
313
|
}
|
|
368
|
-
const fallbackShellResponse = await
|
|
314
|
+
const fallbackShellResponse = options.pprRuntime ? await options.pprRuntime.tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) : null;
|
|
369
315
|
if (fallbackShellResponse) return fallbackShellResponse;
|
|
316
|
+
let interceptDynamicConfig;
|
|
317
|
+
let interceptDynamicConfigResolved = false;
|
|
370
318
|
const interceptResult = await resolveAppPageIntercept({
|
|
371
319
|
async buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess) {
|
|
372
|
-
|
|
320
|
+
const sourceDynamicConfig = interceptDynamicConfigResolved ? interceptDynamicConfig : options.resolveRouteDynamicConfig?.(interceptRoute);
|
|
321
|
+
if (sourceDynamicConfig === "force-static" || sourceDynamicConfig === "error") {
|
|
322
|
+
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
323
|
+
setHeadersContext(createStaticGenerationHeadersContext({
|
|
324
|
+
draftModeEnabled: isDraftMode,
|
|
325
|
+
draftModeSecret: options.draftModeSecret,
|
|
326
|
+
dynamicConfig: sourceDynamicConfig,
|
|
327
|
+
routeKind: "page",
|
|
328
|
+
routePattern: interceptRoute.pattern
|
|
329
|
+
}));
|
|
330
|
+
} else setHeadersContext(requestHeadersContext);
|
|
373
331
|
setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(interceptRoute) ?? null);
|
|
374
|
-
setCurrentForceDynamicFetchDefault(
|
|
375
|
-
return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess
|
|
332
|
+
setCurrentForceDynamicFetchDefault(sourceDynamicConfig === "force-dynamic");
|
|
333
|
+
return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess, {
|
|
334
|
+
observeMetadataSearchParamsAccess: sourceDynamicConfig !== "force-static",
|
|
335
|
+
observePageSearchParamsAccess: sourceDynamicConfig !== "force-static"
|
|
336
|
+
});
|
|
376
337
|
},
|
|
377
338
|
cleanPathname: options.cleanPathname,
|
|
378
339
|
currentRoute: route,
|
|
@@ -404,6 +365,12 @@ async function dispatchAppPageInner(options) {
|
|
|
404
365
|
headers: interceptHeaders
|
|
405
366
|
});
|
|
406
367
|
},
|
|
368
|
+
async resolveSearchParams(sourceRoute, searchParams) {
|
|
369
|
+
await options.ensureRouteLoaded?.(sourceRoute);
|
|
370
|
+
interceptDynamicConfig = options.resolveRouteDynamicConfig?.(sourceRoute);
|
|
371
|
+
interceptDynamicConfigResolved = true;
|
|
372
|
+
return interceptDynamicConfig === "force-static" ? new URLSearchParams() : searchParams;
|
|
373
|
+
},
|
|
407
374
|
searchParams: options.searchParams,
|
|
408
375
|
setNavigationContext: options.setNavigationContext,
|
|
409
376
|
toInterceptOpts(intercept) {
|
|
@@ -414,12 +381,15 @@ async function dispatchAppPageInner(options) {
|
|
|
414
381
|
const buildCurrentPageElement = () => buildAppPageElement({
|
|
415
382
|
buildPageElement() {
|
|
416
383
|
if (options.actionFailed) throw options.actionError;
|
|
417
|
-
return options.buildPageElement(route, options.params, interceptResult.interceptOpts,
|
|
384
|
+
return options.buildPageElement(route, options.params, interceptResult.interceptOpts, pageSearchParams, layoutParamAccess, {
|
|
385
|
+
observeMetadataSearchParamsAccess: !isForceStatic,
|
|
386
|
+
observePageSearchParamsAccess: !isForceStatic
|
|
387
|
+
});
|
|
418
388
|
},
|
|
419
389
|
async probePageSpecialError() {
|
|
420
390
|
if (!shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") && route.loading?.default) return null;
|
|
421
391
|
return resolveAppPageSpecialError(await probeAppPageThrownError({
|
|
422
|
-
probePage: options.probePage,
|
|
392
|
+
probePage: () => options.probePage(pageSearchParams),
|
|
423
393
|
runWithSuppressedHookWarning(probe) {
|
|
424
394
|
return options.runWithSuppressedHookWarning(probe);
|
|
425
395
|
}
|
|
@@ -433,12 +403,11 @@ async function dispatchAppPageInner(options) {
|
|
|
433
403
|
},
|
|
434
404
|
resolveSpecialError: resolveAppPageSpecialError
|
|
435
405
|
});
|
|
436
|
-
const fallbackShellState =
|
|
406
|
+
const fallbackShellState = options.pprRuntime?.getState() ?? null;
|
|
437
407
|
if (fallbackShellState && process.env.VINEXT_PRERENDER === "1" && !options.isRscRequest) {
|
|
438
408
|
const warmupBuildResult = await buildCurrentPageElement();
|
|
439
409
|
if (warmupBuildResult.response) return warmupBuildResult.response;
|
|
440
|
-
|
|
441
|
-
await warmPprFallbackShellCaches({
|
|
410
|
+
await options.pprRuntime.warm({
|
|
442
411
|
element: warmupBuildResult.element,
|
|
443
412
|
onError: options.createRscOnErrorHandler(options.cleanPathname, route.pattern),
|
|
444
413
|
renderToReadableStream: options.renderToReadableStream,
|
|
@@ -451,11 +420,11 @@ async function dispatchAppPageInner(options) {
|
|
|
451
420
|
const navigationParams = resolveAppPageNavigationParams(route, options.params, options.cleanPathname, interceptResult.interceptOpts);
|
|
452
421
|
options.setNavigationContext({
|
|
453
422
|
pathname: options.displayPathname ?? options.cleanPathname,
|
|
454
|
-
searchParams:
|
|
423
|
+
searchParams: pageSearchParams,
|
|
455
424
|
params: navigationParams
|
|
456
425
|
});
|
|
457
426
|
const layoutClassifications = getEffectiveLayoutClassifications(route, options.debugClassification);
|
|
458
|
-
const activeFallbackShellState =
|
|
427
|
+
const activeFallbackShellState = options.pprRuntime?.getState() ?? null;
|
|
459
428
|
const pprFallbackShellSignal = activeFallbackShellState?.abortController.signal;
|
|
460
429
|
const pprFallbackShellReactSignal = activeFallbackShellState?.reactAbortController.signal;
|
|
461
430
|
return renderAppPageLifecycle({
|
|
@@ -465,6 +434,7 @@ async function dispatchAppPageInner(options) {
|
|
|
465
434
|
cleanPathname: options.cleanPathname,
|
|
466
435
|
clearRequestContext: options.clearRequestContext,
|
|
467
436
|
consumeDynamicUsage,
|
|
437
|
+
peekDynamicUsage,
|
|
468
438
|
consumeInvalidDynamicUsageError,
|
|
469
439
|
consumeRenderObservationState: consumeAppPageRenderObservationState,
|
|
470
440
|
createRscOnErrorHandler(pathname, routePath) {
|
|
@@ -487,7 +457,8 @@ async function dispatchAppPageInner(options) {
|
|
|
487
457
|
return _peekRequestScopedCacheLife();
|
|
488
458
|
},
|
|
489
459
|
handlerStart: options.handlerStart,
|
|
490
|
-
hasLoadingBoundary:
|
|
460
|
+
hasLoadingBoundary: hasActiveLoadingBoundary,
|
|
461
|
+
omitPendingDynamicCacheState: !options.isRscRequest && hasRequestSearchParams,
|
|
491
462
|
formState: options.formState ?? null,
|
|
492
463
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
493
464
|
isDynamicError,
|
|
@@ -512,7 +483,7 @@ async function dispatchAppPageInner(options) {
|
|
|
512
483
|
pprFallbackShellSignal,
|
|
513
484
|
pprFallbackShellReactSignal,
|
|
514
485
|
abortPprFallbackShell: activeFallbackShellState ? () => {
|
|
515
|
-
|
|
486
|
+
options.pprRuntime.beginFinalRender(activeFallbackShellState);
|
|
516
487
|
} : void 0,
|
|
517
488
|
layoutParamAccess,
|
|
518
489
|
rootParams: options.rootParams,
|
|
@@ -526,8 +497,9 @@ async function dispatchAppPageInner(options) {
|
|
|
526
497
|
return options.probeLayoutAt(layoutIndex, layoutParamAccess);
|
|
527
498
|
},
|
|
528
499
|
probePage() {
|
|
529
|
-
return options.probePage();
|
|
500
|
+
return options.probePage(pageSearchParams);
|
|
530
501
|
},
|
|
502
|
+
probePageBeforeRender: options.isRscRequest,
|
|
531
503
|
classification: {
|
|
532
504
|
getLayoutId(index) {
|
|
533
505
|
const treePosition = route.layoutTreePositions?.[index] ?? 0;
|
|
@@ -556,8 +528,8 @@ async function dispatchAppPageInner(options) {
|
|
|
556
528
|
revalidateSeconds: currentRevalidateSeconds,
|
|
557
529
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
558
530
|
renderMode: options.renderMode ?? "navigation",
|
|
559
|
-
renderErrorBoundaryResponse(renderError) {
|
|
560
|
-
return options.renderErrorBoundaryPage(renderError);
|
|
531
|
+
renderErrorBoundaryResponse(renderError, errorOrigin) {
|
|
532
|
+
return options.renderErrorBoundaryPage(renderError, errorOrigin);
|
|
561
533
|
},
|
|
562
534
|
renderLayoutSpecialError(specialError, layoutIndex) {
|
|
563
535
|
return renderLayoutSpecialError(options, specialError, layoutIndex);
|
|
@@ -674,4 +646,4 @@ async function renderPageSpecialError(options, specialError) {
|
|
|
674
646
|
});
|
|
675
647
|
}
|
|
676
648
|
//#endregion
|
|
677
|
-
export { dispatchAppPage };
|
|
649
|
+
export { dispatchAppPage, hasSearchParams, shouldReadAppPageCache };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
2
|
import { AppElements } from "./app-elements-wire.js";
|
|
3
3
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
4
|
+
import { ApplyAppPageFileBasedMetadata } from "./app-page-head.js";
|
|
4
5
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
5
6
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
6
7
|
import { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute } from "./app-page-route-wiring.js";
|
|
@@ -19,6 +20,8 @@ type AppPageBuildRoute<TModule extends AppPageModule = AppPageModule, TErrorModu
|
|
|
19
20
|
type AppPageInterceptOptions<TModule extends AppPageModule = AppPageModule> = {
|
|
20
21
|
interceptionContext?: string | null;
|
|
21
22
|
interceptLayouts?: readonly (TModule | null | undefined)[] | null;
|
|
23
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
24
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
22
25
|
interceptPage?: TModule | null;
|
|
23
26
|
interceptParams?: AppPageParams | null;
|
|
24
27
|
interceptSlotId?: string | null;
|
|
@@ -32,9 +35,12 @@ type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> = {
|
|
|
32
35
|
isRscRequest: boolean; /** The incoming HTTP request (available but unused by this module). */
|
|
33
36
|
request: Request; /** Normalized x-vinext-mounted-slots header value. */
|
|
34
37
|
mountedSlotsHeader: string | null; /** Semantic RSC payload mode for this page render. */
|
|
35
|
-
renderMode?: AppRscRenderMode;
|
|
38
|
+
renderMode?: AppRscRenderMode; /** Observe page `searchParams` access for cache-safety classification. */
|
|
39
|
+
observePageSearchParamsAccess?: boolean; /** Observe page metadata `searchParams` access for cache-safety classification. */
|
|
40
|
+
observeMetadataSearchParamsAccess?: boolean;
|
|
36
41
|
};
|
|
37
42
|
type BuildPageElementsOptions<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule> = {
|
|
43
|
+
applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
|
|
38
44
|
route: AppPageBuildRoute<TModule, TErrorModule>;
|
|
39
45
|
params: AppPageParams;
|
|
40
46
|
routePath: string;
|