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
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
return mergeViewport((await Promise.all(createHttpAccessFallbackPlan(options, "snapshot").map((source) => resolveModuleViewport(source.module, source.params)))).filter(isPresent));
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { createHttpAccessFallbackMetadataPlan, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport };
|
|
@@ -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,20 @@ type AppPageInterceptMatch<TPage = unknown> = {
|
|
|
56
62
|
interceptLayouts?: readonly unknown[] | null;
|
|
57
63
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
58
64
|
interceptBranchSegments?: readonly string[] | null;
|
|
65
|
+
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
59
66
|
__loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
|
|
60
67
|
matchedParams: AppPageParams;
|
|
61
68
|
sourceMatchedParams?: AppPageParams;
|
|
62
69
|
page: TPage;
|
|
63
70
|
__pageLoader?: (() => Promise<TPage>) | null;
|
|
71
|
+
notFound?: unknown;
|
|
72
|
+
__loadNotFound?: (() => Promise<unknown>) | null;
|
|
73
|
+
notFoundTreePosition?: number | null;
|
|
64
74
|
__loadState?: {
|
|
65
75
|
page: TPage;
|
|
66
76
|
pageLoading: Promise<TPage> | null;
|
|
77
|
+
notFound?: unknown;
|
|
78
|
+
notFoundLoading?: Promise<unknown> | null;
|
|
67
79
|
interceptLayoutsLoading: Promise<readonly unknown[]> | null;
|
|
68
80
|
};
|
|
69
81
|
slotId?: string | null;
|
|
@@ -46,8 +46,14 @@ function collectParentParamNames(routeSegments, boundaryPosition) {
|
|
|
46
46
|
}
|
|
47
47
|
return names;
|
|
48
48
|
}
|
|
49
|
-
function getLayoutGenerateStaticParamsBoundary(layoutTreePosition) {
|
|
50
|
-
|
|
49
|
+
function getLayoutGenerateStaticParamsBoundary(routeSegments, layoutTreePosition) {
|
|
50
|
+
let boundary = Math.min((layoutTreePosition ?? 0) - 1, routeSegments.length - 1);
|
|
51
|
+
while (boundary >= 0) {
|
|
52
|
+
const segment = routeSegments[boundary];
|
|
53
|
+
if (!segment.startsWith("@") && !(segment.startsWith("(") && segment.endsWith(")"))) break;
|
|
54
|
+
boundary -= 1;
|
|
55
|
+
}
|
|
56
|
+
return boundary;
|
|
51
57
|
}
|
|
52
58
|
function getParallelParentParamNames(routeParamNames, branch, boundaryPosition) {
|
|
53
59
|
const slotParamNames = branch.paramNames ?? routeParamNames;
|
|
@@ -64,11 +70,13 @@ function resolveAppPageGenerateStaticParamsSources(options) {
|
|
|
64
70
|
options.layouts?.forEach((layout, index) => {
|
|
65
71
|
if (typeof layout?.generateStaticParams !== "function") return;
|
|
66
72
|
sources.push({
|
|
73
|
+
chained: true,
|
|
67
74
|
generateStaticParams: layout.generateStaticParams,
|
|
68
|
-
parentParamNames: collectParentParamNames(options.routeSegments, getLayoutGenerateStaticParamsBoundary(options.layoutTreePositions?.[index]))
|
|
75
|
+
parentParamNames: collectParentParamNames(options.routeSegments, getLayoutGenerateStaticParamsBoundary(options.routeSegments, options.layoutTreePositions?.[index]))
|
|
69
76
|
});
|
|
70
77
|
});
|
|
71
78
|
if (typeof options.page?.generateStaticParams === "function") sources.push({
|
|
79
|
+
chained: true,
|
|
72
80
|
generateStaticParams: options.page.generateStaticParams,
|
|
73
81
|
parentParamNames: collectParentParamNames(options.routeSegments, Math.max(0, options.routeSegments.length - 1))
|
|
74
82
|
});
|
|
@@ -76,7 +84,7 @@ function resolveAppPageGenerateStaticParamsSources(options) {
|
|
|
76
84
|
const name = getAppPageSegmentParamName(segment);
|
|
77
85
|
return name ? [name] : [];
|
|
78
86
|
});
|
|
79
|
-
for (const parallelBranch of options.parallelBranches ?? []) {
|
|
87
|
+
for (const [independentChain, parallelBranch] of (options.parallelBranches ?? []).entries()) {
|
|
80
88
|
if (!parallelBranch) continue;
|
|
81
89
|
const slotParamNames = parallelBranch.paramNames ?? routeParamNames;
|
|
82
90
|
const paramAliases = Object.fromEntries(routeParamNames.flatMap((routeParamName, index) => {
|
|
@@ -87,6 +95,7 @@ function resolveAppPageGenerateStaticParamsSources(options) {
|
|
|
87
95
|
if (typeof module?.generateStaticParams !== "function") return;
|
|
88
96
|
sources.push({
|
|
89
97
|
generateStaticParams: module.generateStaticParams,
|
|
98
|
+
independentChain,
|
|
90
99
|
...Object.keys(paramAliases).length > 0 ? { paramAliases } : {},
|
|
91
100
|
...parallelBranch.patternParts ? { paramPatternParts: parallelBranch.patternParts } : {},
|
|
92
101
|
...options.routePatternParts ? { routePatternParts: options.routePatternParts } : {},
|
|
@@ -95,24 +104,101 @@ function resolveAppPageGenerateStaticParamsSources(options) {
|
|
|
95
104
|
};
|
|
96
105
|
addParallelSource(parallelBranch.layout, -1);
|
|
97
106
|
parallelBranch.configLayouts?.forEach((layout, index) => {
|
|
98
|
-
addParallelSource(layout, getLayoutGenerateStaticParamsBoundary(parallelBranch.configLayoutTreePositions?.[index]));
|
|
107
|
+
addParallelSource(layout, getLayoutGenerateStaticParamsBoundary(parallelBranch.routeSegments ?? [], parallelBranch.configLayoutTreePositions?.[index]));
|
|
99
108
|
});
|
|
100
109
|
addParallelSource(parallelBranch.page, Math.max(0, (parallelBranch.routeSegments?.length ?? 0) - 1));
|
|
101
110
|
}
|
|
102
111
|
return sources;
|
|
103
112
|
}
|
|
104
|
-
function areStaticParamsAllowed(params, staticParams) {
|
|
113
|
+
function areStaticParamsAllowed(params, staticParams, allowMissingValues = false) {
|
|
105
114
|
const paramKeys = Object.keys(params);
|
|
115
|
+
const stringParamMatches = (value, staticValue) => value === encodeURIComponent(staticValue);
|
|
106
116
|
return staticParams.some((staticParamSet) => paramKeys.every((key) => {
|
|
107
117
|
const value = params[key];
|
|
108
118
|
const staticValue = staticParamSet[key];
|
|
109
|
-
if (
|
|
110
|
-
if (Array.isArray(value)) return Array.isArray(staticValue) && value.length === staticValue.length && value.every((part, index) => typeof staticValue[index] === "string" ? part
|
|
111
|
-
if (typeof staticValue === "string") return value
|
|
119
|
+
if (!Object.hasOwn(staticParamSet, key)) return allowMissingValues;
|
|
120
|
+
if (Array.isArray(value)) return Array.isArray(staticValue) && value.length === staticValue.length && value.every((part, index) => typeof staticValue[index] === "string" ? stringParamMatches(part, staticValue[index]) : part === staticValue[index]);
|
|
121
|
+
if (typeof staticValue === "string") return stringParamMatches(value, staticValue);
|
|
112
122
|
if (typeof staticValue === "number" || typeof staticValue === "boolean") return String(value) === String(staticValue);
|
|
113
123
|
return JSON.stringify(value) === JSON.stringify(staticValue);
|
|
114
124
|
}));
|
|
115
125
|
}
|
|
126
|
+
function remapStaticParamsToRouteParams(staticParams, source) {
|
|
127
|
+
if (!source.paramAliases) return [...staticParams];
|
|
128
|
+
const routeParamNamesBySourceName = new Map(Object.entries(source.paramAliases).map(([routeParamName, sourceParamName]) => [sourceParamName, routeParamName]));
|
|
129
|
+
return staticParams.map((params) => Object.fromEntries(Object.entries(params).map(([name, value]) => [routeParamNamesBySourceName.get(name) ?? name, value])));
|
|
130
|
+
}
|
|
131
|
+
async function generateIndependentStaticParams(sources, primaryParams, requestParams) {
|
|
132
|
+
let rows = (primaryParams ?? []).map((params) => ({
|
|
133
|
+
params,
|
|
134
|
+
branchParams: {}
|
|
135
|
+
}));
|
|
136
|
+
let hasParentParams = rows.length > 0;
|
|
137
|
+
let validated = false;
|
|
138
|
+
for (const source of sources) {
|
|
139
|
+
const parents = hasParentParams ? rows : [{
|
|
140
|
+
params: {},
|
|
141
|
+
branchParams: {}
|
|
142
|
+
}];
|
|
143
|
+
const nextRows = [];
|
|
144
|
+
for (const parent of parents) {
|
|
145
|
+
const sourceParams = remapRouteParams({
|
|
146
|
+
...requestParams,
|
|
147
|
+
...parent.params
|
|
148
|
+
}, source);
|
|
149
|
+
const branchParams = remapRouteParams(parent.branchParams, source);
|
|
150
|
+
const result = await runWithFetchDedupe(() => source.generateStaticParams({ params: {
|
|
151
|
+
...pickRouteParams(sourceParams, source.parentParamNames),
|
|
152
|
+
...branchParams
|
|
153
|
+
} }));
|
|
154
|
+
if (!Array.isArray(result)) {
|
|
155
|
+
if (hasParentParams) nextRows.push(parent);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
validated = true;
|
|
159
|
+
const routeResults = remapStaticParamsToRouteParams(result, source);
|
|
160
|
+
if (routeResults.length === 0) {
|
|
161
|
+
if (hasParentParams) nextRows.push(parent);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
for (const routeResult of routeResults) nextRows.push({
|
|
165
|
+
params: {
|
|
166
|
+
...parent.params,
|
|
167
|
+
...routeResult
|
|
168
|
+
},
|
|
169
|
+
branchParams: {
|
|
170
|
+
...parent.branchParams,
|
|
171
|
+
...routeResult
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
rows = nextRows;
|
|
176
|
+
hasParentParams = rows.length > 0;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
staticParams: rows.map((row) => row.params),
|
|
180
|
+
validated
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async function generateChainedStaticParams(sources) {
|
|
184
|
+
let generatedParams = [];
|
|
185
|
+
for (const source of sources) {
|
|
186
|
+
const hasParentParams = generatedParams.length > 0;
|
|
187
|
+
const parents = hasParentParams ? generatedParams : [{}];
|
|
188
|
+
const nextParams = [];
|
|
189
|
+
for (const parentParams of parents) {
|
|
190
|
+
const result = await runWithFetchDedupe(() => source.generateStaticParams({ params: parentParams }));
|
|
191
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
192
|
+
for (const item of result) if (item !== null && typeof item === "object" && !Array.isArray(item)) nextParams.push({
|
|
193
|
+
...parentParams,
|
|
194
|
+
...item
|
|
195
|
+
});
|
|
196
|
+
} else if (hasParentParams) nextParams.push(parentParams);
|
|
197
|
+
}
|
|
198
|
+
generatedParams = nextParams;
|
|
199
|
+
}
|
|
200
|
+
return generatedParams;
|
|
201
|
+
}
|
|
116
202
|
function normalizeGenerateStaticParams(generateStaticParams) {
|
|
117
203
|
return (Array.isArray(generateStaticParams) ? generateStaticParams : [generateStaticParams]).flatMap((source) => {
|
|
118
204
|
if (typeof source === "function") return [{
|
|
@@ -130,10 +216,28 @@ async function validateAppPageDynamicParams(options) {
|
|
|
130
216
|
options.clearRequestContext();
|
|
131
217
|
return notFoundResponse();
|
|
132
218
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
219
|
+
const chainedSources = generateStaticParamsSources.filter((source) => source.chained);
|
|
220
|
+
let chainedStaticParams = null;
|
|
221
|
+
if (chainedSources.length > 0) chainedStaticParams = await generateChainedStaticParams(chainedSources);
|
|
222
|
+
const independentChains = /* @__PURE__ */ new Map();
|
|
223
|
+
for (const source of generateStaticParamsSources.filter((source) => !source.chained)) {
|
|
224
|
+
const chain = independentChains.get(source.independentChain ?? source) ?? [];
|
|
225
|
+
chain.push(source);
|
|
226
|
+
independentChains.set(source.independentChain ?? source, chain);
|
|
227
|
+
}
|
|
228
|
+
let validatedIndependentResults = false;
|
|
229
|
+
for (const sources of independentChains.values()) {
|
|
230
|
+
const result = await generateIndependentStaticParams(sources, chainedStaticParams, options.params);
|
|
231
|
+
if (result.validated) {
|
|
232
|
+
validatedIndependentResults = true;
|
|
233
|
+
if (!areStaticParamsAllowed(options.params, result.staticParams, true)) {
|
|
234
|
+
options.clearRequestContext();
|
|
235
|
+
return notFoundResponse();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (chainedStaticParams && !validatedIndependentResults) {
|
|
240
|
+
if (!areStaticParamsAllowed(options.params, chainedStaticParams)) {
|
|
137
241
|
options.clearRequestContext();
|
|
138
242
|
return notFoundResponse();
|
|
139
243
|
}
|
|
@@ -187,6 +291,22 @@ async function resolveAppPageInterceptState(options) {
|
|
|
187
291
|
if (loadState) loadState.pageLoading = loading;
|
|
188
292
|
await loading;
|
|
189
293
|
}
|
|
294
|
+
if (loadState?.notFound != null) intercept.notFound = loadState.notFound;
|
|
295
|
+
if (intercept.__loadNotFound && intercept.notFound == null) {
|
|
296
|
+
const loading = loadState?.notFoundLoading ?? intercept.__loadNotFound().then((notFound) => {
|
|
297
|
+
intercept.notFound = notFound;
|
|
298
|
+
if (loadState) {
|
|
299
|
+
loadState.notFound = notFound;
|
|
300
|
+
loadState.notFoundLoading = null;
|
|
301
|
+
}
|
|
302
|
+
return notFound;
|
|
303
|
+
}).catch((error) => {
|
|
304
|
+
if (loadState) loadState.notFoundLoading = null;
|
|
305
|
+
throw error;
|
|
306
|
+
});
|
|
307
|
+
if (loadState) loadState.notFoundLoading = loading;
|
|
308
|
+
await loading;
|
|
309
|
+
}
|
|
190
310
|
if (intercept.__loadInterceptLayouts) await loadAppInterceptLayouts(intercept);
|
|
191
311
|
const sourceRoute = await options.getSourceRoute(intercept.sourceRouteIndex);
|
|
192
312
|
if (!sourceRoute) return { kind: "none" };
|
|
@@ -37,6 +37,8 @@ type AppPageRouteWiringSlot<TModule extends AppPageModule = AppPageModule, TErro
|
|
|
37
37
|
layout?: TModule | null;
|
|
38
38
|
layoutIndex: number;
|
|
39
39
|
loading?: TModule | null;
|
|
40
|
+
notFound?: TModule | null;
|
|
41
|
+
notFoundTreePosition?: number | null;
|
|
40
42
|
page?: TModule | null;
|
|
41
43
|
routeSegments?: readonly string[] | null;
|
|
42
44
|
/**
|
|
@@ -59,9 +61,12 @@ type AppPageRouteWiringRoute<TModule extends AppPageModule = AppPageModule, TErr
|
|
|
59
61
|
loading?: TModule | null;
|
|
60
62
|
notFound?: TModule | null;
|
|
61
63
|
notFounds?: readonly (TModule | null | undefined)[] | null;
|
|
64
|
+
notFoundTreePosition?: number | null;
|
|
62
65
|
forbidden?: TModule | null;
|
|
66
|
+
forbiddenTreePosition?: number | null;
|
|
63
67
|
forbiddens?: readonly (TModule | null | undefined)[] | null;
|
|
64
68
|
unauthorized?: TModule | null;
|
|
69
|
+
unauthorizedTreePosition?: number | null;
|
|
65
70
|
unauthorizeds?: readonly (TModule | null | undefined)[] | null;
|
|
66
71
|
routeSegments?: readonly string[];
|
|
67
72
|
childrenRouteSegments?: readonly string[] | null;
|
|
@@ -124,6 +129,10 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
|
|
|
124
129
|
resolvedMetadata: Metadata | null;
|
|
125
130
|
resolvedMetadataPathname?: string;
|
|
126
131
|
resolvedViewport: Viewport;
|
|
132
|
+
streamingMetadata?: Promise<Metadata | null> | null;
|
|
133
|
+
streamingMetadataOutlet?: Promise<unknown> | null;
|
|
134
|
+
streamingMetadataOutletSuspended?: boolean;
|
|
135
|
+
streamingMetadataTags?: Promise<Metadata | null> | null;
|
|
127
136
|
trailingSlash?: boolean;
|
|
128
137
|
rootForbiddenModule?: TModule | null;
|
|
129
138
|
rootNotFoundModule?: TModule | null;
|
|
@@ -179,6 +179,37 @@ function createAppPageRouteBodyMetadata(metadata, pathname, metadataPlacement, t
|
|
|
179
179
|
dangerouslySetInnerHTML: { __html: renderMetadataToHtml(metadata, pathname, { trailingSlash }) }
|
|
180
180
|
});
|
|
181
181
|
}
|
|
182
|
+
async function AppPageStreamingMetadata(props) {
|
|
183
|
+
try {
|
|
184
|
+
return createAppPageRouteBodyMetadata(await props.metadata, props.pathname, "body", props.trailingSlash);
|
|
185
|
+
} catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
AppPageStreamingMetadata.displayName = "Vinext.StreamingMetadata";
|
|
190
|
+
async function AppPageMetadataOutlet(props) {
|
|
191
|
+
await props.metadata;
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
AppPageMetadataOutlet.displayName = "Vinext.MetadataOutlet";
|
|
195
|
+
function createAppPageStreamingMetadataOutlet(elementId, suspended = true) {
|
|
196
|
+
if (!elementId) return null;
|
|
197
|
+
const outlet = /* @__PURE__ */ jsx(Slot, { id: elementId });
|
|
198
|
+
return suspended ? /* @__PURE__ */ jsx(Suspense, {
|
|
199
|
+
fallback: null,
|
|
200
|
+
children: outlet
|
|
201
|
+
}) : outlet;
|
|
202
|
+
}
|
|
203
|
+
function createAppPageStreamingMetadataBody(elementId) {
|
|
204
|
+
if (!elementId) return null;
|
|
205
|
+
return /* @__PURE__ */ jsx("div", {
|
|
206
|
+
hidden: true,
|
|
207
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
208
|
+
fallback: null,
|
|
209
|
+
children: /* @__PURE__ */ jsx(Slot, { id: elementId })
|
|
210
|
+
})
|
|
211
|
+
});
|
|
212
|
+
}
|
|
182
213
|
function buildAppPageElements(options) {
|
|
183
214
|
const renderIdentity = options.renderIdentity;
|
|
184
215
|
const interceptionContext = renderIdentity?.interceptionContext ?? options.interceptionContext ?? null;
|
|
@@ -188,6 +219,8 @@ function buildAppPageElements(options) {
|
|
|
188
219
|
const routeId = renderIdentity?.routeId ?? AppElementsWire.encodeRouteId(options.routePath, interceptionContext);
|
|
189
220
|
const pageId = renderIdentity?.pageId ?? AppElementsWire.encodePageId(options.routePath, interceptionContext);
|
|
190
221
|
const pageElementId = options.route.childrenSlot?.id ?? pageId;
|
|
222
|
+
const streamingMetadataBodyId = options.streamingMetadata ? `__vinext_streaming_metadata_body:${routeId}` : null;
|
|
223
|
+
const streamingMetadataOutletId = options.streamingMetadataOutlet ? `__vinext_streaming_metadata_outlet:${routeId}` : null;
|
|
191
224
|
const layoutEntries = createAppPageLayoutEntries(options.route);
|
|
192
225
|
const templateEntries = createAppPageTemplateEntries(options.route);
|
|
193
226
|
const errorEntries = createAppPageErrorEntries(options.route);
|
|
@@ -237,6 +270,12 @@ function buildAppPageElements(options) {
|
|
|
237
270
|
})
|
|
238
271
|
}) };
|
|
239
272
|
if (options.route.staticSiblings && options.route.staticSiblings.length > 0) elements[APP_STATIC_SIBLINGS_KEY] = options.route.staticSiblings;
|
|
273
|
+
if (options.streamingMetadata && streamingMetadataBodyId) elements[streamingMetadataBodyId] = /* @__PURE__ */ jsx(AppPageStreamingMetadata, {
|
|
274
|
+
metadata: options.streamingMetadataTags ?? options.streamingMetadata,
|
|
275
|
+
pathname: options.resolvedMetadataPathname ?? options.routePath,
|
|
276
|
+
trailingSlash: options.trailingSlash
|
|
277
|
+
});
|
|
278
|
+
if (options.streamingMetadataOutlet && streamingMetadataOutletId) elements[streamingMetadataOutletId] = /* @__PURE__ */ jsx(AppPageMetadataOutlet, { metadata: options.streamingMetadataOutlet });
|
|
240
279
|
const getEffectiveSlotParams = (slotKey, slotName) => resolveSlotOverride(slotKey, slotName)?.params ?? options.matchedParams;
|
|
241
280
|
for (const treePosition of orderedTreePositions) {
|
|
242
281
|
const layoutIndex = layoutIndicesByTreePosition.get(treePosition);
|
|
@@ -365,11 +404,11 @@ function buildAppPageElements(options) {
|
|
|
365
404
|
});
|
|
366
405
|
elements[slotId] = renderAfterAppDependencies(slotElement, targetIndex >= 0 ? slotDependenciesByLayoutIndex[targetIndex] ?? [] : []);
|
|
367
406
|
}
|
|
368
|
-
let routeChildren = /* @__PURE__ */ jsx(LayoutSegmentProvider, {
|
|
407
|
+
let routeChildren = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(LayoutSegmentProvider, {
|
|
369
408
|
providerId: pageElementId,
|
|
370
409
|
segmentMap: { children: [APP_PAGE_SEGMENT_KEY] },
|
|
371
410
|
children: /* @__PURE__ */ jsx(Slot, { id: pageElementId })
|
|
372
|
-
});
|
|
411
|
+
}), createAppPageStreamingMetadataOutlet(streamingMetadataOutletId, options.streamingMetadataOutletSuspended)] });
|
|
373
412
|
if (isPrefetchLoadingShell) if (routeLoadingComponent === null) routeChildren = null;
|
|
374
413
|
else routeChildren = /* @__PURE__ */ jsx(routeLoadingComponent, {});
|
|
375
414
|
else {
|
|
@@ -479,7 +518,8 @@ function buildAppPageElements(options) {
|
|
|
479
518
|
elements[routeId] = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
480
519
|
createAppPageRouteHead(options.resolvedMetadata, options.resolvedViewport, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash),
|
|
481
520
|
routeChildren,
|
|
482
|
-
createAppPageRouteBodyMetadata(options.resolvedMetadata, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash)
|
|
521
|
+
createAppPageRouteBodyMetadata(options.resolvedMetadata, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash),
|
|
522
|
+
createAppPageStreamingMetadataBody(streamingMetadataBodyId)
|
|
483
523
|
] });
|
|
484
524
|
registerAppElementRenderDependencies(elements, renderDependenciesByElementId);
|
|
485
525
|
return elements;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeHost, requestContextFromRequest } from "../config/
|
|
1
|
+
import { normalizeHost, requestContextFromRequest } from "../config/request-context.js";
|
|
2
2
|
import { getHeadersContext } from "../shims/headers.js";
|
|
3
3
|
//#region src/server/app-post-middleware-context.ts
|
|
4
4
|
/**
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
3
3
|
import { reportRequestError } from "./instrumentation.js";
|
|
4
|
-
import { consumeDynamicUsage, getAndClearPendingCookies, getDraftModeCookieHeader, markDynamicUsage, setHeadersAccessPhase } from "../shims/headers.js";
|
|
4
|
+
import { consumeDynamicUsage, getActiveDraftModeState, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, markDynamicUsage, setHeadersAccessPhase } from "../shims/headers.js";
|
|
5
|
+
import { _drainPendingRevalidations } from "../shims/cache-request-state.js";
|
|
5
6
|
import { ensureFetchPatch, getCollectedFetchTags, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
|
|
6
7
|
import { setNavigationContext } from "../shims/navigation-context-state.js";
|
|
7
8
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
8
9
|
import "../shims/navigation.js";
|
|
9
10
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
10
|
-
import { applyRouteHandlerMiddlewareContext } from "./app-route-handler-response.js";
|
|
11
|
+
import { applyRouteHandlerMiddlewareContext, finalizeRouteHandlerResponse } from "./app-route-handler-response.js";
|
|
11
12
|
import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
|
|
12
13
|
import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
|
|
13
14
|
import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
14
|
-
import { executeAppRouteHandler } from "./app-route-handler-execution.js";
|
|
15
|
+
import { applyDraftModeCachePolicy, executeAppRouteHandler } from "./app-route-handler-execution.js";
|
|
15
16
|
import { readAppRouteHandlerCacheResponse } from "./app-route-handler-cache.js";
|
|
16
17
|
import { resolveAppRouteHandlerFetchCacheMode } from "./app-segment-config.js";
|
|
17
18
|
//#region src/server/app-route-handler-dispatch.ts
|
|
@@ -37,7 +38,11 @@ async function runInRouteHandlerRevalidationContext(options, renderFn) {
|
|
|
37
38
|
setCurrentFetchSoftTags(buildRouteHandlerPageCacheTags(options.cleanPathname, [], options.routeSegments));
|
|
38
39
|
setCurrentFetchCacheMode(options.fetchCacheMode);
|
|
39
40
|
setCurrentForceDynamicFetchDefault(options.dynamicConfig === "force-dynamic");
|
|
40
|
-
|
|
41
|
+
try {
|
|
42
|
+
await renderFn();
|
|
43
|
+
} finally {
|
|
44
|
+
await _drainPendingRevalidations();
|
|
45
|
+
}
|
|
41
46
|
});
|
|
42
47
|
}
|
|
43
48
|
async function dispatchAppRouteHandler(options) {
|
|
@@ -47,19 +52,25 @@ async function dispatchAppRouteHandler(options) {
|
|
|
47
52
|
const revalidateSeconds = getAppRouteHandlerRevalidateSeconds(handler);
|
|
48
53
|
const isDevelopment = options.isDevelopment ?? process.env.NODE_ENV === "development";
|
|
49
54
|
const isProduction = options.isProduction ?? process.env.NODE_ENV === "production";
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
const isDraftMode = getActiveDraftModeState() ?? isDraftModeRequest(options.request, options.draftModeSecret);
|
|
56
|
+
const initialDraftModeCookie = getDraftModeCookieHeader();
|
|
57
|
+
const hasDraftModeTransition = initialDraftModeCookie != null;
|
|
58
|
+
const finalizeFrameworkResponse = (response, isHead = false) => {
|
|
59
|
+
const finalized = finalizeRouteHandlerResponse(response, {
|
|
60
|
+
pendingCookies: getAndClearPendingCookies(),
|
|
61
|
+
draftCookie: initialDraftModeCookie,
|
|
62
|
+
isHead
|
|
63
|
+
});
|
|
52
64
|
options.clearRequestContext();
|
|
53
|
-
return applyRouteHandlerMiddlewareContext(
|
|
54
|
-
}
|
|
65
|
+
return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalized, options.middlewareContext), isDraftMode || hasDraftModeTransition);
|
|
66
|
+
};
|
|
67
|
+
if (hasAppRouteHandlerDefaultExport(handler) && isDevelopment) console.error("[vinext] Detected default export in route handler " + route.pattern + ". Export a named export for each HTTP method instead.");
|
|
68
|
+
if (!isValidHTTPMethod(method)) return finalizeFrameworkResponse(new Response(null, { status: 400 }));
|
|
55
69
|
const { allowHeaderForOptions, handlerFn, isAutoHead, shouldAutoRespondToOptions } = resolveAppRouteHandlerMethod(handler, method);
|
|
56
|
-
if (shouldAutoRespondToOptions) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
headers: { Allow: allowHeaderForOptions }
|
|
61
|
-
}), options.middlewareContext);
|
|
62
|
-
}
|
|
70
|
+
if (shouldAutoRespondToOptions) return finalizeFrameworkResponse(new Response(null, {
|
|
71
|
+
status: 204,
|
|
72
|
+
headers: { Allow: allowHeaderForOptions }
|
|
73
|
+
}));
|
|
63
74
|
const resolvedHandlerFn = isAppRouteHandlerFunction(handlerFn) ? handlerFn : void 0;
|
|
64
75
|
const fetchCacheMode = resolveAppRouteHandlerFetchCacheMode(handler);
|
|
65
76
|
setCurrentFetchCacheMode(fetchCacheMode);
|
|
@@ -69,6 +80,7 @@ async function dispatchAppRouteHandler(options) {
|
|
|
69
80
|
handlerFn: resolvedHandlerFn,
|
|
70
81
|
isAutoHead,
|
|
71
82
|
isKnownDynamic: isKnownDynamicAppRoute(route.pattern),
|
|
83
|
+
isDraftMode: isDraftMode || hasDraftModeTransition,
|
|
72
84
|
isProduction,
|
|
73
85
|
method,
|
|
74
86
|
revalidateSeconds
|
|
@@ -133,12 +145,15 @@ async function dispatchAppRouteHandler(options) {
|
|
|
133
145
|
executionContext: getRequestExecutionContext(),
|
|
134
146
|
getAndClearPendingCookies,
|
|
135
147
|
getCollectedFetchTags,
|
|
148
|
+
getActiveDraftModeState,
|
|
136
149
|
getDraftModeCookieHeader,
|
|
137
150
|
handler,
|
|
138
151
|
handlerFn: resolvedHandlerFn,
|
|
139
152
|
i18n: options.i18n,
|
|
140
153
|
trailingSlash: options.trailingSlash,
|
|
141
154
|
isAutoHead,
|
|
155
|
+
initialDraftModeCookie,
|
|
156
|
+
isDraftMode,
|
|
142
157
|
isProduction,
|
|
143
158
|
isrDebug: options.isrDebug,
|
|
144
159
|
isrRouteKey: options.isrRouteKey,
|
|
@@ -157,8 +172,7 @@ async function dispatchAppRouteHandler(options) {
|
|
|
157
172
|
routePattern: route.pattern,
|
|
158
173
|
setHeadersAccessPhase
|
|
159
174
|
});
|
|
160
|
-
|
|
161
|
-
return applyRouteHandlerMiddlewareContext(new Response(null, { status: 405 }), options.middlewareContext);
|
|
175
|
+
return finalizeFrameworkResponse(new Response(null, { status: 405 }));
|
|
162
176
|
}
|
|
163
177
|
//#endregion
|
|
164
178
|
export { dispatchAppRouteHandler };
|
|
@@ -42,6 +42,7 @@ type RunAppRouteHandlerOptions = {
|
|
|
42
42
|
dynamicConfig?: string;
|
|
43
43
|
handlerFn: AppRouteHandlerFunction;
|
|
44
44
|
i18n?: NextI18nConfig | null;
|
|
45
|
+
isDraftMode?: boolean;
|
|
45
46
|
trailingSlash?: boolean;
|
|
46
47
|
markDynamicUsage: MarkAppRouteDynamicUsageFn;
|
|
47
48
|
middlewareRequestHeaders?: Headers | null;
|
|
@@ -58,6 +59,7 @@ type RunAppRouteHandlerResult = {
|
|
|
58
59
|
dynamicUsedInHandler: boolean;
|
|
59
60
|
response: Response;
|
|
60
61
|
};
|
|
62
|
+
declare function applyDraftModeCachePolicy(response: Response, isDraftMode: boolean): Response;
|
|
61
63
|
type ExecuteAppRouteHandlerOptions = {
|
|
62
64
|
buildPageCacheTags: (pathname: string, extraTags: string[]) => string[];
|
|
63
65
|
clearRequestContext: () => void;
|
|
@@ -65,9 +67,12 @@ type ExecuteAppRouteHandlerOptions = {
|
|
|
65
67
|
executionContext: ExecutionContextLike | null;
|
|
66
68
|
getAndClearPendingCookies: () => string[];
|
|
67
69
|
getCollectedFetchTags: () => string[];
|
|
70
|
+
getActiveDraftModeState?: () => boolean | null;
|
|
68
71
|
getDraftModeCookieHeader: () => string | null | undefined;
|
|
69
72
|
handler: AppRouteHandlerModule;
|
|
70
73
|
isAutoHead: boolean;
|
|
74
|
+
initialDraftModeCookie?: string | null;
|
|
75
|
+
isDraftMode?: boolean;
|
|
71
76
|
isProduction: boolean;
|
|
72
77
|
isrDebug?: AppRouteDebugLogger;
|
|
73
78
|
isrRouteKey: (pathname: string) => string;
|
|
@@ -83,4 +88,4 @@ type ExecuteAppRouteHandlerOptions = {
|
|
|
83
88
|
declare function runAppRouteHandler(options: RunAppRouteHandlerOptions): Promise<RunAppRouteHandlerResult>;
|
|
84
89
|
declare function executeAppRouteHandler(options: ExecuteAppRouteHandlerOptions): Promise<Response>;
|
|
85
90
|
//#endregion
|
|
86
|
-
export { AppRouteDebugLogger, AppRouteDynamicUsageFn, AppRouteHandlerFunction, AppRouteParams, MarkAppRouteDynamicUsageFn, RouteHandlerCacheSetter, executeAppRouteHandler, runAppRouteHandler };
|
|
91
|
+
export { AppRouteDebugLogger, AppRouteDynamicUsageFn, AppRouteHandlerFunction, AppRouteParams, MarkAppRouteDynamicUsageFn, RouteHandlerCacheSetter, applyDraftModeCachePolicy, executeAppRouteHandler, runAppRouteHandler };
|