vinext 1.0.0-beta.1 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/build/client-build-config.js +1 -0
- package/dist/build/report.d.ts +8 -1
- package/dist/build/report.js +12 -2
- package/dist/check.js +15 -2
- package/dist/cli.js +3 -2
- package/dist/config/config-matchers.d.ts +13 -37
- package/dist/config/config-matchers.js +31 -121
- package/dist/config/next-config.d.ts +3 -2
- package/dist/config/next-config.js +3 -1
- package/dist/config/request-context.d.ts +14 -0
- package/dist/config/request-context.js +26 -0
- package/dist/entries/app-rsc-entry.js +27 -9
- package/dist/entries/app-rsc-manifest.js +17 -0
- package/dist/entries/pages-server-entry.js +3 -2
- package/dist/index.js +82 -58
- package/dist/init.d.ts +6 -4
- package/dist/init.js +20 -22
- package/dist/plugins/og-assets.js +1 -1
- package/dist/routing/app-route-graph.d.ts +13 -5
- package/dist/routing/app-route-graph.js +59 -13
- package/dist/routing/app-router.js +12 -6
- package/dist/routing/file-matcher.d.ts +11 -22
- package/dist/routing/file-matcher.js +21 -33
- package/dist/routing/pages-router.js +23 -29
- package/dist/routing/route-matching.d.ts +14 -1
- package/dist/routing/route-matching.js +13 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +7 -4
- package/dist/routing/route-trie.d.ts +5 -1
- package/dist/routing/route-trie.js +5 -2
- package/dist/server/app-browser-entry.js +7 -6
- package/dist/server/app-browser-history-controller.d.ts +1 -1
- package/dist/server/app-browser-history-controller.js +3 -3
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +3 -0
- package/dist/server/app-fallback-renderer.js +4 -2
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +12 -1
- package/dist/server/app-page-boundary-render.js +84 -2
- package/dist/server/app-page-cache-finalizer.d.ts +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-dispatch.d.ts +11 -2
- package/dist/server/app-page-dispatch.js +14 -17
- package/dist/server/app-page-element-builder.d.ts +7 -2
- package/dist/server/app-page-element-builder.js +112 -27
- package/dist/server/app-page-head.d.ts +54 -2
- package/dist/server/app-page-head.js +164 -78
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +106 -0
- package/dist/server/app-page-render.d.ts +2 -2
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-request.d.ts +12 -0
- package/dist/server/app-page-request.js +133 -13
- package/dist/server/app-page-route-wiring.d.ts +9 -0
- package/dist/server/app-page-route-wiring.js +43 -3
- package/dist/server/app-post-middleware-context.d.ts +1 -1
- package/dist/server/app-post-middleware-context.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +31 -17
- package/dist/server/app-route-handler-execution.d.ts +6 -1
- package/dist/server/app-route-handler-execution.js +42 -16
- package/dist/server/app-route-handler-policy.d.ts +2 -0
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-module-loader.d.ts +3 -1
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-rsc-cache-busting.d.ts +1 -1
- package/dist/server/app-rsc-errors.d.ts +1 -1
- package/dist/server/app-rsc-errors.js +12 -2
- package/dist/server/app-rsc-handler.d.ts +10 -5
- package/dist/server/app-rsc-handler.js +52 -24
- package/dist/server/app-rsc-request-normalization.d.ts +3 -2
- package/dist/server/app-rsc-request-normalization.js +8 -2
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
- package/dist/server/app-rsc-response-finalizer.js +5 -11
- package/dist/server/app-rsc-route-matching.d.ts +20 -0
- package/dist/server/app-rsc-route-matching.js +87 -11
- package/dist/server/app-segment-config.js +13 -3
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +9 -7
- package/dist/server/app-ssr-entry.js +2 -2
- package/dist/server/app-ssr-stream.d.ts +1 -7
- package/dist/server/app-ssr-stream.js +2 -10
- package/dist/server/config-headers.d.ts +24 -0
- package/dist/server/config-headers.js +52 -0
- package/dist/server/dev-initial-server-error.d.ts +1 -1
- package/dist/server/dev-server.js +29 -13
- package/dist/server/isr-cache.d.ts +1 -1
- package/dist/server/middleware-matcher-pattern.d.ts +22 -0
- package/dist/server/middleware-matcher-pattern.js +219 -0
- package/dist/server/middleware-matcher.d.ts +2 -7
- package/dist/server/middleware-matcher.js +13 -60
- package/dist/server/middleware-path-to-regexp.d.ts +14 -0
- package/dist/server/middleware-path-to-regexp.js +228 -0
- package/dist/server/middleware-runtime.js +4 -3
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +2 -1
- package/dist/server/pages-data-route.d.ts +11 -1
- package/dist/server/pages-data-route.js +16 -1
- package/dist/server/pages-get-initial-props.d.ts +15 -2
- package/dist/server/pages-get-initial-props.js +16 -6
- package/dist/server/pages-page-data.d.ts +3 -1
- package/dist/server/pages-page-data.js +16 -7
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +16 -17
- package/dist/server/pages-page-response.js +1 -1
- package/dist/server/pages-readiness.d.ts +3 -3
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +25 -11
- package/dist/server/pages-router-entry.js +6 -0
- package/dist/server/prerender-route-params.js +2 -2
- package/dist/server/prod-server.d.ts +1 -4
- package/dist/server/prod-server.js +36 -23
- package/dist/server/request-pipeline.d.ts +15 -29
- package/dist/server/request-pipeline.js +24 -59
- package/dist/server/rsc-stream-hints.js +122 -18
- package/dist/shims/app.d.ts +1 -1
- package/dist/shims/cache-request-state.d.ts +27 -1
- package/dist/shims/cache-request-state.js +60 -1
- package/dist/shims/cache-runtime.d.ts +12 -1
- package/dist/shims/cache-runtime.js +22 -7
- package/dist/shims/cache.d.ts +5 -5
- package/dist/shims/cache.js +26 -10
- package/dist/shims/document.d.ts +42 -83
- package/dist/shims/document.js +62 -53
- package/dist/shims/dynamic.d.ts +5 -25
- package/dist/shims/dynamic.js +29 -8
- package/dist/shims/error.d.ts +1 -1
- package/dist/shims/error.js +1 -1
- package/dist/shims/fetch-cache.js +12 -3
- package/dist/shims/font-google-base.d.ts +11 -4
- package/dist/shims/font-local.d.ts +10 -3
- package/dist/shims/head.d.ts +13 -2
- package/dist/shims/head.js +3 -3
- package/dist/shims/headers.d.ts +28 -31
- package/dist/shims/headers.js +109 -49
- package/dist/shims/image.d.ts +27 -37
- package/dist/shims/image.js +21 -14
- package/dist/shims/internal/cookie-serialize.d.ts +3 -1
- package/dist/shims/internal/cookie-serialize.js +3 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
- package/dist/shims/internal/utils.d.ts +3 -3
- package/dist/shims/legacy-image.d.ts +3 -37
- package/dist/shims/legacy-image.js +6 -16
- package/dist/shims/link.d.ts +15 -22
- package/dist/shims/link.js +20 -11
- package/dist/shims/navigation-context-state.d.ts +1 -1
- package/dist/shims/navigation.d.ts +7 -3
- package/dist/shims/navigation.js +24 -13
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/next-shims-augmentations.d.ts +1 -0
- package/dist/shims/next-shims-public.d.ts +1 -0
- package/dist/shims/public-shim-map.json.js +103 -0
- package/dist/shims/readonly-url-search-params.d.ts +3 -3
- package/dist/shims/readonly-url-search-params.js +3 -3
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router.d.ts +55 -21
- package/dist/shims/router.js +162 -37
- package/dist/shims/script.d.ts +6 -10
- package/dist/shims/script.js +6 -3
- package/dist/shims/server.d.ts +45 -22
- package/dist/shims/server.js +44 -5
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/url-safety.d.ts +1 -1
- package/dist/shims/url-safety.js +2 -2
- package/dist/typegen.d.ts +8 -2
- package/dist/typegen.js +76 -15
- package/dist/utils/domain-locale.d.ts +2 -2
- package/dist/utils/external-url.d.ts +5 -0
- package/dist/utils/external-url.js +7 -0
- package/dist/utils/regex-safety.d.ts +8 -0
- package/dist/utils/regex-safety.js +737 -0
- package/package.json +13 -2
|
@@ -4,13 +4,17 @@ import "./app-elements.js";
|
|
|
4
4
|
import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
5
5
|
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
6
6
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
7
|
-
import { resolveAppPageBranchParams } from "./app-page-params.js";
|
|
8
|
-
import {
|
|
7
|
+
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
8
|
+
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
9
|
+
import { prepareAppPageHead, resolveActiveParallelRouteHeadInputs } from "./app-page-head.js";
|
|
9
10
|
import { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
10
11
|
import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath } from "./app-page-route-wiring.js";
|
|
12
|
+
import { resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport } from "./app-page-http-access-fallback-metadata.js";
|
|
13
|
+
import "./app-rsc-route-matching.js";
|
|
14
|
+
import { resolveAppPageParentHttpAccessBoundary } from "./app-page-boundary.js";
|
|
15
|
+
import { sanitizeErrorForClient } from "./app-rsc-errors.js";
|
|
11
16
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
12
17
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
13
|
-
import "./app-rsc-route-matching.js";
|
|
14
18
|
import { createElement } from "react";
|
|
15
19
|
//#region src/server/app-page-element-builder.ts
|
|
16
20
|
function resolveInterceptLayoutParams(branchSegments, layoutSegments, params) {
|
|
@@ -41,7 +45,7 @@ function isReactOwnedPageComponent(component) {
|
|
|
41
45
|
async function buildPageElements(options) {
|
|
42
46
|
const { route, params, routePath, displayPathname = routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
|
|
43
47
|
const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
|
|
44
|
-
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, serveStreamingMetadata } = pageRequest;
|
|
48
|
+
const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, serveStreamingMetadata, isProduction = process.env.NODE_ENV === "production" } = pageRequest;
|
|
45
49
|
const pageModule = route.page;
|
|
46
50
|
const isSiblingIntercept = opts?.interceptSlotKey === "__vinext_page_intercept" && !!opts?.interceptPage;
|
|
47
51
|
const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
|
|
@@ -76,38 +80,116 @@ async function buildPageElements(options) {
|
|
|
76
80
|
[renderIdentity.routeId]: createElement("div", null, "Page has no default export")
|
|
77
81
|
};
|
|
78
82
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
const activeParallelRouteHeadInputs = resolveActiveParallelRouteHeadInputs({
|
|
84
|
+
interceptBranchSegments: opts?.interceptBranchSegments ?? null,
|
|
85
|
+
interceptLayouts: opts?.interceptLayouts ?? null,
|
|
86
|
+
interceptLayoutSegments: opts?.interceptLayoutSegments ?? null,
|
|
87
|
+
interceptNotFoundBranchSegments: opts?.interceptNotFoundBranchSegments ?? null,
|
|
88
|
+
interceptNotFound: opts?.interceptNotFound ?? null,
|
|
89
|
+
interceptNotFoundTreePosition: opts?.interceptNotFoundTreePosition ?? null,
|
|
90
|
+
interceptPage: opts?.interceptPage ?? null,
|
|
91
|
+
interceptParams: opts?.interceptParams ?? null,
|
|
92
|
+
interceptSlotKey: opts?.interceptSlotKey ?? null,
|
|
93
|
+
interceptSourcePageSegments: opts?.interceptSourcePageSegments ?? null,
|
|
83
94
|
layoutTreePositions: route.layoutTreePositions,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
interceptParams: opts?.interceptParams ?? null,
|
|
92
|
-
interceptSlotKey: opts?.interceptSlotKey ?? null,
|
|
93
|
-
layoutTreePositions: route.layoutTreePositions,
|
|
94
|
-
params,
|
|
95
|
-
routeSegments: route.routeSegments ?? [],
|
|
96
|
-
slotParams: slotParamOverrides,
|
|
97
|
-
slots: route.slots ?? null
|
|
98
|
-
}), ...isSiblingIntercept ? [{
|
|
95
|
+
params,
|
|
96
|
+
routeSegments: route.routeSegments ?? [],
|
|
97
|
+
slotParams: slotParamOverrides,
|
|
98
|
+
slots: route.slots ?? null
|
|
99
|
+
});
|
|
100
|
+
const primaryParallelRouteHeadInput = isSiblingIntercept ? {
|
|
101
|
+
head: {
|
|
99
102
|
layoutModules: opts?.interceptLayouts ?? [],
|
|
100
103
|
layoutParams: (opts?.interceptLayoutSegments ?? []).map((segments) => resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? segments, segments, effectiveParams)),
|
|
101
104
|
pageModule: effectivePageModule ?? null,
|
|
102
105
|
params: effectiveParams,
|
|
103
106
|
routeSegments: opts?.interceptSourcePageSegments ?? route.routeSegments ?? []
|
|
104
|
-
}
|
|
107
|
+
},
|
|
108
|
+
...opts?.interceptNotFound ? {
|
|
109
|
+
notFoundModule: opts.interceptNotFound,
|
|
110
|
+
notFoundParams: resolveAppPageBranchParams(opts.interceptNotFoundBranchSegments ?? opts.interceptBranchSegments ?? route.routeSegments ?? [], opts.interceptNotFoundTreePosition ?? 0, effectiveParams)
|
|
111
|
+
} : {},
|
|
112
|
+
ownerTreePosition: route.routeSegments?.length ?? 0
|
|
113
|
+
} : null;
|
|
114
|
+
const parallelRoutes = [...activeParallelRouteHeadInputs.map((input) => input.head), ...primaryParallelRouteHeadInput ? [primaryParallelRouteHeadInput.head] : []];
|
|
115
|
+
const metadataSearchParamsObserver = observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0;
|
|
116
|
+
const preparedHead = prepareAppPageHead({
|
|
117
|
+
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
118
|
+
basePath: options.basePath ?? "",
|
|
119
|
+
layoutModules: route.layouts,
|
|
120
|
+
layoutTreePositions: route.layoutTreePositions,
|
|
121
|
+
metadataRoutes,
|
|
122
|
+
pageModule: isSiblingIntercept ? null : effectivePageModule ?? null,
|
|
123
|
+
parallelRoutes,
|
|
105
124
|
params: effectiveParams,
|
|
106
125
|
routePath: route.pattern,
|
|
107
126
|
routeSegments: route.routeSegments ?? null,
|
|
108
127
|
searchParams,
|
|
109
|
-
searchParamsObserver:
|
|
128
|
+
searchParamsObserver: metadataSearchParamsObserver
|
|
110
129
|
});
|
|
130
|
+
const { hasDynamicMetadata, pageSearchParams } = preparedHead;
|
|
131
|
+
const streamGeneratedHead = serveStreamingMetadata ?? shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots);
|
|
132
|
+
const metadataPlacement = hasDynamicMetadata && streamGeneratedHead ? "body" : "head";
|
|
133
|
+
const shouldDeferMetadata = metadataPlacement === "body";
|
|
134
|
+
const streamingMetadata = shouldDeferMetadata ? isProduction ? preparedHead.metadata.catch((error) => {
|
|
135
|
+
throw sanitizeErrorForClient(error, "production");
|
|
136
|
+
}) : preparedHead.metadata : null;
|
|
137
|
+
streamingMetadata?.catch(() => null);
|
|
138
|
+
const resolveNotFoundFallbackPlanOptions = () => {
|
|
139
|
+
const routeBoundaryModule = route.notFound;
|
|
140
|
+
const parentBoundary = resolveAppPageParentHttpAccessBoundary({
|
|
141
|
+
layoutIndex: route.layouts.length,
|
|
142
|
+
rootForbiddenModule,
|
|
143
|
+
rootNotFoundModule,
|
|
144
|
+
rootUnauthorizedModule,
|
|
145
|
+
routeForbiddenModules: route.forbiddens,
|
|
146
|
+
routeNotFoundModules: route.notFounds,
|
|
147
|
+
routeUnauthorizedModules: route.unauthorizeds,
|
|
148
|
+
statusCode: 404
|
|
149
|
+
});
|
|
150
|
+
const boundaryModule = routeBoundaryModule ?? parentBoundary.module;
|
|
151
|
+
const boundaryTreePosition = routeBoundaryModule ? route.notFoundTreePosition : parentBoundary.layoutIndex === null ? null : route.layoutTreePositions?.[parentBoundary.layoutIndex];
|
|
152
|
+
return {
|
|
153
|
+
boundaryModule,
|
|
154
|
+
boundaryParams: boundaryModule && boundaryTreePosition != null ? resolveAppPageSegmentParams(route.routeSegments ?? [], boundaryTreePosition, effectiveParams) : {},
|
|
155
|
+
layoutModules: route.layouts,
|
|
156
|
+
layoutTreePositions: route.layoutTreePositions,
|
|
157
|
+
parallelBranches: activeParallelRouteHeadInputs,
|
|
158
|
+
params: effectiveParams,
|
|
159
|
+
primaryParallelBranch: primaryParallelRouteHeadInput,
|
|
160
|
+
routeSegments: route.routeSegments ?? null
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
let viewportErrorOutlet = null;
|
|
164
|
+
let metadataErrorOutlet = null;
|
|
165
|
+
const resolveMetadataErrorTags = async (error) => {
|
|
166
|
+
if (resolveAppPageSpecialError(error)?.kind !== "http-access-fallback") return null;
|
|
167
|
+
return resolveHttpAccessFallbackMetadata({
|
|
168
|
+
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
169
|
+
basePath: options.basePath ?? "",
|
|
170
|
+
...resolveNotFoundFallbackPlanOptions(),
|
|
171
|
+
metadataRoutes,
|
|
172
|
+
routePath: route.pattern
|
|
173
|
+
}).catch(() => null);
|
|
174
|
+
};
|
|
175
|
+
const [resolvedMetadata, resolvedViewport] = await Promise.all([shouldDeferMetadata ? Promise.resolve(null) : preparedHead.metadata.catch((error) => {
|
|
176
|
+
metadataErrorOutlet = Promise.reject(isProduction ? sanitizeErrorForClient(error, "production") : error);
|
|
177
|
+
metadataErrorOutlet.catch(() => null);
|
|
178
|
+
return resolveMetadataErrorTags(error);
|
|
179
|
+
}), preparedHead.viewport.catch(async (error) => {
|
|
180
|
+
const specialError = resolveAppPageSpecialError(error);
|
|
181
|
+
viewportErrorOutlet = Promise.reject(isProduction ? sanitizeErrorForClient(error, "production") : error);
|
|
182
|
+
viewportErrorOutlet.catch(() => null);
|
|
183
|
+
return specialError?.kind === "http-access-fallback" ? resolveHttpAccessFallbackViewport(resolveNotFoundFallbackPlanOptions()).catch(() => ({})) : {};
|
|
184
|
+
})]);
|
|
185
|
+
const streamingMetadataTags = shouldDeferMetadata ? preparedHead.metadata.catch(resolveMetadataErrorTags) : null;
|
|
186
|
+
const streamingMetadataOutletInputs = [
|
|
187
|
+
streamingMetadata,
|
|
188
|
+
metadataErrorOutlet,
|
|
189
|
+
viewportErrorOutlet
|
|
190
|
+
].filter((promise) => promise !== null).map((promise) => Promise.resolve(promise));
|
|
191
|
+
const streamingMetadataOutlet = streamingMetadataOutletInputs.length > 0 ? Promise.all(streamingMetadataOutletInputs).then(() => null) : null;
|
|
192
|
+
streamingMetadataOutlet?.catch(() => null);
|
|
111
193
|
const pageProps = { params: makeThenableParams(effectiveParams) };
|
|
112
194
|
const hasRequestSearchParams = Object.keys(pageSearchParams).length > 0;
|
|
113
195
|
const createPageElement = (PageComponent, props) => {
|
|
@@ -127,7 +209,6 @@ async function buildPageElements(options) {
|
|
|
127
209
|
const pageSearchParamsThenable = searchParams ? makeThenableParams(pageSearchParams) : void 0;
|
|
128
210
|
const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(" ")) : null;
|
|
129
211
|
const slotOverrides = buildSlotOverrides(route, params, routePath, opts);
|
|
130
|
-
const metadataPlacement = hasDynamicMetadata && (serveStreamingMetadata ?? shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots)) ? "body" : "head";
|
|
131
212
|
let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null;
|
|
132
213
|
if (isSiblingIntercept && siblingInterceptElement !== null && opts?.interceptLayouts?.length) for (let i = opts.interceptLayouts.length - 1; i >= 0; i--) {
|
|
133
214
|
const LayoutComponent = opts.interceptLayouts[i]?.default;
|
|
@@ -149,6 +230,10 @@ async function buildPageElements(options) {
|
|
|
149
230
|
resolvedMetadata,
|
|
150
231
|
resolvedMetadataPathname: routePath,
|
|
151
232
|
resolvedViewport,
|
|
233
|
+
streamingMetadata,
|
|
234
|
+
streamingMetadataOutlet,
|
|
235
|
+
streamingMetadataOutletSuspended: streamGeneratedHead,
|
|
236
|
+
streamingMetadataTags,
|
|
152
237
|
renderIdentity,
|
|
153
238
|
routePath,
|
|
154
239
|
sourcePageSegments,
|
|
@@ -293,4 +378,4 @@ function collectParamNameSet(params) {
|
|
|
293
378
|
return set;
|
|
294
379
|
}
|
|
295
380
|
//#endregion
|
|
296
|
-
export { buildPageElements, resolveAppPageNavigationParams, resolveInterceptedSlotSegments };
|
|
381
|
+
export { buildPageElements, resolveAppPageNavigationParams, resolveInterceptedSlotSegments, resolveSlotParamOverrides };
|
|
@@ -8,6 +8,14 @@ import { applyFileBasedMetadata } from "./file-based-metadata.js";
|
|
|
8
8
|
type AppPageSearchParams = Record<string, string | string[]>;
|
|
9
9
|
type AppPageHeadModule = Record<string, unknown>;
|
|
10
10
|
type ApplyAppPageFileBasedMetadata = typeof applyFileBasedMetadata;
|
|
11
|
+
type OrderedAppPageMetadataSource<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
12
|
+
/** Preserve an empty result as the most specific file-metadata source. */includeWhenEmpty?: boolean;
|
|
13
|
+
module: TModule;
|
|
14
|
+
params: AppPageParams;
|
|
15
|
+
routeSegments: readonly string[];
|
|
16
|
+
searchParams?: AppPageSearchParams;
|
|
17
|
+
searchParamsObserver?: ThenableParamsObserver;
|
|
18
|
+
};
|
|
11
19
|
type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
12
20
|
layoutParams?: readonly AppPageParams[] | null;
|
|
13
21
|
layoutModule?: TModule | null;
|
|
@@ -17,11 +25,19 @@ type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadMod
|
|
|
17
25
|
params?: AppPageParams | null;
|
|
18
26
|
routeSegments?: readonly string[] | null;
|
|
19
27
|
};
|
|
28
|
+
type ActiveParallelRouteHeadInput<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
29
|
+
head: AppPageHeadParallelRoute<TModule>;
|
|
30
|
+
notFoundModule?: TModule | null;
|
|
31
|
+
notFoundParams?: AppPageParams | null;
|
|
32
|
+
ownerTreePosition: number;
|
|
33
|
+
};
|
|
20
34
|
type AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
21
35
|
configLayouts?: readonly (TModule | null | undefined)[] | null;
|
|
22
36
|
configLayoutTreePositions?: readonly number[] | null;
|
|
23
37
|
layout?: TModule | null;
|
|
24
38
|
layoutIndex?: number;
|
|
39
|
+
notFound?: TModule | null;
|
|
40
|
+
notFoundTreePosition?: number | null;
|
|
25
41
|
page?: TModule | null;
|
|
26
42
|
routeSegments?: readonly string[] | null;
|
|
27
43
|
};
|
|
@@ -30,8 +46,12 @@ type ResolveActiveParallelRouteHeadInputsOptions<TModule extends AppPageHeadModu
|
|
|
30
46
|
interceptBranchSegments?: readonly string[] | null;
|
|
31
47
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
32
48
|
interceptPage?: TModule | null;
|
|
49
|
+
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
50
|
+
interceptNotFound?: TModule | null;
|
|
51
|
+
interceptNotFoundTreePosition?: number | null;
|
|
33
52
|
interceptParams?: AppPageParams | null;
|
|
34
53
|
interceptSlotKey?: string | null;
|
|
54
|
+
interceptSourcePageSegments?: readonly string[] | null;
|
|
35
55
|
layoutTreePositions?: readonly number[] | null;
|
|
36
56
|
params: AppPageParams;
|
|
37
57
|
routeSegments: readonly string[];
|
|
@@ -59,6 +79,18 @@ type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadMo
|
|
|
59
79
|
searchParams?: URLSearchParams | null;
|
|
60
80
|
searchParamsObserver?: ThenableParamsObserver;
|
|
61
81
|
};
|
|
82
|
+
type AppPageMetadataOutputOptions = {
|
|
83
|
+
applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
|
|
84
|
+
basePath?: string;
|
|
85
|
+
fallbackOnFileMetadataError?: boolean;
|
|
86
|
+
metadataRoutes: readonly MetadataFileRoute[];
|
|
87
|
+
params: AppPageParams;
|
|
88
|
+
routePath: string;
|
|
89
|
+
routeSegments?: readonly string[] | null;
|
|
90
|
+
};
|
|
91
|
+
type ResolveOrderedAppPageMetadataOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = AppPageMetadataOutputOptions & {
|
|
92
|
+
sources: readonly OrderedAppPageMetadataSource<TModule>[];
|
|
93
|
+
};
|
|
62
94
|
type ResolveAppPageHeadResult = {
|
|
63
95
|
hasDynamicMetadata: boolean;
|
|
64
96
|
hasSearchParams: boolean;
|
|
@@ -66,12 +98,32 @@ type ResolveAppPageHeadResult = {
|
|
|
66
98
|
pageSearchParams: AppPageSearchParams;
|
|
67
99
|
viewport: Viewport;
|
|
68
100
|
};
|
|
101
|
+
type PreparedAppPageHead = Omit<ResolveAppPageHeadResult, "metadata" | "viewport"> & {
|
|
102
|
+
metadata: Promise<Metadata | null>;
|
|
103
|
+
viewport: Promise<Viewport>;
|
|
104
|
+
};
|
|
69
105
|
type AppPageSearchParamsCollection = {
|
|
70
106
|
hasSearchParams: boolean;
|
|
71
107
|
pageSearchParams: AppPageSearchParams;
|
|
72
108
|
};
|
|
73
|
-
declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(options: ResolveActiveParallelRouteHeadInputsOptions<TModule>):
|
|
109
|
+
declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(options: ResolveActiveParallelRouteHeadInputsOptions<TModule>): ActiveParallelRouteHeadInput<TModule>[];
|
|
74
110
|
declare function collectAppPageSearchParams(searchParams: URLSearchParams | null | undefined): AppPageSearchParamsCollection;
|
|
111
|
+
/**
|
|
112
|
+
* Resolve an explicit metadata-source sequence.
|
|
113
|
+
*
|
|
114
|
+
* Route-specific conventions own source selection and ordering. This resolver
|
|
115
|
+
* only supplies each source with its accumulated parent, merges the results,
|
|
116
|
+
* and applies file-based metadata at the end.
|
|
117
|
+
*/
|
|
118
|
+
declare function resolveOrderedAppPageMetadata<TModule extends AppPageHeadModule>(options: ResolveOrderedAppPageMetadataOptions<TModule>): Promise<Metadata | null>;
|
|
75
119
|
declare function resolveAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): Promise<ResolveAppPageHeadResult>;
|
|
120
|
+
/**
|
|
121
|
+
* Start metadata and viewport resolution without coupling their completion.
|
|
122
|
+
*
|
|
123
|
+
* Live document renders can place the metadata promise behind Suspense while
|
|
124
|
+
* still waiting for viewport tags before the shell is emitted. Blocking
|
|
125
|
+
* callers use {@link resolveAppPageHead} and observe the same result as before.
|
|
126
|
+
*/
|
|
127
|
+
declare function prepareAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): PreparedAppPageHead;
|
|
76
128
|
//#endregion
|
|
77
|
-
export { AppPageSearchParams, ApplyAppPageFileBasedMetadata, collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
129
|
+
export { ActiveParallelRouteHeadInput, AppPageHeadModule, AppPageHeadParallelRoute, AppPageSearchParams, ApplyAppPageFileBasedMetadata, OrderedAppPageMetadataSource, PreparedAppPageHead, ResolveAppPageHeadResult, ResolveOrderedAppPageMetadataOptions, collectAppPageSearchParams, prepareAppPageHead, resolveActiveParallelRouteHeadInputs, resolveAppPageHead, resolveOrderedAppPageMetadata };
|
|
@@ -26,33 +26,58 @@ function resolveActiveParallelRouteHeadInputs(options) {
|
|
|
26
26
|
return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {
|
|
27
27
|
const ownerTreePosition = options.layoutTreePositions?.[slot.layoutIndex ?? 0] ?? 0;
|
|
28
28
|
const ownerParams = resolveAppPageSegmentParams(options.routeSegments, ownerTreePosition, options.params);
|
|
29
|
+
const slotParams = options.slotParams?.[slotKey] ?? options.params;
|
|
30
|
+
const notFoundParams = slot.notFound ? {
|
|
31
|
+
...ownerParams,
|
|
32
|
+
...resolveParallelLayoutParams(slot.routeSegments ?? options.routeSegments, slot.notFoundTreePosition ?? 0, slotParams)
|
|
33
|
+
} : null;
|
|
29
34
|
if (options.interceptSlotKey === slotKey && options.interceptPage) {
|
|
30
35
|
const interceptLayouts = options.interceptLayouts ?? [];
|
|
36
|
+
const inheritedSlotNotFound = slot.notFoundTreePosition === 0 ? slot.notFound ?? null : null;
|
|
37
|
+
const interceptNotFound = options.interceptNotFound ?? inheritedSlotNotFound;
|
|
38
|
+
const interceptNotFoundParams = interceptNotFound ? {
|
|
39
|
+
...ownerParams,
|
|
40
|
+
...resolveParallelLayoutParams(options.interceptNotFoundBranchSegments ?? options.interceptBranchSegments ?? options.routeSegments, options.interceptNotFound ? options.interceptNotFoundTreePosition ?? 0 : slot.notFoundTreePosition ?? 0, options.interceptParams ?? options.params)
|
|
41
|
+
} : null;
|
|
31
42
|
return {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
head: {
|
|
44
|
+
layoutModules: [slot.layout, ...interceptLayouts].filter(isPresent),
|
|
45
|
+
layoutParams: [...slot.layout ? [ownerParams] : [], ...interceptLayouts.filter(isPresent).map((_, index) => {
|
|
46
|
+
const segments = options.interceptLayoutSegments?.[index] ?? [];
|
|
47
|
+
return {
|
|
48
|
+
...ownerParams,
|
|
49
|
+
...resolveParallelLayoutParams(options.interceptBranchSegments ?? segments, segments.length, options.interceptParams ?? options.params)
|
|
50
|
+
};
|
|
51
|
+
})],
|
|
52
|
+
layoutTreePositions: [...slot.layout ? [0] : [], ...interceptLayouts.filter(isPresent).map(() => options.routeSegments.length)],
|
|
53
|
+
pageModule: options.interceptPage,
|
|
54
|
+
params: options.interceptParams ?? options.params,
|
|
55
|
+
routeSegments: options.interceptSourcePageSegments ?? options.routeSegments
|
|
56
|
+
},
|
|
57
|
+
...interceptNotFound ? {
|
|
58
|
+
notFoundModule: interceptNotFound,
|
|
59
|
+
notFoundParams: interceptNotFoundParams
|
|
60
|
+
} : {},
|
|
61
|
+
ownerTreePosition
|
|
44
62
|
};
|
|
45
63
|
}
|
|
46
64
|
return {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
...ownerParams,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
head: {
|
|
66
|
+
layoutModules: [slot.layout, ...slot.configLayouts ?? []].filter(isPresent),
|
|
67
|
+
layoutParams: [...slot.layout ? [ownerParams] : [], ...(slot.configLayoutTreePositions ?? []).map((treePosition) => ({
|
|
68
|
+
...ownerParams,
|
|
69
|
+
...resolveParallelLayoutParams(slot.routeSegments ?? options.routeSegments, treePosition, options.slotParams?.[slotKey] ?? options.params)
|
|
70
|
+
}))],
|
|
71
|
+
layoutTreePositions: [...slot.layout ? [0] : [], ...slot.configLayoutTreePositions ?? []],
|
|
72
|
+
pageModule: slot.page,
|
|
73
|
+
params: slotParams,
|
|
74
|
+
routeSegments: slot.routeSegments ?? options.routeSegments
|
|
75
|
+
},
|
|
76
|
+
...slot.notFound ? {
|
|
77
|
+
notFoundModule: slot.notFound,
|
|
78
|
+
notFoundParams
|
|
79
|
+
} : {},
|
|
80
|
+
ownerTreePosition
|
|
56
81
|
};
|
|
57
82
|
});
|
|
58
83
|
}
|
|
@@ -97,6 +122,20 @@ function createMetadataSources(metadataResults, routeSegments, layoutTreePositio
|
|
|
97
122
|
});
|
|
98
123
|
return metadataSources;
|
|
99
124
|
}
|
|
125
|
+
async function finalizeAppPageMetadata(metadata, metadataSources, options) {
|
|
126
|
+
let resolvedMetadata = metadata;
|
|
127
|
+
if (options.applyFileBasedMetadata && options.metadataRoutes.length > 0) try {
|
|
128
|
+
resolvedMetadata = await options.applyFileBasedMetadata(metadata, options.routePath, options.params, options.metadataRoutes, {
|
|
129
|
+
routeSegments: options.routeSegments ?? [],
|
|
130
|
+
metadataSources,
|
|
131
|
+
basePath: options.basePath ?? ""
|
|
132
|
+
});
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (!options.fallbackOnFileMetadataError) throw error;
|
|
135
|
+
console.error(`[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`, error);
|
|
136
|
+
}
|
|
137
|
+
return resolvedMetadata ? postProcessMetadata(resolvedMetadata) : null;
|
|
138
|
+
}
|
|
100
139
|
function createLayoutInputs(layoutModules, layoutTreePositions) {
|
|
101
140
|
const layoutInputs = [];
|
|
102
141
|
for (let index = 0; index < layoutModules.length; index++) {
|
|
@@ -132,21 +171,21 @@ async function resolveLayoutViewport(layoutInputs, params, routeSegments) {
|
|
|
132
171
|
return resolveModuleViewport(layoutInput.module, layoutParams);
|
|
133
172
|
}));
|
|
134
173
|
}
|
|
135
|
-
|
|
174
|
+
function getParallelRouteModules(parallelRoute) {
|
|
175
|
+
return [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
|
|
176
|
+
}
|
|
177
|
+
function parallelRouteHasDynamicMetadata(parallelRoute) {
|
|
178
|
+
return getParallelRouteModules(parallelRoute).some(hasGenerateMetadata) || hasGenerateMetadata(parallelRoute.pageModule);
|
|
179
|
+
}
|
|
180
|
+
async function resolveParallelRouteMetadata(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent, searchParamsObserver) {
|
|
136
181
|
const params = parallelRoute.params ?? fallbackParams;
|
|
137
182
|
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
138
183
|
const metadataResults = [];
|
|
139
|
-
const viewportResults = [];
|
|
140
184
|
const metadataSources = [];
|
|
141
185
|
let accumulatedMetadata = parent;
|
|
142
|
-
const layoutModules =
|
|
186
|
+
const layoutModules = getParallelRouteModules(parallelRoute);
|
|
143
187
|
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
144
188
|
const layoutParams = parallelRoute.layoutParams ?? [];
|
|
145
|
-
const hasDynamicMetadata = layoutModules.some(hasGenerateMetadata) || hasGenerateMetadata(parallelRoute.pageModule);
|
|
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);
|
|
148
|
-
for (const layoutViewportPromise of layoutViewportPromises) layoutViewportPromise.catch(() => null);
|
|
149
|
-
pageViewportPromise.catch(() => null);
|
|
150
189
|
for (const [index, layoutModule] of layoutModules.entries()) {
|
|
151
190
|
const layoutMetadata = await resolveModuleMetadata(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params), void 0, accumulatedMetadata);
|
|
152
191
|
metadataResults.push(layoutMetadata);
|
|
@@ -167,20 +206,72 @@ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackR
|
|
|
167
206
|
routeSegments
|
|
168
207
|
});
|
|
169
208
|
}
|
|
170
|
-
viewportResults.push(...await Promise.all(layoutViewportPromises));
|
|
171
|
-
const pageViewport = await pageViewportPromise;
|
|
172
|
-
if (parallelRoute.pageModule) viewportResults.push(pageViewport);
|
|
173
209
|
return {
|
|
174
|
-
hasDynamicMetadata,
|
|
175
210
|
metadataResults,
|
|
176
|
-
metadataSources
|
|
177
|
-
viewportResults
|
|
211
|
+
metadataSources
|
|
178
212
|
};
|
|
179
213
|
}
|
|
214
|
+
async function resolveParallelRouteViewport(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, searchParamsObserver) {
|
|
215
|
+
const params = parallelRoute.params ?? fallbackParams;
|
|
216
|
+
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
217
|
+
const layoutModules = getParallelRouteModules(parallelRoute);
|
|
218
|
+
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
219
|
+
const layoutParams = parallelRoute.layoutParams ?? [];
|
|
220
|
+
const layoutViewportPromise = Promise.all(layoutModules.map((layoutModule, index) => resolveModuleViewport(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params))));
|
|
221
|
+
const pageViewportPromise = parallelRoute.pageModule ? resolveModuleViewport(parallelRoute.pageModule, params, pageSearchParams, searchParamsObserver) : Promise.resolve(null);
|
|
222
|
+
const [layoutViewports, pageViewport] = await Promise.all([layoutViewportPromise, pageViewportPromise]);
|
|
223
|
+
return parallelRoute.pageModule ? [...layoutViewports, pageViewport] : layoutViewports;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Resolve an explicit metadata-source sequence.
|
|
227
|
+
*
|
|
228
|
+
* Route-specific conventions own source selection and ordering. This resolver
|
|
229
|
+
* only supplies each source with its accumulated parent, merges the results,
|
|
230
|
+
* and applies file-based metadata at the end.
|
|
231
|
+
*/
|
|
232
|
+
function resolveOrderedAppPageMetadata(options) {
|
|
233
|
+
return runWithFetchDedupe(async () => {
|
|
234
|
+
const metadataPromises = [];
|
|
235
|
+
let accumulatedEntriesPromise = Promise.resolve([]);
|
|
236
|
+
for (const source of options.sources) {
|
|
237
|
+
const parentPromise = accumulatedEntriesPromise.then((entries) => entries.length > 0 ? mergeMetadataEntries(entries) : {});
|
|
238
|
+
const metadataPromise = resolveModuleMetadata(source.module, source.params, source.searchParams, parentPromise, source.searchParamsObserver);
|
|
239
|
+
metadataPromises.push(metadataPromise);
|
|
240
|
+
metadataPromise.catch(() => null);
|
|
241
|
+
accumulatedEntriesPromise = Promise.all([accumulatedEntriesPromise, metadataPromise]).then(([entries, metadata]) => metadata ? [...entries, { metadata }] : entries);
|
|
242
|
+
accumulatedEntriesPromise.catch(() => null);
|
|
243
|
+
}
|
|
244
|
+
const [metadataEntries, metadataResults] = await Promise.all([accumulatedEntriesPromise, Promise.all(metadataPromises)]);
|
|
245
|
+
const metadataSources = options.sources.flatMap((source, index) => {
|
|
246
|
+
const metadata = metadataResults[index] ?? null;
|
|
247
|
+
return metadata || source.includeWhenEmpty ? [{
|
|
248
|
+
metadata,
|
|
249
|
+
routeSegments: source.routeSegments
|
|
250
|
+
}] : [];
|
|
251
|
+
});
|
|
252
|
+
return finalizeAppPageMetadata(metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null, metadataSources, options);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
180
255
|
async function resolveAppPageHead(options) {
|
|
181
|
-
|
|
256
|
+
const prepared = prepareAppPageHead(options);
|
|
257
|
+
const [metadata, viewport] = await Promise.all([prepared.metadata, prepared.viewport]);
|
|
258
|
+
return {
|
|
259
|
+
...prepared,
|
|
260
|
+
metadata,
|
|
261
|
+
viewport
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Start metadata and viewport resolution without coupling their completion.
|
|
266
|
+
*
|
|
267
|
+
* Live document renders can place the metadata promise behind Suspense while
|
|
268
|
+
* still waiting for viewport tags before the shell is emitted. Blocking
|
|
269
|
+
* callers use {@link resolveAppPageHead} and observe the same result as before.
|
|
270
|
+
*/
|
|
271
|
+
function prepareAppPageHead(options) {
|
|
272
|
+
return runWithFetchDedupe(() => prepareAppPageHeadInner(options));
|
|
182
273
|
}
|
|
183
|
-
|
|
274
|
+
function prepareAppPageHeadInner(options) {
|
|
184
275
|
const routeSegments = options.routeSegments ?? [];
|
|
185
276
|
const layoutTreePositions = options.layoutTreePositions ?? [];
|
|
186
277
|
const layoutInputs = createLayoutInputs(options.layoutModules, layoutTreePositions);
|
|
@@ -195,57 +286,52 @@ async function resolveAppPageHeadInner(options) {
|
|
|
195
286
|
pageParentPromise.catch(() => null);
|
|
196
287
|
const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise, options.searchParamsObserver) : Promise.resolve(null);
|
|
197
288
|
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params, pageSearchParams, options.searchParamsObserver) : Promise.resolve(null);
|
|
198
|
-
const
|
|
199
|
-
const
|
|
289
|
+
const parallelRoutes = options.parallelRoutes ?? [];
|
|
290
|
+
const parallelRouteMetadataPromise = Promise.all(parallelRoutes.map((parallelRoute) => resolveParallelRouteMetadata(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise, options.searchParamsObserver)));
|
|
291
|
+
const parallelRouteViewportPromise = Promise.all(parallelRoutes.map((parallelRoute) => resolveParallelRouteViewport(parallelRoute, options.params, routeSegments, pageSearchParams, options.searchParamsObserver)));
|
|
292
|
+
const hasDynamicMetadata = primaryHasDynamicMetadata || parallelRoutes.some(parallelRouteHasDynamicMetadata);
|
|
293
|
+
const metadata = Promise.all([
|
|
200
294
|
layoutMetadataPromise,
|
|
201
|
-
layoutViewportPromise,
|
|
202
295
|
pageMetadataPromise,
|
|
296
|
+
parallelRouteMetadataPromise
|
|
297
|
+
]).then(async ([layoutMetadataResults, pageMetadata, parallelRouteMetadata]) => {
|
|
298
|
+
const parallelMetadataResults = parallelRouteMetadata.flatMap((head) => head.metadataResults);
|
|
299
|
+
const parallelMetadataSources = parallelRouteMetadata.flatMap((head) => head.metadataSources);
|
|
300
|
+
const primaryPageHasTitle = pageMetadata != null && pageMetadata.title !== void 0;
|
|
301
|
+
const metadataEntries = [
|
|
302
|
+
...layoutMetadataResults.filter(isPresent).map((entry) => ({ metadata: entry })),
|
|
303
|
+
...pageMetadata ? [{
|
|
304
|
+
isPage: true,
|
|
305
|
+
metadata: pageMetadata
|
|
306
|
+
}] : [],
|
|
307
|
+
...parallelMetadataResults.filter(isPresent).map((entry) => ({
|
|
308
|
+
contributesTitle: !primaryPageHasTitle,
|
|
309
|
+
metadata: entry
|
|
310
|
+
}))
|
|
311
|
+
];
|
|
312
|
+
const resolvedMetadataBase = metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null;
|
|
313
|
+
const metadataSources = createMetadataSources(layoutMetadataResults, routeSegments, layoutSourcePositions, pageMetadata, Boolean(options.pageModule));
|
|
314
|
+
metadataSources.push(...parallelMetadataSources);
|
|
315
|
+
return finalizeAppPageMetadata(resolvedMetadataBase, metadataSources, options);
|
|
316
|
+
});
|
|
317
|
+
const viewport = Promise.all([
|
|
318
|
+
layoutViewportPromise,
|
|
203
319
|
pageViewportPromise,
|
|
204
|
-
|
|
205
|
-
])
|
|
206
|
-
const parallelMetadataResults = parallelRouteHeads.flatMap((head) => head.metadataResults);
|
|
207
|
-
const parallelViewportResults = parallelRouteHeads.flatMap((head) => head.viewportResults);
|
|
208
|
-
const parallelMetadataSources = parallelRouteHeads.flatMap((head) => head.metadataSources);
|
|
209
|
-
const hasDynamicMetadata = primaryHasDynamicMetadata || parallelRouteHeads.some((head) => head.hasDynamicMetadata);
|
|
210
|
-
const primaryPageHasTitle = pageMetadata != null && pageMetadata.title !== void 0;
|
|
211
|
-
const metadataEntries = [
|
|
212
|
-
...layoutMetadataResults.filter(isPresent).map((metadata) => ({ metadata })),
|
|
213
|
-
...pageMetadata ? [{
|
|
214
|
-
isPage: true,
|
|
215
|
-
metadata: pageMetadata
|
|
216
|
-
}] : [],
|
|
217
|
-
...parallelMetadataResults.filter(isPresent).map((metadata) => ({
|
|
218
|
-
contributesTitle: !primaryPageHasTitle,
|
|
219
|
-
metadata
|
|
220
|
-
}))
|
|
221
|
-
];
|
|
222
|
-
const viewportList = [
|
|
320
|
+
parallelRouteViewportPromise
|
|
321
|
+
]).then(([layoutViewportResults, pageViewport, parallelRouteViewports]) => mergeViewport([
|
|
223
322
|
...layoutViewportResults.filter(isPresent),
|
|
224
323
|
...pageViewport ? [pageViewport] : [],
|
|
225
|
-
...
|
|
226
|
-
];
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
metadataSources.push(...parallelMetadataSources);
|
|
230
|
-
let metadata = resolvedMetadataBase;
|
|
231
|
-
if (options.applyFileBasedMetadata && options.metadataRoutes.length > 0) try {
|
|
232
|
-
metadata = await options.applyFileBasedMetadata(resolvedMetadataBase, options.routePath, options.params, options.metadataRoutes, {
|
|
233
|
-
routeSegments,
|
|
234
|
-
metadataSources,
|
|
235
|
-
basePath: options.basePath ?? ""
|
|
236
|
-
});
|
|
237
|
-
} catch (error) {
|
|
238
|
-
if (!options.fallbackOnFileMetadataError) throw error;
|
|
239
|
-
console.error(`[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`, error);
|
|
240
|
-
}
|
|
241
|
-
if (metadata) metadata = postProcessMetadata(metadata);
|
|
324
|
+
...parallelRouteViewports.flat().filter(isPresent)
|
|
325
|
+
]));
|
|
326
|
+
metadata.catch(() => null);
|
|
327
|
+
viewport.catch(() => null);
|
|
242
328
|
return {
|
|
243
329
|
hasDynamicMetadata,
|
|
244
330
|
hasSearchParams,
|
|
245
331
|
metadata,
|
|
246
332
|
pageSearchParams,
|
|
247
|
-
viewport
|
|
333
|
+
viewport
|
|
248
334
|
};
|
|
249
335
|
}
|
|
250
336
|
//#endregion
|
|
251
|
-
export { collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
337
|
+
export { collectAppPageSearchParams, prepareAppPageHead, resolveActiveParallelRouteHeadInputs, resolveAppPageHead, resolveOrderedAppPageMetadata };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
|
+
import { AppPageParams } from "./app-page-boundary.js";
|
|
3
|
+
import { Metadata, Viewport } from "../shims/metadata.js";
|
|
4
|
+
import { ActiveParallelRouteHeadInput, AppPageHeadModule, ApplyAppPageFileBasedMetadata, OrderedAppPageMetadataSource } from "./app-page-head.js";
|
|
5
|
+
|
|
6
|
+
//#region src/server/app-page-http-access-fallback-metadata.d.ts
|
|
7
|
+
type HttpAccessFallbackMetadataPlanOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
8
|
+
boundaryModule?: TModule | null;
|
|
9
|
+
boundaryParams: AppPageParams; /** Whether active branches may replace the fallback with their local not-found convention. */
|
|
10
|
+
branchNotFoundConventions?: boolean;
|
|
11
|
+
layoutModules: readonly (TModule | null | undefined)[];
|
|
12
|
+
layoutTreePositions?: readonly number[] | null;
|
|
13
|
+
parallelBranches?: readonly ActiveParallelRouteHeadInput<TModule>[] | null;
|
|
14
|
+
params: AppPageParams;
|
|
15
|
+
primaryParallelBranch?: ActiveParallelRouteHeadInput<TModule> | null;
|
|
16
|
+
routeSegments?: readonly string[] | null;
|
|
17
|
+
};
|
|
18
|
+
type ResolveHttpAccessFallbackMetadataOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = HttpAccessFallbackMetadataPlanOptions<TModule> & {
|
|
19
|
+
applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
|
|
20
|
+
basePath?: string;
|
|
21
|
+
fallbackOnFileMetadataError?: boolean;
|
|
22
|
+
metadataRoutes: readonly MetadataFileRoute[];
|
|
23
|
+
routePath: string;
|
|
24
|
+
};
|
|
25
|
+
declare function createHttpAccessFallbackMetadataPlan<TModule extends AppPageHeadModule>(options: HttpAccessFallbackMetadataPlanOptions<TModule>): OrderedAppPageMetadataSource<TModule>[];
|
|
26
|
+
declare function resolveHttpAccessFallbackMetadata<TModule extends AppPageHeadModule>(options: ResolveHttpAccessFallbackMetadataOptions<TModule>): Promise<Metadata | null>;
|
|
27
|
+
declare function resolveHttpAccessFallbackViewport<TModule extends AppPageHeadModule>(options: HttpAccessFallbackMetadataPlanOptions<TModule>): Promise<Viewport>;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { createHttpAccessFallbackMetadataPlan, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport };
|