vinext 1.0.0-beta.1 → 1.0.0-beta.3
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 +10 -10
- package/dist/build/client-build-config.js +8 -1
- package/dist/build/report.d.ts +8 -1
- package/dist/build/report.js +12 -2
- package/dist/check.js +19 -2
- package/dist/cli.js +3 -2
- package/dist/config/config-matchers.d.ts +13 -37
- package/dist/config/config-matchers.js +35 -122
- package/dist/config/next-config.d.ts +15 -5
- package/dist/config/next-config.js +7 -1
- package/dist/config/request-context.d.ts +14 -0
- package/dist/config/request-context.js +26 -0
- package/dist/entries/app-browser-entry.d.ts +4 -10
- package/dist/entries/app-browser-entry.js +20 -4
- package/dist/entries/app-rsc-entry.js +30 -9
- package/dist/entries/app-rsc-manifest.js +36 -0
- package/dist/entries/pages-client-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +13 -5
- package/dist/index.js +194 -101
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -5
- package/dist/init.d.ts +6 -4
- package/dist/init.js +20 -22
- package/dist/plugins/extensionless-dynamic-import.js +23 -18
- package/dist/plugins/ignore-dynamic-requests.js +3 -1
- package/dist/plugins/import-meta-url.js +17 -6
- package/dist/plugins/og-assets.js +1 -1
- package/dist/plugins/require-context.js +20 -15
- package/dist/plugins/transform-cache.d.ts +19 -0
- package/dist/plugins/transform-cache.js +36 -0
- package/dist/routing/app-route-graph.d.ts +27 -11
- package/dist/routing/app-route-graph.js +158 -22
- 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/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +3 -3
- package/dist/server/app-browser-entry.js +110 -37
- 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.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +2 -2
- 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-finalizer.js +1 -1
- package/dist/server/app-page-cache.d.ts +2 -2
- package/dist/server/app-page-cache.js +16 -2
- package/dist/server/app-page-dispatch.d.ts +19 -2
- package/dist/server/app-page-dispatch.js +45 -23
- package/dist/server/app-page-element-builder.d.ts +9 -2
- package/dist/server/app-page-element-builder.js +144 -33
- package/dist/server/app-page-head.d.ts +56 -4
- package/dist/server/app-page-head.js +216 -85
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +114 -0
- package/dist/server/app-page-probe.d.ts +4 -0
- package/dist/server/app-page-probe.js +6 -2
- 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 +15 -0
- package/dist/server/app-page-request.js +134 -14
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +16 -0
- package/dist/server/app-page-route-wiring.js +254 -52
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -1
- 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-cache.js +4 -0
- package/dist/server/app-route-handler-dispatch.js +40 -20
- 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-handler-response.js +1 -1
- package/dist/server/app-route-module-loader.d.ts +9 -1
- package/dist/server/app-route-module-loader.js +4 -0
- package/dist/server/app-router-entry.js +6 -3
- 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 +22 -2
- package/dist/server/app-rsc-handler.d.ts +10 -5
- package/dist/server/app-rsc-handler.js +73 -33
- 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 +29 -0
- package/dist/server/app-rsc-route-matching.js +93 -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 +6 -6
- package/dist/server/app-ssr-stream.d.ts +1 -7
- package/dist/server/app-ssr-stream.js +2 -10
- package/dist/server/cache-control.d.ts +2 -2
- package/dist/server/cache-control.js +2 -1
- 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.d.ts +3 -1
- package/dist/server/dev-server.js +170 -321
- package/dist/server/headers.d.ts +2 -2
- package/dist/server/headers.js +4 -3
- package/dist/server/isr-cache.d.ts +11 -34
- package/dist/server/isr-cache.js +33 -43
- package/dist/server/isr-decision.d.ts +2 -2
- 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-api-route.d.ts +2 -0
- package/dist/server/pages-api-route.js +4 -1
- package/dist/server/pages-data-route.d.ts +11 -1
- package/dist/server/pages-data-route.js +16 -1
- package/dist/server/pages-dev-hydration.js +0 -1
- package/dist/server/pages-get-initial-props.d.ts +16 -3
- package/dist/server/pages-get-initial-props.js +17 -10
- package/dist/server/pages-i18n.js +64 -16
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +7 -3
- package/dist/server/pages-page-data.d.ts +64 -10
- package/dist/server/pages-page-data.js +349 -80
- package/dist/server/pages-page-handler.d.ts +9 -3
- package/dist/server/pages-page-handler.js +131 -36
- package/dist/server/pages-page-response.d.ts +5 -3
- package/dist/server/pages-page-response.js +24 -27
- package/dist/server/pages-readiness.d.ts +3 -3
- package/dist/server/pages-request-pipeline.d.ts +8 -0
- package/dist/server/pages-request-pipeline.js +30 -12
- package/dist/server/pages-revalidate.d.ts +1 -1
- package/dist/server/pages-revalidate.js +54 -8
- package/dist/server/pages-router-entry.d.ts +1 -0
- package/dist/server/pages-router-entry.js +16 -4
- package/dist/server/prerender-route-params.js +2 -2
- package/dist/server/prod-server.d.ts +3 -5
- package/dist/server/prod-server.js +72 -35
- package/dist/server/request-pipeline.d.ts +15 -29
- package/dist/server/request-pipeline.js +24 -59
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/rsc-stream-hints.js +122 -18
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +29 -0
- package/dist/shims/app.d.ts +1 -1
- package/dist/shims/cache-handler.d.ts +1 -1
- package/dist/shims/cache-handler.js +10 -7
- 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 +18 -1
- package/dist/shims/cache-runtime.js +26 -8
- package/dist/shims/cache.d.ts +5 -5
- package/dist/shims/cache.js +27 -11
- 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 +2 -2
- package/dist/shims/fetch-cache.js +13 -4
- package/dist/shims/font-google-base.d.ts +11 -4
- package/dist/shims/font-google-base.js +17 -8
- package/dist/shims/font-local.d.ts +10 -3
- package/dist/shims/font-local.js +41 -10
- package/dist/shims/head.d.ts +13 -2
- package/dist/shims/head.js +3 -3
- package/dist/shims/headers.d.ts +37 -43
- package/dist/shims/headers.js +183 -74
- package/dist/shims/image.d.ts +27 -37
- package/dist/shims/image.js +21 -14
- package/dist/shims/internal/cookie-serialize.d.ts +12 -9
- package/dist/shims/internal/cookie-serialize.js +10 -7
- package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
- package/dist/shims/internal/interpolate-as.d.ts +15 -1
- package/dist/shims/internal/interpolate-as.js +27 -2
- 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 +34 -13
- package/dist/shims/metadata.d.ts +7 -17
- package/dist/shims/metadata.js +74 -24
- package/dist/shims/navigation-context-state.d.ts +1 -1
- package/dist/shims/navigation.d.ts +7 -3
- package/dist/shims/navigation.js +25 -14
- 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-context.d.ts +4 -1
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router.d.ts +55 -21
- package/dist/shims/router.js +180 -44
- package/dist/shims/script.d.ts +6 -10
- package/dist/shims/script.js +7 -4
- package/dist/shims/server.d.ts +50 -26
- package/dist/shims/server.js +193 -55
- package/dist/shims/unified-request-context.d.ts +22 -3
- package/dist/shims/unified-request-context.js +84 -1
- 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/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +5 -1
- 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/html-limited-bots.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/dist/utils/regex-safety.d.ts +8 -0
- package/dist/utils/regex-safety.js +737 -0
- package/package.json +13 -2
|
@@ -26,35 +26,60 @@ 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
|
+
}).sort((left, right) => right.ownerTreePosition - left.ownerTreePosition);
|
|
58
83
|
}
|
|
59
84
|
function isPresent(value) {
|
|
60
85
|
return value !== null && value !== void 0;
|
|
@@ -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++) {
|
|
@@ -126,27 +165,41 @@ async function resolveLayoutMetadata(layoutInputs, params, routeSegments) {
|
|
|
126
165
|
}
|
|
127
166
|
return Promise.all(layoutMetadataPromises);
|
|
128
167
|
}
|
|
129
|
-
|
|
130
|
-
|
|
168
|
+
function resolveLayoutViewport(layoutInputs, params, routeSegments) {
|
|
169
|
+
const viewportPromises = [];
|
|
170
|
+
let accumulatedViewport = Promise.resolve(mergeViewport([]));
|
|
171
|
+
for (const layoutInput of layoutInputs) {
|
|
172
|
+
const parentForLayout = accumulatedViewport;
|
|
131
173
|
const layoutParams = resolveAppPageSegmentParams(routeSegments, layoutInput.treePosition, params);
|
|
132
|
-
|
|
133
|
-
|
|
174
|
+
const viewportPromise = resolveModuleViewport(layoutInput.module, layoutParams, void 0, parentForLayout);
|
|
175
|
+
viewportPromises.push(viewportPromise);
|
|
176
|
+
viewportPromise.catch(() => null);
|
|
177
|
+
accumulatedViewport = mergeResolvedViewport(parentForLayout, viewportPromise);
|
|
178
|
+
accumulatedViewport.catch(() => null);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
resolvedViewport: accumulatedViewport,
|
|
182
|
+
viewportResults: Promise.all(viewportPromises)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function mergeResolvedViewport(parent, viewport) {
|
|
186
|
+
return Promise.all([parent, viewport]).then(([resolvedParent, resolvedViewport]) => resolvedViewport ? mergeViewport([resolvedParent, resolvedViewport]) : resolvedParent);
|
|
187
|
+
}
|
|
188
|
+
function getParallelRouteModules(parallelRoute) {
|
|
189
|
+
return [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
|
|
134
190
|
}
|
|
135
|
-
|
|
191
|
+
function parallelRouteHasDynamicMetadata(parallelRoute) {
|
|
192
|
+
return getParallelRouteModules(parallelRoute).some(hasGenerateMetadata) || hasGenerateMetadata(parallelRoute.pageModule);
|
|
193
|
+
}
|
|
194
|
+
async function resolveParallelRouteMetadata(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent, searchParamsObserver) {
|
|
136
195
|
const params = parallelRoute.params ?? fallbackParams;
|
|
137
196
|
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
138
197
|
const metadataResults = [];
|
|
139
|
-
const viewportResults = [];
|
|
140
198
|
const metadataSources = [];
|
|
141
199
|
let accumulatedMetadata = parent;
|
|
142
|
-
const layoutModules =
|
|
200
|
+
const layoutModules = getParallelRouteModules(parallelRoute);
|
|
143
201
|
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
144
202
|
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
203
|
for (const [index, layoutModule] of layoutModules.entries()) {
|
|
151
204
|
const layoutMetadata = await resolveModuleMetadata(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params), void 0, accumulatedMetadata);
|
|
152
205
|
metadataResults.push(layoutMetadata);
|
|
@@ -167,20 +220,90 @@ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackR
|
|
|
167
220
|
routeSegments
|
|
168
221
|
});
|
|
169
222
|
}
|
|
170
|
-
viewportResults.push(...await Promise.all(layoutViewportPromises));
|
|
171
|
-
const pageViewport = await pageViewportPromise;
|
|
172
|
-
if (parallelRoute.pageModule) viewportResults.push(pageViewport);
|
|
173
223
|
return {
|
|
174
|
-
hasDynamicMetadata,
|
|
175
224
|
metadataResults,
|
|
176
|
-
metadataSources
|
|
177
|
-
viewportResults
|
|
225
|
+
metadataSources
|
|
178
226
|
};
|
|
179
227
|
}
|
|
228
|
+
function resolveParallelRouteViewport(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent, searchParamsObserver) {
|
|
229
|
+
const params = parallelRoute.params ?? fallbackParams;
|
|
230
|
+
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
231
|
+
const layoutModules = getParallelRouteModules(parallelRoute);
|
|
232
|
+
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
233
|
+
const layoutParams = parallelRoute.layoutParams ?? [];
|
|
234
|
+
const viewportPromises = [];
|
|
235
|
+
let accumulatedViewport = parent;
|
|
236
|
+
for (const [index, layoutModule] of layoutModules.entries()) {
|
|
237
|
+
const parentForLayout = accumulatedViewport;
|
|
238
|
+
const viewportPromise = resolveModuleViewport(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params), void 0, parentForLayout);
|
|
239
|
+
viewportPromises.push(viewportPromise);
|
|
240
|
+
viewportPromise.catch(() => null);
|
|
241
|
+
accumulatedViewport = mergeResolvedViewport(parentForLayout, viewportPromise);
|
|
242
|
+
accumulatedViewport.catch(() => null);
|
|
243
|
+
}
|
|
244
|
+
if (parallelRoute.pageModule) {
|
|
245
|
+
const parentForPage = accumulatedViewport;
|
|
246
|
+
const viewportPromise = resolveModuleViewport(parallelRoute.pageModule, params, pageSearchParams, parentForPage, searchParamsObserver);
|
|
247
|
+
viewportPromises.push(viewportPromise);
|
|
248
|
+
viewportPromise.catch(() => null);
|
|
249
|
+
accumulatedViewport = mergeResolvedViewport(parentForPage, viewportPromise);
|
|
250
|
+
accumulatedViewport.catch(() => null);
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
resolvedViewport: accumulatedViewport,
|
|
254
|
+
viewportResults: Promise.all(viewportPromises)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Resolve an explicit metadata-source sequence.
|
|
259
|
+
*
|
|
260
|
+
* Route-specific conventions own source selection and ordering. This resolver
|
|
261
|
+
* only supplies each source with its accumulated parent, merges the results,
|
|
262
|
+
* and applies file-based metadata at the end.
|
|
263
|
+
*/
|
|
264
|
+
function resolveOrderedAppPageMetadata(options) {
|
|
265
|
+
return runWithFetchDedupe(async () => {
|
|
266
|
+
const metadataPromises = [];
|
|
267
|
+
let accumulatedEntriesPromise = Promise.resolve([]);
|
|
268
|
+
for (const source of options.sources) {
|
|
269
|
+
const parentPromise = accumulatedEntriesPromise.then((entries) => entries.length > 0 ? mergeMetadataEntries(entries) : {});
|
|
270
|
+
const metadataPromise = resolveModuleMetadata(source.module, source.params, source.searchParams, parentPromise, source.searchParamsObserver);
|
|
271
|
+
metadataPromises.push(metadataPromise);
|
|
272
|
+
metadataPromise.catch(() => null);
|
|
273
|
+
accumulatedEntriesPromise = Promise.all([accumulatedEntriesPromise, metadataPromise]).then(([entries, metadata]) => metadata ? [...entries, { metadata }] : entries);
|
|
274
|
+
accumulatedEntriesPromise.catch(() => null);
|
|
275
|
+
}
|
|
276
|
+
const [metadataEntries, metadataResults] = await Promise.all([accumulatedEntriesPromise, Promise.all(metadataPromises)]);
|
|
277
|
+
const metadataSources = options.sources.flatMap((source, index) => {
|
|
278
|
+
const metadata = metadataResults[index] ?? null;
|
|
279
|
+
return metadata || source.includeWhenEmpty ? [{
|
|
280
|
+
metadata,
|
|
281
|
+
routeSegments: source.routeSegments
|
|
282
|
+
}] : [];
|
|
283
|
+
});
|
|
284
|
+
return finalizeAppPageMetadata(metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null, metadataSources, options);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
180
287
|
async function resolveAppPageHead(options) {
|
|
181
|
-
|
|
288
|
+
const prepared = prepareAppPageHead(options);
|
|
289
|
+
const [metadata, viewport] = await Promise.all([prepared.metadata, prepared.viewport]);
|
|
290
|
+
return {
|
|
291
|
+
...prepared,
|
|
292
|
+
metadata,
|
|
293
|
+
viewport
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Start metadata and viewport resolution without coupling their completion.
|
|
298
|
+
*
|
|
299
|
+
* Live document renders can place the metadata promise behind Suspense while
|
|
300
|
+
* still waiting for viewport tags before the shell is emitted. Blocking
|
|
301
|
+
* callers use {@link resolveAppPageHead} and observe the same result as before.
|
|
302
|
+
*/
|
|
303
|
+
function prepareAppPageHead(options) {
|
|
304
|
+
return runWithFetchDedupe(() => prepareAppPageHeadInner(options));
|
|
182
305
|
}
|
|
183
|
-
|
|
306
|
+
function prepareAppPageHeadInner(options) {
|
|
184
307
|
const routeSegments = options.routeSegments ?? [];
|
|
185
308
|
const layoutTreePositions = options.layoutTreePositions ?? [];
|
|
186
309
|
const layoutInputs = createLayoutInputs(options.layoutModules, layoutTreePositions);
|
|
@@ -188,64 +311,72 @@ async function resolveAppPageHeadInner(options) {
|
|
|
188
311
|
const primaryHasDynamicMetadata = layoutInputs.some((input) => hasGenerateMetadata(input.module)) || hasGenerateMetadata(options.pageModule);
|
|
189
312
|
const { hasSearchParams, pageSearchParams } = collectAppPageSearchParams(options.searchParams);
|
|
190
313
|
const layoutMetadataPromise = resolveLayoutMetadata(layoutInputs, options.params, routeSegments);
|
|
191
|
-
const
|
|
314
|
+
const layoutViewport = resolveLayoutViewport(layoutInputs, options.params, routeSegments);
|
|
315
|
+
const layoutViewportPromise = layoutViewport.viewportResults;
|
|
192
316
|
const layoutMetadataResultsForParent = layoutMetadataPromise.then((metadataResults) => metadataResults.filter(isPresent));
|
|
193
317
|
layoutMetadataResultsForParent.catch(() => null);
|
|
194
318
|
const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) => metadataResults.length > 0 ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata }))) : {});
|
|
195
319
|
pageParentPromise.catch(() => null);
|
|
196
320
|
const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise, options.searchParamsObserver) : Promise.resolve(null);
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
const
|
|
321
|
+
const parallelRoutes = options.parallelRoutes ?? [];
|
|
322
|
+
const parallelRouteMetadataPromise = Promise.all(parallelRoutes.map((parallelRoute) => resolveParallelRouteMetadata(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise, options.searchParamsObserver)));
|
|
323
|
+
const parallelRouteViewportPromises = [];
|
|
324
|
+
let accumulatedViewport = layoutViewport.resolvedViewport;
|
|
325
|
+
const pageParentViewport = accumulatedViewport;
|
|
326
|
+
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params, pageSearchParams, pageParentViewport, options.searchParamsObserver) : Promise.resolve(null);
|
|
327
|
+
if (options.pageModule) {
|
|
328
|
+
accumulatedViewport = mergeResolvedViewport(pageParentViewport, pageViewportPromise);
|
|
329
|
+
accumulatedViewport.catch(() => null);
|
|
330
|
+
}
|
|
331
|
+
for (const parallelRoute of parallelRoutes) {
|
|
332
|
+
const parallelViewport = resolveParallelRouteViewport(parallelRoute, options.params, routeSegments, pageSearchParams, accumulatedViewport, options.searchParamsObserver);
|
|
333
|
+
parallelRouteViewportPromises.push(parallelViewport.viewportResults);
|
|
334
|
+
accumulatedViewport = parallelViewport.resolvedViewport;
|
|
335
|
+
}
|
|
336
|
+
const parallelRouteViewportPromise = Promise.all(parallelRouteViewportPromises);
|
|
337
|
+
const hasDynamicMetadata = primaryHasDynamicMetadata || parallelRoutes.some(parallelRouteHasDynamicMetadata);
|
|
338
|
+
const metadata = Promise.all([
|
|
200
339
|
layoutMetadataPromise,
|
|
201
|
-
layoutViewportPromise,
|
|
202
340
|
pageMetadataPromise,
|
|
341
|
+
parallelRouteMetadataPromise
|
|
342
|
+
]).then(async ([layoutMetadataResults, pageMetadata, parallelRouteMetadata]) => {
|
|
343
|
+
const parallelMetadataResults = parallelRouteMetadata.flatMap((head) => head.metadataResults);
|
|
344
|
+
const parallelMetadataSources = parallelRouteMetadata.flatMap((head) => head.metadataSources);
|
|
345
|
+
const primaryPageHasTitle = pageMetadata != null && pageMetadata.title !== void 0;
|
|
346
|
+
const metadataEntries = [
|
|
347
|
+
...layoutMetadataResults.filter(isPresent).map((entry) => ({ metadata: entry })),
|
|
348
|
+
...pageMetadata ? [{
|
|
349
|
+
isPage: true,
|
|
350
|
+
metadata: pageMetadata
|
|
351
|
+
}] : [],
|
|
352
|
+
...parallelMetadataResults.filter(isPresent).map((entry) => ({
|
|
353
|
+
contributesTitle: !primaryPageHasTitle,
|
|
354
|
+
metadata: entry
|
|
355
|
+
}))
|
|
356
|
+
];
|
|
357
|
+
const resolvedMetadataBase = metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null;
|
|
358
|
+
const metadataSources = createMetadataSources(layoutMetadataResults, routeSegments, layoutSourcePositions, pageMetadata, Boolean(options.pageModule));
|
|
359
|
+
metadataSources.push(...parallelMetadataSources);
|
|
360
|
+
return finalizeAppPageMetadata(resolvedMetadataBase, metadataSources, options);
|
|
361
|
+
});
|
|
362
|
+
const viewport = Promise.all([
|
|
363
|
+
layoutViewportPromise,
|
|
203
364
|
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 = [
|
|
365
|
+
parallelRouteViewportPromise
|
|
366
|
+
]).then(([layoutViewportResults, pageViewport, parallelRouteViewports]) => mergeViewport([
|
|
223
367
|
...layoutViewportResults.filter(isPresent),
|
|
224
368
|
...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);
|
|
369
|
+
...parallelRouteViewports.flat().filter(isPresent)
|
|
370
|
+
]));
|
|
371
|
+
metadata.catch(() => null);
|
|
372
|
+
viewport.catch(() => null);
|
|
242
373
|
return {
|
|
243
374
|
hasDynamicMetadata,
|
|
244
375
|
hasSearchParams,
|
|
245
376
|
metadata,
|
|
246
377
|
pageSearchParams,
|
|
247
|
-
viewport
|
|
378
|
+
viewport
|
|
248
379
|
};
|
|
249
380
|
}
|
|
250
381
|
//#endregion
|
|
251
|
-
export { collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
382
|
+
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, ResolvedViewport } 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<ResolvedViewport>;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { createHttpAccessFallbackMetadataPlan, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { mergeViewport, resolveModuleViewport } from "../shims/metadata.js";
|
|
2
|
+
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
3
|
+
import { resolveOrderedAppPageMetadata } from "./app-page-head.js";
|
|
4
|
+
//#region src/server/app-page-http-access-fallback-metadata.ts
|
|
5
|
+
function isPresent(value) {
|
|
6
|
+
return value !== null && value !== void 0;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Translate HTTP-access boundary semantics into the exact metadata source
|
|
10
|
+
* order used by Next.js's loader-tree walk.
|
|
11
|
+
*
|
|
12
|
+
* The not-found convention is appended at every active leaf. A sibling
|
|
13
|
+
* intercept is the primary leaf and therefore precedes the ordinary slot
|
|
14
|
+
* branches; otherwise the convention also represents the primary page leaf.
|
|
15
|
+
*/
|
|
16
|
+
function createHttpAccessFallbackPlan(options, fallbackLeafMode) {
|
|
17
|
+
const routeSegments = options.routeSegments ?? [];
|
|
18
|
+
const plan = [];
|
|
19
|
+
for (const [index, layoutModule] of options.layoutModules.entries()) {
|
|
20
|
+
if (!isPresent(layoutModule)) continue;
|
|
21
|
+
const treePosition = options.layoutTreePositions?.[index] ?? 0;
|
|
22
|
+
plan.push({
|
|
23
|
+
kind: "source",
|
|
24
|
+
source: {
|
|
25
|
+
includeWhenEmpty: true,
|
|
26
|
+
module: layoutModule,
|
|
27
|
+
params: resolveAppPageSegmentParams(routeSegments, treePosition, options.params),
|
|
28
|
+
routeSegments: routeSegments.slice(0, treePosition)
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
let activeBoundaryModule = options.boundaryModule;
|
|
33
|
+
let activeBoundaryParams = options.boundaryParams;
|
|
34
|
+
let activeBoundaryRouteSegments = routeSegments;
|
|
35
|
+
const appendFallbackLeaf = () => {
|
|
36
|
+
if (fallbackLeafMode === "final") {
|
|
37
|
+
plan.push({ kind: "fallback-leaf" });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!activeBoundaryModule) return;
|
|
41
|
+
plan.push({
|
|
42
|
+
kind: "source",
|
|
43
|
+
source: {
|
|
44
|
+
includeWhenEmpty: true,
|
|
45
|
+
module: activeBoundaryModule,
|
|
46
|
+
params: activeBoundaryParams,
|
|
47
|
+
routeSegments: activeBoundaryRouteSegments
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
if (!options.primaryParallelBranch) appendFallbackLeaf();
|
|
52
|
+
const parallelBranches = [...options.primaryParallelBranch ? [options.primaryParallelBranch] : [], ...[...options.parallelBranches ?? []].sort((left, right) => right.ownerTreePosition - left.ownerTreePosition)];
|
|
53
|
+
for (const branch of parallelBranches) {
|
|
54
|
+
const parallelRoute = branch.head;
|
|
55
|
+
const parallelParams = parallelRoute.params ?? options.params;
|
|
56
|
+
const parallelRouteSegments = parallelRoute.routeSegments ?? routeSegments;
|
|
57
|
+
const layoutModules = [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
|
|
58
|
+
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
59
|
+
const layoutParams = parallelRoute.layoutParams ?? [];
|
|
60
|
+
for (const [index, layoutModule] of layoutModules.entries()) plan.push({
|
|
61
|
+
kind: "source",
|
|
62
|
+
source: {
|
|
63
|
+
includeWhenEmpty: true,
|
|
64
|
+
module: layoutModule,
|
|
65
|
+
params: layoutParams[index] ?? resolveAppPageBranchParams(parallelRouteSegments, layoutTreePositions[index] ?? 0, parallelParams),
|
|
66
|
+
routeSegments: parallelRouteSegments
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
if (options.branchNotFoundConventions !== false && branch.notFoundModule) {
|
|
70
|
+
activeBoundaryModule = branch.notFoundModule;
|
|
71
|
+
activeBoundaryParams = branch.notFoundParams ?? parallelParams;
|
|
72
|
+
activeBoundaryRouteSegments = parallelRouteSegments;
|
|
73
|
+
}
|
|
74
|
+
appendFallbackLeaf();
|
|
75
|
+
}
|
|
76
|
+
return plan.flatMap((item) => {
|
|
77
|
+
if (item.kind === "source") return [item.source];
|
|
78
|
+
if (!activeBoundaryModule) return [];
|
|
79
|
+
return [{
|
|
80
|
+
includeWhenEmpty: true,
|
|
81
|
+
module: activeBoundaryModule,
|
|
82
|
+
params: activeBoundaryParams,
|
|
83
|
+
routeSegments: activeBoundaryRouteSegments
|
|
84
|
+
}];
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function createHttpAccessFallbackMetadataPlan(options) {
|
|
88
|
+
return createHttpAccessFallbackPlan(options, "final");
|
|
89
|
+
}
|
|
90
|
+
function resolveHttpAccessFallbackMetadata(options) {
|
|
91
|
+
return resolveOrderedAppPageMetadata({
|
|
92
|
+
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
93
|
+
basePath: options.basePath,
|
|
94
|
+
fallbackOnFileMetadataError: options.fallbackOnFileMetadataError,
|
|
95
|
+
metadataRoutes: options.metadataRoutes,
|
|
96
|
+
params: options.params,
|
|
97
|
+
routePath: options.routePath,
|
|
98
|
+
routeSegments: options.routeSegments,
|
|
99
|
+
sources: createHttpAccessFallbackMetadataPlan(options)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async function resolveHttpAccessFallbackViewport(options) {
|
|
103
|
+
let accumulatedViewport = Promise.resolve(mergeViewport([]));
|
|
104
|
+
for (const source of createHttpAccessFallbackPlan(options, "snapshot")) {
|
|
105
|
+
const parentForSource = accumulatedViewport;
|
|
106
|
+
const viewportPromise = resolveModuleViewport(source.module, source.params, void 0, parentForSource);
|
|
107
|
+
viewportPromise.catch(() => null);
|
|
108
|
+
accumulatedViewport = Promise.all([parentForSource, viewportPromise]).then(([parent, viewport]) => viewport ? mergeViewport([parent, viewport]) : parent);
|
|
109
|
+
accumulatedViewport.catch(() => null);
|
|
110
|
+
}
|
|
111
|
+
return accumulatedViewport;
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { createHttpAccessFallbackMetadataPlan, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport };
|
|
@@ -40,12 +40,16 @@ type AppPageProbeModule = Readonly<{
|
|
|
40
40
|
}> | null | undefined;
|
|
41
41
|
type AppPageProbeSlot = Readonly<{
|
|
42
42
|
page?: AppPageProbeModule;
|
|
43
|
+
loading?: AppPageProbeModule;
|
|
44
|
+
loadings?: readonly AppPageProbeModule[] | null;
|
|
45
|
+
loadingTreePositions?: readonly number[] | null;
|
|
43
46
|
}> | null | undefined;
|
|
44
47
|
type AppPageProbeRoute = Readonly<{
|
|
45
48
|
slots?: Readonly<Record<string, AppPageProbeSlot>> | null;
|
|
46
49
|
}>;
|
|
47
50
|
type AppPageProbeIntercept = Readonly<{
|
|
48
51
|
page?: AppPageProbeModule;
|
|
52
|
+
interceptLoadings?: readonly AppPageProbeModule[] | null;
|
|
49
53
|
matchedParams?: unknown;
|
|
50
54
|
/**
|
|
51
55
|
* Key of the parallel-route slot this interception overrides. At render
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { markAppPagePropsForUseCache } from "../shims/internal/app-page-props-cache-key.js";
|
|
2
1
|
import { isNextRouterError } from "../shims/navigation-errors.js";
|
|
3
2
|
import "../shims/navigation-server.js";
|
|
3
|
+
import { markAppPagePropsForUseCache } from "../shims/internal/app-page-props-cache-key.js";
|
|
4
4
|
import { isPromiseLike } from "../utils/promise.js";
|
|
5
5
|
import { probeAppPageComponent, probeAppPageLayouts } from "./app-page-execution.js";
|
|
6
6
|
import { collectAppPageSearchParams } from "./app-page-head.js";
|
|
@@ -218,13 +218,17 @@ function buildAppPageProbes(options) {
|
|
|
218
218
|
const overriddenSlotKey = intercept?.slotKey ?? null;
|
|
219
219
|
for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {
|
|
220
220
|
if (overriddenSlotKey !== null && slotKey === overriddenSlotKey) continue;
|
|
221
|
+
if (slot?.loading?.default || slot?.loadings?.some((loading) => loading?.default)) continue;
|
|
221
222
|
probes.push(probeAppPage({
|
|
222
223
|
pageComponent: slot?.page?.default,
|
|
223
224
|
asyncRouteParams,
|
|
224
225
|
searchParams
|
|
225
226
|
}));
|
|
226
227
|
}
|
|
227
|
-
|
|
228
|
+
const interceptedSlot = intercept?.slotKey ? route.slots?.[intercept.slotKey] : null;
|
|
229
|
+
const interceptedSlotHasRootLoading = Boolean(interceptedSlot?.loading?.default || interceptedSlot?.loadings?.some((loading, index) => loading?.default && interceptedSlot.loadingTreePositions?.[index] === 0));
|
|
230
|
+
const interceptHasLoadingBoundary = Boolean(intercept?.interceptLoadings?.some((loading) => loading?.default) || interceptedSlotHasRootLoading);
|
|
231
|
+
if (intercept && !interceptHasLoadingBoundary) probes.push(probeAppPage({
|
|
228
232
|
pageComponent: intercept.page?.default,
|
|
229
233
|
asyncRouteParams: options.makeThenableParams(intercept.matchedParams ?? matchedParams),
|
|
230
234
|
searchParams
|
|
@@ -3,11 +3,11 @@ import { AppOutgoingElements } from "./app-elements-wire.js";
|
|
|
3
3
|
import { NavigationContext } from "../shims/navigation-context-state.js";
|
|
4
4
|
import { AppPageFontPreload, AppPageSpecialError, LayoutClassificationOptions } from "./app-page-execution.js";
|
|
5
5
|
import { AppPageMiddlewareContext } from "./app-page-response.js";
|
|
6
|
+
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
7
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
6
8
|
import { RootParams } from "../shims/root-params.js";
|
|
7
9
|
import { AppPageSsrHandler } from "./app-page-stream.js";
|
|
8
|
-
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
9
10
|
import { CachedAppPageValue } from "../shims/cache-handler.js";
|
|
10
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
11
11
|
import { AppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
12
12
|
import { ReactNode } from "react";
|
|
13
13
|
import { ReactFormState } from "react-dom/client";
|
|
@@ -11,10 +11,10 @@ import { DEFAULT_CACHE_VARIANT_BUDGET, buildCacheVariantWithRouteBudget, buildRe
|
|
|
11
11
|
import { createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope, createEmptyAppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
12
12
|
import { finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse } from "./app-page-cache-finalizer.js";
|
|
13
13
|
import { createStaticLayoutClientReuseArtifactCompatibility, createStaticLayoutClientReusePayloadHash, createStaticLayoutClientReuseRouteId } from "./static-layout-client-reuse-proof.js";
|
|
14
|
+
import { hasDigest } from "./app-rsc-errors.js";
|
|
14
15
|
import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
|
|
15
16
|
import { buildAppPageLinkHeader, createAppPageFontData, createAppPageRscErrorTracker, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery } from "./app-page-stream.js";
|
|
16
17
|
import { getStaticLayoutObservationSkipRejection } from "./app-layout-param-observation.js";
|
|
17
|
-
import { hasDigest } from "./app-rsc-errors.js";
|
|
18
18
|
import { createClientReuseSkipTransportPlan, crossCheckClientReuseManifestEntryWithCache } from "./skip-cache-proof.js";
|
|
19
19
|
//#region src/server/app-page-render.ts
|
|
20
20
|
function buildResponseTiming(options) {
|
|
@@ -11,7 +11,13 @@ type GenerateStaticParamsModule = {
|
|
|
11
11
|
generateStaticParams?: GenerateStaticParams | null;
|
|
12
12
|
};
|
|
13
13
|
type GenerateStaticParamsSource = {
|
|
14
|
+
/**
|
|
15
|
+
* Primary loader-tree sources execute top-down as one chain. Each source
|
|
16
|
+
* receives the complete params object produced by the sources before it.
|
|
17
|
+
*/
|
|
18
|
+
chained?: true;
|
|
14
19
|
generateStaticParams: GenerateStaticParams;
|
|
20
|
+
independentChain?: number;
|
|
15
21
|
paramAliases?: Readonly<Record<string, string>>;
|
|
16
22
|
paramPatternParts?: readonly string[];
|
|
17
23
|
routePatternParts?: readonly string[];
|
|
@@ -56,14 +62,23 @@ type AppPageInterceptMatch<TPage = unknown> = {
|
|
|
56
62
|
interceptLayouts?: readonly unknown[] | null;
|
|
57
63
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
58
64
|
interceptBranchSegments?: readonly string[] | null;
|
|
65
|
+
interceptLoadings?: readonly unknown[] | null;
|
|
66
|
+
interceptLoadingTreePositions?: readonly number[] | null;
|
|
67
|
+
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
59
68
|
__loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
|
|
69
|
+
__loadInterceptLoadings?: readonly (() => Promise<unknown>)[] | null;
|
|
60
70
|
matchedParams: AppPageParams;
|
|
61
71
|
sourceMatchedParams?: AppPageParams;
|
|
62
72
|
page: TPage;
|
|
63
73
|
__pageLoader?: (() => Promise<TPage>) | null;
|
|
74
|
+
notFound?: unknown;
|
|
75
|
+
__loadNotFound?: (() => Promise<unknown>) | null;
|
|
76
|
+
notFoundTreePosition?: number | null;
|
|
64
77
|
__loadState?: {
|
|
65
78
|
page: TPage;
|
|
66
79
|
pageLoading: Promise<TPage> | null;
|
|
80
|
+
notFound?: unknown;
|
|
81
|
+
notFoundLoading?: Promise<unknown> | null;
|
|
67
82
|
interceptLayoutsLoading: Promise<readonly unknown[]> | null;
|
|
68
83
|
};
|
|
69
84
|
slotId?: string | null;
|