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
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
2
2
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
3
|
-
import { APP_RSC_RENDER_MODE_NAVIGATION
|
|
3
|
+
import { APP_RSC_RENDER_MODE_NAVIGATION } from "./app-rsc-render-mode.js";
|
|
4
4
|
import "./app-elements.js";
|
|
5
5
|
import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
6
6
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
7
|
+
import { resolveAppPageBranchParams } from "./app-page-params.js";
|
|
7
8
|
import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
|
|
8
|
-
import { makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
9
|
+
import { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
9
10
|
import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath } from "./app-page-route-wiring.js";
|
|
10
11
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
11
12
|
import "./app-rsc-route-matching.js";
|
|
12
13
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
13
14
|
import { createElement } from "react";
|
|
14
15
|
//#region src/server/app-page-element-builder.ts
|
|
16
|
+
function resolveInterceptLayoutParams(branchSegments, layoutSegments, params) {
|
|
17
|
+
return resolveAppPageBranchParams(branchSegments, layoutSegments.length, params, layoutSegments);
|
|
18
|
+
}
|
|
19
|
+
const REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference");
|
|
20
|
+
function isReactOwnedPageComponent(component) {
|
|
21
|
+
if (typeof component !== "function") return true;
|
|
22
|
+
const candidate = component;
|
|
23
|
+
return candidate.$$typeof === REACT_CLIENT_REFERENCE || candidate.prototype?.isReactComponent != null;
|
|
24
|
+
}
|
|
15
25
|
/**
|
|
16
26
|
* Build the App Router element tree for a matched route.
|
|
17
27
|
*
|
|
@@ -30,7 +40,8 @@ import { createElement } from "react";
|
|
|
30
40
|
*/
|
|
31
41
|
async function buildPageElements(options) {
|
|
32
42
|
const { route, params, routePath, displayPathname = routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
|
|
33
|
-
const
|
|
43
|
+
const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
|
|
44
|
+
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false } = pageRequest;
|
|
34
45
|
const pageModule = route.page;
|
|
35
46
|
const isSiblingIntercept = opts?.interceptSlotKey === "__vinext_page_intercept" && !!opts?.interceptPage;
|
|
36
47
|
const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
|
|
@@ -64,44 +75,68 @@ async function buildPageElements(options) {
|
|
|
64
75
|
};
|
|
65
76
|
}
|
|
66
77
|
const { hasDynamicMetadata, metadata: resolvedMetadata, pageSearchParams, viewport: resolvedViewport } = await resolveAppPageHead({
|
|
78
|
+
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
67
79
|
basePath: options.basePath ?? "",
|
|
68
80
|
layoutModules: route.layouts,
|
|
69
81
|
layoutTreePositions: route.layoutTreePositions,
|
|
70
82
|
metadataRoutes,
|
|
71
|
-
pageModule: effectivePageModule ?? null,
|
|
72
|
-
parallelRoutes: resolveActiveParallelRouteHeadInputs({
|
|
83
|
+
pageModule: isSiblingIntercept ? null : effectivePageModule ?? null,
|
|
84
|
+
parallelRoutes: [...resolveActiveParallelRouteHeadInputs({
|
|
85
|
+
interceptBranchSegments: opts?.interceptBranchSegments ?? null,
|
|
73
86
|
interceptLayouts: opts?.interceptLayouts ?? null,
|
|
87
|
+
interceptLayoutSegments: opts?.interceptLayoutSegments ?? null,
|
|
74
88
|
interceptPage: opts?.interceptPage ?? null,
|
|
75
89
|
interceptParams: opts?.interceptParams ?? null,
|
|
76
90
|
interceptSlotKey: opts?.interceptSlotKey ?? null,
|
|
91
|
+
layoutTreePositions: route.layoutTreePositions,
|
|
77
92
|
params,
|
|
78
93
|
routeSegments: route.routeSegments ?? [],
|
|
94
|
+
slotParams: slotParamOverrides,
|
|
79
95
|
slots: route.slots ?? null
|
|
80
|
-
}),
|
|
96
|
+
}), ...isSiblingIntercept ? [{
|
|
97
|
+
layoutModules: opts?.interceptLayouts ?? [],
|
|
98
|
+
layoutParams: (opts?.interceptLayoutSegments ?? []).map((segments) => resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? segments, segments, effectiveParams)),
|
|
99
|
+
pageModule: effectivePageModule ?? null,
|
|
100
|
+
params: effectiveParams,
|
|
101
|
+
routeSegments: opts?.interceptSourcePageSegments ?? route.routeSegments ?? []
|
|
102
|
+
}] : []],
|
|
81
103
|
params: effectiveParams,
|
|
82
104
|
routePath: route.pattern,
|
|
83
105
|
routeSegments: route.routeSegments ?? null,
|
|
84
|
-
searchParams
|
|
106
|
+
searchParams,
|
|
107
|
+
searchParamsObserver: observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0
|
|
85
108
|
});
|
|
86
109
|
const pageProps = { params: makeThenableParams(effectiveParams) };
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
110
|
+
const hasRequestSearchParams = Object.keys(pageSearchParams).length > 0;
|
|
111
|
+
const createPageElement = (PageComponent, props) => {
|
|
112
|
+
if (isReactOwnedPageComponent(PageComponent)) {
|
|
113
|
+
const invocationProps = { ...props };
|
|
114
|
+
if (searchParams) invocationProps.searchParams = observePageSearchParamsAccess ? makeObservedAppPageSearchParamsThenable(pageSearchParams, { markDynamic: hasRequestSearchParams }) : makeThenableParams(pageSearchParams);
|
|
115
|
+
return createElement(PageComponent, invocationProps);
|
|
116
|
+
}
|
|
117
|
+
const ServerPageComponent = PageComponent;
|
|
118
|
+
const PageInvoker = () => {
|
|
119
|
+
const invocationProps = { ...props };
|
|
120
|
+
if (searchParams) invocationProps.searchParams = observePageSearchParamsAccess ? makeObservedAppPageSearchParamsThenable(pageSearchParams) : makeThenableParams(pageSearchParams);
|
|
121
|
+
return ServerPageComponent(invocationProps);
|
|
122
|
+
};
|
|
123
|
+
return createElement(PageInvoker);
|
|
124
|
+
};
|
|
125
|
+
const pageSearchParamsThenable = searchParams ? makeThenableParams(pageSearchParams) : void 0;
|
|
92
126
|
const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(" ")) : null;
|
|
93
127
|
const slotOverrides = buildSlotOverrides(route, params, routePath, opts);
|
|
94
128
|
const metadataPlacement = hasDynamicMetadata && shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots) ? "body" : "head";
|
|
95
|
-
let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ?
|
|
96
|
-
if (isSiblingIntercept && siblingInterceptElement !== null && opts?.interceptLayouts?.length) {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
129
|
+
let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null;
|
|
130
|
+
if (isSiblingIntercept && siblingInterceptElement !== null && opts?.interceptLayouts?.length) for (let i = opts.interceptLayouts.length - 1; i >= 0; i--) {
|
|
131
|
+
const LayoutComponent = opts.interceptLayouts[i]?.default;
|
|
132
|
+
if (LayoutComponent) {
|
|
133
|
+
const interceptLayoutSegments = opts.interceptLayoutSegments?.[i] ?? [];
|
|
134
|
+
siblingInterceptElement = createElement(LayoutComponent, { params: makeThenableParams(resolveInterceptLayoutParams(opts.interceptBranchSegments ?? interceptLayoutSegments, interceptLayoutSegments, effectiveParams)) }, siblingInterceptElement);
|
|
101
135
|
}
|
|
102
136
|
}
|
|
103
137
|
return buildAppPageElements({
|
|
104
|
-
element: isSiblingIntercept ? siblingInterceptElement : EffectivePageComponent ?
|
|
138
|
+
element: isSiblingIntercept ? siblingInterceptElement : EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null,
|
|
139
|
+
createPageElement,
|
|
105
140
|
globalErrorModule: globalErrorModule ?? DEFAULT_GLOBAL_ERROR_MODULE,
|
|
106
141
|
isRscRequest,
|
|
107
142
|
layoutParamAccess: options.layoutParamAccess,
|
|
@@ -142,7 +177,9 @@ async function buildPageElements(options) {
|
|
|
142
177
|
function buildSlotOverrides(route, routeParams, routePath, opts) {
|
|
143
178
|
const overrides = {};
|
|
144
179
|
if (opts && opts.interceptSlotKey && opts.interceptPage && opts.interceptSlotKey !== "__vinext_page_intercept") overrides[opts.interceptSlotKey] = {
|
|
180
|
+
branchSegments: opts.interceptBranchSegments ?? null,
|
|
145
181
|
layoutModules: opts.interceptLayouts || null,
|
|
182
|
+
layoutSegments: opts.interceptLayoutSegments ?? null,
|
|
146
183
|
pageModule: opts.interceptPage,
|
|
147
184
|
params: opts.interceptParams || routeParams
|
|
148
185
|
};
|
|
@@ -1,31 +1,45 @@
|
|
|
1
1
|
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
2
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
3
|
+
import { ThenableParamsObserver } from "../shims/thenable-params.js";
|
|
3
4
|
import { Metadata, Viewport } from "../shims/metadata.js";
|
|
5
|
+
import { applyFileBasedMetadata } from "./file-based-metadata.js";
|
|
4
6
|
|
|
5
7
|
//#region src/server/app-page-head.d.ts
|
|
6
8
|
type AppPageSearchParams = Record<string, string | string[]>;
|
|
7
9
|
type AppPageHeadModule = Record<string, unknown>;
|
|
10
|
+
type ApplyAppPageFileBasedMetadata = typeof applyFileBasedMetadata;
|
|
8
11
|
type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
12
|
+
layoutParams?: readonly AppPageParams[] | null;
|
|
9
13
|
layoutModule?: TModule | null;
|
|
10
14
|
layoutModules?: readonly (TModule | null | undefined)[] | null;
|
|
15
|
+
layoutTreePositions?: readonly number[] | null;
|
|
11
16
|
pageModule?: TModule | null;
|
|
12
17
|
params?: AppPageParams | null;
|
|
13
18
|
routeSegments?: readonly string[] | null;
|
|
14
19
|
};
|
|
15
20
|
type AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
21
|
+
configLayouts?: readonly (TModule | null | undefined)[] | null;
|
|
22
|
+
configLayoutTreePositions?: readonly number[] | null;
|
|
16
23
|
layout?: TModule | null;
|
|
24
|
+
layoutIndex?: number;
|
|
17
25
|
page?: TModule | null;
|
|
26
|
+
routeSegments?: readonly string[] | null;
|
|
18
27
|
};
|
|
19
28
|
type ResolveActiveParallelRouteHeadInputsOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
20
29
|
interceptLayouts?: readonly (TModule | null | undefined)[] | null;
|
|
30
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
31
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
21
32
|
interceptPage?: TModule | null;
|
|
22
33
|
interceptParams?: AppPageParams | null;
|
|
23
34
|
interceptSlotKey?: string | null;
|
|
35
|
+
layoutTreePositions?: readonly number[] | null;
|
|
24
36
|
params: AppPageParams;
|
|
25
37
|
routeSegments: readonly string[];
|
|
38
|
+
slotParams?: Readonly<Record<string, AppPageParams>> | null;
|
|
26
39
|
slots?: Record<string, AppPageHeadSlot<TModule>> | null;
|
|
27
40
|
};
|
|
28
41
|
type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
42
|
+
applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
|
|
29
43
|
/**
|
|
30
44
|
* Configured next.config `basePath`. Threaded into `applyFileBasedMetadata`
|
|
31
45
|
* so file-based metadata route URLs (icon, opengraph-image, manifest, ...)
|
|
@@ -43,6 +57,7 @@ type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadMo
|
|
|
43
57
|
routePath: string;
|
|
44
58
|
routeSegments?: readonly string[] | null;
|
|
45
59
|
searchParams?: URLSearchParams | null;
|
|
60
|
+
searchParamsObserver?: ThenableParamsObserver;
|
|
46
61
|
};
|
|
47
62
|
type ResolveAppPageHeadResult = {
|
|
48
63
|
hasDynamicMetadata: boolean;
|
|
@@ -59,4 +74,4 @@ declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHea
|
|
|
59
74
|
declare function collectAppPageSearchParams(searchParams: URLSearchParams | null | undefined): AppPageSearchParamsCollection;
|
|
60
75
|
declare function resolveAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): Promise<ResolveAppPageHeadResult>;
|
|
61
76
|
//#endregion
|
|
62
|
-
export { AppPageSearchParams, collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
77
|
+
export { AppPageSearchParams, ApplyAppPageFileBasedMetadata, collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { runWithFetchDedupe } from "../shims/fetch-cache.js";
|
|
2
2
|
import { mergeMetadataEntries, mergeViewport, postProcessMetadata, resolveModuleMetadata as resolveModuleMetadata$1, resolveModuleViewport } from "../shims/metadata.js";
|
|
3
|
-
import { resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
3
|
+
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
4
4
|
import { tagAppPageMetadataError } from "./app-page-execution.js";
|
|
5
5
|
//#region src/server/app-page-head.ts
|
|
6
6
|
/**
|
|
@@ -24,23 +24,44 @@ async function resolveModuleMetadata(...args) {
|
|
|
24
24
|
}
|
|
25
25
|
function resolveActiveParallelRouteHeadInputs(options) {
|
|
26
26
|
return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const ownerTreePosition = options.layoutTreePositions?.[slot.layoutIndex ?? 0] ?? 0;
|
|
28
|
+
const ownerParams = resolveAppPageSegmentParams(options.routeSegments, ownerTreePosition, options.params);
|
|
29
|
+
if (options.interceptSlotKey === slotKey && options.interceptPage) {
|
|
30
|
+
const interceptLayouts = options.interceptLayouts ?? [];
|
|
31
|
+
return {
|
|
32
|
+
layoutModules: [slot.layout, ...interceptLayouts].filter(isPresent),
|
|
33
|
+
layoutParams: [...slot.layout ? [ownerParams] : [], ...interceptLayouts.filter(isPresent).map((_, index) => {
|
|
34
|
+
const segments = options.interceptLayoutSegments?.[index] ?? [];
|
|
35
|
+
return {
|
|
36
|
+
...ownerParams,
|
|
37
|
+
...resolveParallelLayoutParams(options.interceptBranchSegments ?? segments, segments.length, options.interceptParams ?? options.params)
|
|
38
|
+
};
|
|
39
|
+
})],
|
|
40
|
+
layoutTreePositions: [...slot.layout ? [0] : [], ...interceptLayouts.filter(isPresent).map(() => options.routeSegments.length)],
|
|
41
|
+
pageModule: options.interceptPage,
|
|
42
|
+
params: options.interceptParams ?? options.params,
|
|
43
|
+
routeSegments: options.routeSegments
|
|
44
|
+
};
|
|
45
|
+
}
|
|
33
46
|
return {
|
|
34
|
-
layoutModules: slot.layout
|
|
47
|
+
layoutModules: [slot.layout, ...slot.configLayouts ?? []].filter(isPresent),
|
|
48
|
+
layoutParams: [...slot.layout ? [ownerParams] : [], ...(slot.configLayoutTreePositions ?? []).map((treePosition) => ({
|
|
49
|
+
...ownerParams,
|
|
50
|
+
...resolveParallelLayoutParams(slot.routeSegments ?? options.routeSegments, treePosition, options.slotParams?.[slotKey] ?? options.params)
|
|
51
|
+
}))],
|
|
52
|
+
layoutTreePositions: [...slot.layout ? [0] : [], ...slot.configLayoutTreePositions ?? []],
|
|
35
53
|
pageModule: slot.page,
|
|
36
|
-
params: options.params,
|
|
37
|
-
routeSegments: options.routeSegments
|
|
54
|
+
params: options.slotParams?.[slotKey] ?? options.params,
|
|
55
|
+
routeSegments: slot.routeSegments ?? options.routeSegments
|
|
38
56
|
};
|
|
39
57
|
});
|
|
40
58
|
}
|
|
41
59
|
function isPresent(value) {
|
|
42
60
|
return value !== null && value !== void 0;
|
|
43
61
|
}
|
|
62
|
+
function resolveParallelLayoutParams(routeSegments, treePosition, params) {
|
|
63
|
+
return resolveAppPageBranchParams(routeSegments, treePosition, params);
|
|
64
|
+
}
|
|
44
65
|
function hasGenerateMetadata(module) {
|
|
45
66
|
return typeof module?.generateMetadata === "function";
|
|
46
67
|
}
|
|
@@ -111,7 +132,7 @@ async function resolveLayoutViewport(layoutInputs, params, routeSegments) {
|
|
|
111
132
|
return resolveModuleViewport(layoutInput.module, layoutParams);
|
|
112
133
|
}));
|
|
113
134
|
}
|
|
114
|
-
async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent) {
|
|
135
|
+
async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent, searchParamsObserver) {
|
|
115
136
|
const params = parallelRoute.params ?? fallbackParams;
|
|
116
137
|
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
117
138
|
const metadataResults = [];
|
|
@@ -119,13 +140,15 @@ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackR
|
|
|
119
140
|
const metadataSources = [];
|
|
120
141
|
let accumulatedMetadata = parent;
|
|
121
142
|
const layoutModules = [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
|
|
143
|
+
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
144
|
+
const layoutParams = parallelRoute.layoutParams ?? [];
|
|
122
145
|
const hasDynamicMetadata = layoutModules.some(hasGenerateMetadata) || hasGenerateMetadata(parallelRoute.pageModule);
|
|
123
|
-
const layoutViewportPromises = layoutModules.map((layoutModule) => resolveModuleViewport(layoutModule, params));
|
|
124
|
-
const pageViewportPromise = parallelRoute.pageModule ? resolveModuleViewport(parallelRoute.pageModule, params) : Promise.resolve(null);
|
|
146
|
+
const layoutViewportPromises = layoutModules.map((layoutModule, index) => resolveModuleViewport(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params)));
|
|
147
|
+
const pageViewportPromise = parallelRoute.pageModule ? resolveModuleViewport(parallelRoute.pageModule, params, pageSearchParams, searchParamsObserver) : Promise.resolve(null);
|
|
125
148
|
for (const layoutViewportPromise of layoutViewportPromises) layoutViewportPromise.catch(() => null);
|
|
126
149
|
pageViewportPromise.catch(() => null);
|
|
127
|
-
for (const layoutModule of layoutModules) {
|
|
128
|
-
const layoutMetadata = await resolveModuleMetadata(layoutModule, params, void 0, accumulatedMetadata);
|
|
150
|
+
for (const [index, layoutModule] of layoutModules.entries()) {
|
|
151
|
+
const layoutMetadata = await resolveModuleMetadata(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params), void 0, accumulatedMetadata);
|
|
129
152
|
metadataResults.push(layoutMetadata);
|
|
130
153
|
metadataSources.push({
|
|
131
154
|
metadata: layoutMetadata,
|
|
@@ -137,7 +160,7 @@ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackR
|
|
|
137
160
|
}
|
|
138
161
|
}
|
|
139
162
|
if (parallelRoute.pageModule) {
|
|
140
|
-
const pageMetadata = await resolveModuleMetadata(parallelRoute.pageModule, params, pageSearchParams, accumulatedMetadata);
|
|
163
|
+
const pageMetadata = await resolveModuleMetadata(parallelRoute.pageModule, params, pageSearchParams, accumulatedMetadata, searchParamsObserver);
|
|
141
164
|
metadataResults.push(pageMetadata);
|
|
142
165
|
metadataSources.push({
|
|
143
166
|
metadata: pageMetadata,
|
|
@@ -170,9 +193,9 @@ async function resolveAppPageHeadInner(options) {
|
|
|
170
193
|
layoutMetadataResultsForParent.catch(() => null);
|
|
171
194
|
const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) => metadataResults.length > 0 ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata }))) : {});
|
|
172
195
|
pageParentPromise.catch(() => null);
|
|
173
|
-
const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise) : Promise.resolve(null);
|
|
174
|
-
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params) : Promise.resolve(null);
|
|
175
|
-
const parallelRouteHeadPromise = Promise.all((options.parallelRoutes ?? []).map((parallelRoute) => resolveParallelRouteHead(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise)));
|
|
196
|
+
const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise, options.searchParamsObserver) : Promise.resolve(null);
|
|
197
|
+
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params, pageSearchParams, options.searchParamsObserver) : Promise.resolve(null);
|
|
198
|
+
const parallelRouteHeadPromise = Promise.all((options.parallelRoutes ?? []).map((parallelRoute) => resolveParallelRouteHead(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise, options.searchParamsObserver)));
|
|
176
199
|
const [layoutMetadataResults, layoutViewportResults, pageMetadata, pageViewport, parallelRouteHeads] = await Promise.all([
|
|
177
200
|
layoutMetadataPromise,
|
|
178
201
|
layoutViewportPromise,
|
|
@@ -205,9 +228,8 @@ async function resolveAppPageHeadInner(options) {
|
|
|
205
228
|
const metadataSources = createMetadataSources(layoutMetadataResults, routeSegments, layoutSourcePositions, pageMetadata, Boolean(options.pageModule));
|
|
206
229
|
metadataSources.push(...parallelMetadataSources);
|
|
207
230
|
let metadata = resolvedMetadataBase;
|
|
208
|
-
if (options.metadataRoutes.length > 0) try {
|
|
209
|
-
|
|
210
|
-
metadata = await applyFileBasedMetadata(resolvedMetadataBase, options.routePath, options.params, options.metadataRoutes, {
|
|
231
|
+
if (options.applyFileBasedMetadata && options.metadataRoutes.length > 0) try {
|
|
232
|
+
metadata = await options.applyFileBasedMetadata(resolvedMetadataBase, options.routePath, options.params, options.metadataRoutes, {
|
|
211
233
|
routeSegments,
|
|
212
234
|
metadataSources,
|
|
213
235
|
basePath: options.basePath ?? ""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { methodNotAllowedResponse } from "./http-error-responses.js";
|
|
2
2
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
3
|
-
import { isPossibleAppRouteActionRequest } from "./app-
|
|
3
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
4
4
|
//#region src/server/app-page-method.ts
|
|
5
5
|
function isNonGetOrHead(method) {
|
|
6
6
|
const normalizedMethod = method.toUpperCase();
|
|
@@ -4,5 +4,6 @@ import { AppPageParams } from "./app-page-boundary.js";
|
|
|
4
4
|
declare function getAppPageSegmentParamName(segment: string): string | null;
|
|
5
5
|
declare function resolveAppPageSegmentParamScopeKeys(routeSegments: readonly string[] | null | undefined, treePosition: number): readonly string[];
|
|
6
6
|
declare function resolveAppPageSegmentParams(routeSegments: readonly string[] | null | undefined, treePosition: number, matchedParams: AppPageParams): AppPageParams;
|
|
7
|
+
declare function resolveAppPageBranchParams(branchSegments: readonly string[], treePosition: number, matchedParams: AppPageParams, scopedSegments?: readonly string[]): AppPageParams;
|
|
7
8
|
//#endregion
|
|
8
|
-
export { getAppPageSegmentParamName, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
|
|
9
|
+
export { getAppPageSegmentParamName, resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
|
|
@@ -35,5 +35,12 @@ function resolveAppPageSegmentParams(routeSegments, treePosition, matchedParams)
|
|
|
35
35
|
}
|
|
36
36
|
return segmentParams;
|
|
37
37
|
}
|
|
38
|
+
function resolveAppPageBranchParams(branchSegments, treePosition, matchedParams, scopedSegments = branchSegments) {
|
|
39
|
+
const branchParamNames = new Set(branchSegments.map(getAppPageSegmentParamName).filter((name) => name !== null));
|
|
40
|
+
const scopedParams = {};
|
|
41
|
+
for (const [name, value] of Object.entries(matchedParams)) if (!branchParamNames.has(name)) scopedParams[name] = value;
|
|
42
|
+
Object.assign(scopedParams, resolveAppPageSegmentParams(scopedSegments, treePosition, matchedParams));
|
|
43
|
+
return scopedParams;
|
|
44
|
+
}
|
|
38
45
|
//#endregion
|
|
39
|
-
export { getAppPageSegmentParamName, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
|
|
46
|
+
export { getAppPageSegmentParamName, resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createAppPprFallbackShells } from "./app-ppr-fallback-shell.js";
|
|
2
|
+
import { AppPageDispatchRoute, AppPagePprRuntime } from "./app-page-dispatch.js";
|
|
3
|
+
|
|
4
|
+
//#region src/server/app-page-ppr-runtime.d.ts
|
|
5
|
+
declare const appPagePprRuntime: AppPagePprRuntime<AppPageDispatchRoute>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { appPagePprRuntime, createAppPprFallbackShells };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { beginPprFallbackShellFinalRender, createPprFallbackShellState, getPprFallbackShellState, runWithPprFallbackShellState } from "../shims/ppr-fallback-shell.js";
|
|
2
|
+
import { createAppPprFallbackShells } from "./app-ppr-fallback-shell.js";
|
|
3
|
+
import { hasSearchParams, shouldReadAppPageCache } from "./app-page-dispatch.js";
|
|
4
|
+
//#region src/server/app-page-ppr-runtime.ts
|
|
5
|
+
function classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
|
|
6
|
+
if (options.renderedConcreteUrlPaths?.has(options.cleanPathname) === true) return { kind: "skip-known-pregenerated-route" };
|
|
7
|
+
const fallbackShells = options.pprFallbackCacheShells;
|
|
8
|
+
if (!fallbackShells || fallbackShells.length === 0) return { kind: "skip-no-fallback-shells" };
|
|
9
|
+
if (options.isRscRequest) return { kind: "skip-rsc-request" };
|
|
10
|
+
if (options.request.method !== "GET") return { kind: "skip-non-get" };
|
|
11
|
+
if (!isForceStatic && hasSearchParams(options.searchParams)) return { kind: "skip-search-params" };
|
|
12
|
+
if (!shouldReadAppPageCache({
|
|
13
|
+
isDraftMode,
|
|
14
|
+
isForceDynamic,
|
|
15
|
+
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
16
|
+
isProduction: options.isProduction,
|
|
17
|
+
isRscRequest: false,
|
|
18
|
+
revalidateSeconds: currentRevalidateSeconds,
|
|
19
|
+
scriptNonce: options.scriptNonce
|
|
20
|
+
})) return { kind: "skip-cache-disabled" };
|
|
21
|
+
return {
|
|
22
|
+
kind: "probe-fallback-shells",
|
|
23
|
+
fallbackShells
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function probePprFallbackShellCache(options, fallbackShells, currentRevalidateSeconds) {
|
|
27
|
+
const { readAppPageFallbackShellCacheResponse } = await import("./app-page-cache.js");
|
|
28
|
+
const { rewriteAppPprFallbackShellHtmlNavigation } = await import("./app-ppr-fallback-shell.js");
|
|
29
|
+
for (const fallbackShell of fallbackShells) {
|
|
30
|
+
const fallbackShellResponse = await readAppPageFallbackShellCacheResponse({
|
|
31
|
+
clearRequestContext: options.clearRequestContext,
|
|
32
|
+
expireSeconds: options.expireSeconds,
|
|
33
|
+
fallbackPathname: fallbackShell.pathname,
|
|
34
|
+
isEdgeRuntime: options.isEdgeRuntime,
|
|
35
|
+
isrDebug: options.isrDebug,
|
|
36
|
+
isrGet: options.isrGet,
|
|
37
|
+
isrHtmlKey: options.isrHtmlKey,
|
|
38
|
+
middlewareHeaders: options.middlewareContext.headers,
|
|
39
|
+
middlewareStatus: options.middlewareContext.status,
|
|
40
|
+
revalidateSeconds: currentRevalidateSeconds ?? 0,
|
|
41
|
+
rewriteHtml(html) {
|
|
42
|
+
return rewriteAppPprFallbackShellHtmlNavigation({
|
|
43
|
+
html,
|
|
44
|
+
params: options.params,
|
|
45
|
+
pathname: options.cleanPathname,
|
|
46
|
+
searchParams: options.searchParams
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
if (fallbackShellResponse) return fallbackShellResponse;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const appPagePprRuntime = {
|
|
55
|
+
beginFinalRender: beginPprFallbackShellFinalRender,
|
|
56
|
+
getState: getPprFallbackShellState,
|
|
57
|
+
run(shell, fn) {
|
|
58
|
+
return runWithPprFallbackShellState(createPprFallbackShellState(shell), fn);
|
|
59
|
+
},
|
|
60
|
+
async tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
|
|
61
|
+
const decision = classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic);
|
|
62
|
+
return decision.kind === "probe-fallback-shells" ? probePprFallbackShellCache(options, decision.fallbackShells, currentRevalidateSeconds) : null;
|
|
63
|
+
},
|
|
64
|
+
async warm(options) {
|
|
65
|
+
const { warmPprFallbackShellCaches } = await import("./app-ppr-fallback-shell-render.js");
|
|
66
|
+
await warmPprFallbackShellCaches(options);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
export { appPagePprRuntime, createAppPprFallbackShells };
|
|
@@ -119,6 +119,7 @@ type ProbeAppPageBeforeRenderResult = {
|
|
|
119
119
|
};
|
|
120
120
|
type ProbeAppPageBeforeRenderOptions = {
|
|
121
121
|
hasLoadingBoundary: boolean;
|
|
122
|
+
probePageBeforeRender?: boolean;
|
|
122
123
|
skipProbes?: boolean;
|
|
123
124
|
layoutCount: number;
|
|
124
125
|
probeLayoutAt: (layoutIndex: number) => unknown;
|
|
@@ -252,7 +252,7 @@ async function probeAppPageBeforeRender(options) {
|
|
|
252
252
|
layoutFlags
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
|
-
if (options.hasLoadingBoundary) return {
|
|
255
|
+
if (options.hasLoadingBoundary || options.probePageBeforeRender === false) return {
|
|
256
256
|
response: null,
|
|
257
257
|
layoutFlags
|
|
258
258
|
};
|
|
@@ -37,6 +37,7 @@ type RenderAppPageLifecycleOptions = {
|
|
|
37
37
|
cleanPathname: string;
|
|
38
38
|
clearRequestContext: () => void;
|
|
39
39
|
consumeDynamicUsage: () => boolean;
|
|
40
|
+
peekDynamicUsage?: () => boolean;
|
|
40
41
|
consumeRenderObservationState?: () => AppPageRenderObservationState; /** Read and clear any invalid dynamic usage error recorded during render (dev-only). */
|
|
41
42
|
consumeInvalidDynamicUsageError?: () => unknown;
|
|
42
43
|
createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;
|
|
@@ -60,6 +61,8 @@ type RenderAppPageLifecycleOptions = {
|
|
|
60
61
|
isProgressiveActionRender?: boolean;
|
|
61
62
|
isPrerender?: boolean;
|
|
62
63
|
isProduction: boolean;
|
|
64
|
+
probePageBeforeRender?: boolean;
|
|
65
|
+
omitPendingDynamicCacheState?: boolean;
|
|
63
66
|
isRscRequest: boolean;
|
|
64
67
|
isrDebug?: AppPageDebugLogger;
|
|
65
68
|
isrHtmlKey: (pathname: string) => string;
|
|
@@ -81,7 +84,7 @@ type RenderAppPageLifecycleOptions = {
|
|
|
81
84
|
expireSeconds?: number;
|
|
82
85
|
formState?: ReactFormState | null;
|
|
83
86
|
revalidateSeconds: number | null;
|
|
84
|
-
renderErrorBoundaryResponse: (error: unknown) => Promise<Response | null>;
|
|
87
|
+
renderErrorBoundaryResponse: (error: unknown, errorOrigin: "rsc" | "ssr") => Promise<Response | null>;
|
|
85
88
|
renderLayoutSpecialError: (specialError: AppPageSpecialError, layoutIndex: number) => Promise<Response>;
|
|
86
89
|
renderPageSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;
|
|
87
90
|
renderToReadableStream: (element: ReactNode | AppOutgoingElements, options: {
|
|
@@ -248,8 +248,11 @@ function wrapRscResponseForDevErrorReporting(response, consumeInvalidDynamicUsag
|
|
|
248
248
|
});
|
|
249
249
|
}
|
|
250
250
|
async function renderAppPageLifecycle(options) {
|
|
251
|
+
const configuredProbePageBeforeRender = options.probePageBeforeRender ?? options.isRscRequest;
|
|
252
|
+
const probePageBeforeRender = options.isRscRequest || configuredProbePageBeforeRender && !(options.peekDynamicUsage?.() ?? false);
|
|
251
253
|
const preRenderResult = await probeAppPageBeforeRender({
|
|
252
254
|
hasLoadingBoundary: options.hasLoadingBoundary,
|
|
255
|
+
probePageBeforeRender,
|
|
253
256
|
skipProbes: options.pprFallbackShellSignal !== void 0,
|
|
254
257
|
layoutCount: options.layoutCount,
|
|
255
258
|
probeLayoutAt(layoutIndex) {
|
|
@@ -430,7 +433,8 @@ async function renderAppPageLifecycle(options) {
|
|
|
430
433
|
if (!options.isProduction) renderEnd = performance.now();
|
|
431
434
|
},
|
|
432
435
|
renderErrorBoundaryResponse(error) {
|
|
433
|
-
|
|
436
|
+
const capturedRscError = rscErrorTracker.getCapturedError();
|
|
437
|
+
return options.renderErrorBoundaryResponse(capturedRscError ?? error, capturedRscError === null ? "ssr" : "rsc");
|
|
434
438
|
},
|
|
435
439
|
async renderHtmlStream() {
|
|
436
440
|
const ssrHandler = await options.loadSsrHandler();
|
|
@@ -462,7 +466,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
462
466
|
if (!htmlStream) throw new Error("[vinext] Expected an HTML stream when no fallback response was returned");
|
|
463
467
|
const linkHeader = buildAppPageLinkHeader(htmlRender.linkHeader, fontLinkHeader, options.reactMaxHeadersLength);
|
|
464
468
|
if (options.isPrerender === true) await htmlRender.metadataReady;
|
|
465
|
-
if (options.hasLoadingBoundary) {
|
|
469
|
+
if (options.hasLoadingBoundary || !probePageBeforeRender) {
|
|
466
470
|
const captured = rscErrorTracker.getCapturedSpecialError();
|
|
467
471
|
if (captured) {
|
|
468
472
|
const specialError = resolveAppPageSpecialError(captured);
|
|
@@ -480,8 +484,8 @@ async function renderAppPageLifecycle(options) {
|
|
|
480
484
|
revalidateSeconds
|
|
481
485
|
}));
|
|
482
486
|
}
|
|
487
|
+
let dynamicUsedDuringRender = options.consumeDynamicUsage();
|
|
483
488
|
const draftCookie = options.getDraftModeCookieHeader();
|
|
484
|
-
const dynamicUsedDuringRender = options.consumeDynamicUsage();
|
|
485
489
|
let dynamicUsedBeforeContextCleanup = dynamicUsedDuringRender;
|
|
486
490
|
const safeHtmlStream = deferUntilStreamConsumed(htmlStream, () => {
|
|
487
491
|
dynamicUsedBeforeContextCleanup = dynamicUsedBeforeContextCleanup || options.consumeDynamicUsage();
|
|
@@ -575,6 +579,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
575
579
|
isrRscKey: options.isrRscKey,
|
|
576
580
|
isrSet: options.isrSet,
|
|
577
581
|
interceptionContext: options.interceptionContext,
|
|
582
|
+
omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
|
|
578
583
|
preserveClientResponseHeaders: !htmlResponsePolicy.shouldWriteToCache,
|
|
579
584
|
expireSeconds,
|
|
580
585
|
revalidateSeconds,
|
|
@@ -40,8 +40,11 @@ type BuildAppPageElementResult<TElement> = {
|
|
|
40
40
|
};
|
|
41
41
|
type AppPageInterceptMatch<TPage = unknown> = {
|
|
42
42
|
interceptLayouts?: readonly unknown[] | null;
|
|
43
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
44
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
43
45
|
__loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
|
|
44
46
|
matchedParams: AppPageParams;
|
|
47
|
+
sourceMatchedParams?: AppPageParams;
|
|
45
48
|
page: TPage;
|
|
46
49
|
__pageLoader?: (() => Promise<TPage>) | null;
|
|
47
50
|
__loadState?: {
|
|
@@ -88,7 +91,10 @@ type ResolveAppPageInterceptionRerenderTargetResult<TRoute, TInterceptOpts> = {
|
|
|
88
91
|
type ResolveAppPageActionRerenderTargetOptions<TRoute, TPage, TInterceptOpts> = ResolveAppPageInterceptionRerenderTargetOptions<TRoute, TPage, TInterceptOpts>;
|
|
89
92
|
type ResolveAppPageActionRerenderTargetResult<TRoute, TInterceptOpts> = ResolveAppPageInterceptionRerenderTargetResult<TRoute, TInterceptOpts>;
|
|
90
93
|
type ResolveAppPageInterceptOptions<TRoute, TPage, TInterceptOpts, TElement> = {
|
|
91
|
-
buildPageElement: (route: TRoute, params: AppPageParams, interceptOpts: TInterceptOpts | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker
|
|
94
|
+
buildPageElement: (route: TRoute, params: AppPageParams, interceptOpts: TInterceptOpts | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker, buildOptions?: {
|
|
95
|
+
observeMetadataSearchParamsAccess?: boolean;
|
|
96
|
+
observePageSearchParamsAccess?: boolean;
|
|
97
|
+
}) => Promise<TElement>;
|
|
92
98
|
cleanPathname: string;
|
|
93
99
|
currentRoute: TRoute;
|
|
94
100
|
findIntercept: (pathname: string) => AppPageInterceptMatch<TPage> | null;
|
|
@@ -98,6 +104,7 @@ type ResolveAppPageInterceptOptions<TRoute, TPage, TInterceptOpts, TElement> = {
|
|
|
98
104
|
layoutParamAccess?: AppLayoutParamAccessTracker;
|
|
99
105
|
resolveNavigationParams: (route: TRoute, params: AppPageParams, pathname: string, interceptOpts: TInterceptOpts) => AppPageParams;
|
|
100
106
|
renderInterceptResponse: (route: TRoute, element: TElement) => Promise<Response> | Response;
|
|
107
|
+
resolveSearchParams?: (route: TRoute, searchParams: URLSearchParams) => Awaitable<URLSearchParams>;
|
|
101
108
|
searchParams: URLSearchParams;
|
|
102
109
|
setNavigationContext: (context: {
|
|
103
110
|
params: AppPageParams;
|
|
@@ -97,7 +97,7 @@ async function resolveAppPageInterceptMatch(options) {
|
|
|
97
97
|
return {
|
|
98
98
|
interceptOpts: options.toInterceptOpts(interceptState.intercept),
|
|
99
99
|
matchedParams: interceptState.intercept.matchedParams,
|
|
100
|
-
sourceParams: pickRouteParams(interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
|
|
100
|
+
sourceParams: pickRouteParams(interceptState.intercept.sourceMatchedParams ?? interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
|
|
101
101
|
sourceRoute: interceptState.sourceRoute
|
|
102
102
|
};
|
|
103
103
|
}
|
|
@@ -145,12 +145,18 @@ async function resolveAppPageInterceptionRerenderTarget(options) {
|
|
|
145
145
|
isRscRequest: options.isRscRequest,
|
|
146
146
|
toInterceptOpts: options.toInterceptOpts
|
|
147
147
|
});
|
|
148
|
-
if (interceptState.kind === "source-route")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
if (interceptState.kind === "source-route") {
|
|
149
|
+
const sourceMatchedParams = interceptState.intercept.sourceMatchedParams ?? interceptState.intercept.matchedParams;
|
|
150
|
+
return {
|
|
151
|
+
interceptOpts: options.toInterceptOpts(interceptState.intercept),
|
|
152
|
+
navigationParams: {
|
|
153
|
+
...sourceMatchedParams,
|
|
154
|
+
...interceptState.intercept.matchedParams
|
|
155
|
+
},
|
|
156
|
+
params: pickRouteParams(sourceMatchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
|
|
157
|
+
route: interceptState.sourceRoute
|
|
158
|
+
};
|
|
159
|
+
}
|
|
154
160
|
return {
|
|
155
161
|
interceptOpts: interceptState.kind === "current-route" ? options.toInterceptOpts(interceptState.intercept) : void 0,
|
|
156
162
|
navigationParams: options.currentParams,
|
|
@@ -174,13 +180,19 @@ async function resolveAppPageIntercept(options) {
|
|
|
174
180
|
if (interceptState.kind === "source-route") {
|
|
175
181
|
const renderRoute = interceptState.sourceRoute;
|
|
176
182
|
const interceptOpts = options.toInterceptOpts(interceptState.intercept);
|
|
177
|
-
const
|
|
183
|
+
const sourceMatchedParams = interceptState.intercept.sourceMatchedParams ?? interceptState.intercept.matchedParams;
|
|
184
|
+
const navigationParams = {
|
|
185
|
+
...sourceMatchedParams,
|
|
186
|
+
...interceptState.intercept.matchedParams
|
|
187
|
+
};
|
|
188
|
+
const renderSearchParams = options.resolveSearchParams ? await options.resolveSearchParams(renderRoute, options.searchParams) : options.searchParams;
|
|
189
|
+
const renderParams = pickRouteParams(sourceMatchedParams, options.getRouteParamNames(interceptState.sourceRoute));
|
|
178
190
|
options.setNavigationContext({
|
|
179
|
-
params: options.resolveNavigationParams(renderRoute,
|
|
191
|
+
params: options.resolveNavigationParams(renderRoute, navigationParams, options.cleanPathname, interceptOpts),
|
|
180
192
|
pathname: options.cleanPathname,
|
|
181
|
-
searchParams:
|
|
193
|
+
searchParams: renderSearchParams
|
|
182
194
|
});
|
|
183
|
-
const interceptElement = await options.buildPageElement(renderRoute, renderParams, interceptOpts,
|
|
195
|
+
const interceptElement = await options.buildPageElement(renderRoute, renderParams, interceptOpts, renderSearchParams, options.layoutParamAccess);
|
|
184
196
|
return {
|
|
185
197
|
interceptOpts: void 0,
|
|
186
198
|
response: await options.renderInterceptResponse(renderRoute, interceptElement)
|