@qzsy/vinext 0.1.12 → 0.1.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/check.d.ts +8 -0
- package/dist/check.js +20 -9
- package/dist/cli.js +2 -2
- package/dist/deploy.js +10 -11
- package/dist/entries/app-rsc-entry.js +37 -8
- package/dist/entries/app-rsc-manifest.js +8 -0
- package/dist/entries/pages-client-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +1 -0
- package/dist/index.js +12 -8
- package/dist/init.js +2 -1
- package/dist/plugins/middleware-server-only.d.ts +8 -6
- package/dist/plugins/middleware-server-only.js +8 -7
- package/dist/routing/app-route-graph.d.ts +6 -2
- package/dist/routing/app-route-graph.js +60 -12
- package/dist/routing/app-router.d.ts +5 -0
- package/dist/routing/app-router.js +5 -0
- package/dist/routing/file-matcher.d.ts +5 -0
- package/dist/routing/file-matcher.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +2 -1
- package/dist/server/app-browser-history-controller.js +6 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -1
- package/dist/server/app-fallback-renderer.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +12 -3
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +8 -2
- package/dist/server/app-page-dispatch.d.ts +11 -3
- package/dist/server/app-page-dispatch.js +54 -15
- package/dist/server/app-page-element-builder.d.ts +5 -1
- package/dist/server/app-page-element-builder.js +55 -19
- package/dist/server/app-page-head.d.ts +12 -0
- package/dist/server/app-page-head.js +42 -19
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +8 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +1 -1
- package/dist/server/app-page-render.d.ts +4 -1
- package/dist/server/app-page-render.js +8 -3
- package/dist/server/app-page-request.d.ts +8 -1
- package/dist/server/app-page-request.js +23 -11
- package/dist/server/app-page-route-wiring.d.ts +6 -1
- package/dist/server/app-page-route-wiring.js +30 -8
- package/dist/server/app-page-search-params-observation.d.ts +4 -2
- package/dist/server/app-page-search-params-observation.js +11 -7
- package/dist/server/app-route-handler-dispatch.js +1 -0
- package/dist/server/app-route-handler-execution.js +2 -1
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.d.ts +12 -0
- package/dist/server/app-router-entry.js +13 -6
- package/dist/server/app-router-image-optimization.d.ts +37 -0
- package/dist/server/app-router-image-optimization.js +40 -0
- package/dist/server/app-rsc-errors.js +7 -1
- package/dist/server/app-rsc-handler.js +5 -2
- package/dist/server/app-rsc-route-matching.d.ts +7 -0
- package/dist/server/app-rsc-route-matching.js +36 -3
- package/dist/server/app-segment-config.d.ts +1 -0
- package/dist/server/app-segment-config.js +32 -2
- package/dist/server/app-server-action-execution.d.ts +4 -0
- package/dist/server/app-server-action-execution.js +41 -10
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +1 -0
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/prod-server.js +15 -6
- package/dist/server/worker-utils.d.ts +2 -1
- package/dist/server/worker-utils.js +7 -1
- package/dist/shims/error-boundary.d.ts +19 -1
- package/dist/shims/error-boundary.js +11 -1
- package/dist/shims/headers.d.ts +3 -1
- package/dist/shims/headers.js +16 -5
- package/dist/shims/metadata.d.ts +3 -2
- package/dist/shims/metadata.js +8 -4
- package/dist/shims/router.js +13 -2
- package/dist/typegen.js +6 -5
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +1 -1
- package/dist/utils/project.d.ts +4 -0
- package/dist/utils/project.js +5 -1
- package/package.json +1 -1
|
@@ -360,8 +360,8 @@ async function buildAppRouteGraph(appDir, matcher) {
|
|
|
360
360
|
const routePatterns = new Set(routes.map((route) => route.pattern));
|
|
361
361
|
const ghostParentRoutes = [];
|
|
362
362
|
for await (const file of scanWithExtensions("**/layout", appDir, scanMatcher.extensions, excludeDir)) {
|
|
363
|
-
const dir = path.dirname(file);
|
|
364
|
-
const routeDir = dir === "." ? appDir : path.join(appDir, dir);
|
|
363
|
+
const dir = path.posix.dirname(file);
|
|
364
|
+
const routeDir = dir === "." ? appDir : path.posix.join(appDir, dir);
|
|
365
365
|
if (!hasParallelSlotDirectory(routeDir)) continue;
|
|
366
366
|
if (discoverParallelSlots(routeDir, appDir, scanMatcher).length === 0) continue;
|
|
367
367
|
const route = directoryToAppRoute(dir, appDir, scanMatcher, null, null);
|
|
@@ -434,11 +434,16 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
434
434
|
const applySlotSubPages = (route, slotPages, rawSegments) => {
|
|
435
435
|
route.parallelSlots = route.parallelSlots.map((slot) => {
|
|
436
436
|
const subPage = slotPages.get(slot.key);
|
|
437
|
-
if (subPage !== void 0)
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
437
|
+
if (subPage !== void 0) {
|
|
438
|
+
const configLayoutPaths = findSlotConfigLayoutPaths(slot.ownerDir, subPage, matcher);
|
|
439
|
+
return {
|
|
440
|
+
...slot,
|
|
441
|
+
pagePath: subPage,
|
|
442
|
+
configLayoutPaths,
|
|
443
|
+
configLayoutTreePositions: findSlotConfigLayoutTreePositions(slot.ownerDir, configLayoutPaths),
|
|
444
|
+
routeSegments: rawSegments
|
|
445
|
+
};
|
|
446
|
+
}
|
|
442
447
|
return slot;
|
|
443
448
|
});
|
|
444
449
|
};
|
|
@@ -495,9 +500,12 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
495
500
|
if (Array.from(routesByPattern.values()).some((r) => patternsStructurallyEquivalent(r.patternParts, syntheticParts))) continue;
|
|
496
501
|
const subSlots = parentRoute.parallelSlots.map((slot) => {
|
|
497
502
|
const subPage = slotPages.get(slot.key);
|
|
503
|
+
const configLayoutPaths = findSlotConfigLayoutPaths(slot.ownerDir, subPage ?? null, matcher);
|
|
498
504
|
return {
|
|
499
505
|
...slot,
|
|
500
506
|
pagePath: subPage || null,
|
|
507
|
+
configLayoutPaths,
|
|
508
|
+
configLayoutTreePositions: findSlotConfigLayoutTreePositions(slot.ownerDir, configLayoutPaths),
|
|
501
509
|
routeSegments: subPage ? rawSegments : null
|
|
502
510
|
};
|
|
503
511
|
});
|
|
@@ -574,6 +582,23 @@ function findSlotSubPages(slotDir, matcher) {
|
|
|
574
582
|
perMatcher.set(slotDir, results);
|
|
575
583
|
return results;
|
|
576
584
|
}
|
|
585
|
+
function findSlotConfigLayoutPaths(slotDir, pagePath, matcher) {
|
|
586
|
+
if (!pagePath) return [];
|
|
587
|
+
const layouts = [];
|
|
588
|
+
let dir = path.dirname(pagePath);
|
|
589
|
+
while (dir !== slotDir && dir.startsWith(`${slotDir}${path.sep}`)) {
|
|
590
|
+
const layoutPath = findFile(dir, "layout", matcher);
|
|
591
|
+
if (layoutPath) layouts.unshift(layoutPath);
|
|
592
|
+
dir = path.dirname(dir);
|
|
593
|
+
}
|
|
594
|
+
return layouts;
|
|
595
|
+
}
|
|
596
|
+
function findSlotConfigLayoutTreePositions(slotDir, layoutPaths) {
|
|
597
|
+
return layoutPaths.map((layoutPath) => {
|
|
598
|
+
const relativeDir = path.relative(slotDir, path.dirname(layoutPath));
|
|
599
|
+
return relativeDir ? relativeDir.split(path.sep).filter(Boolean).length : 0;
|
|
600
|
+
});
|
|
601
|
+
}
|
|
577
602
|
/**
|
|
578
603
|
* Find a sibling catch-all page directly under `dir`, i.e. a `[...slug]` or
|
|
579
604
|
* `[[...slug]]` directory that contains a `page` file. Returns the absolute
|
|
@@ -613,8 +638,14 @@ function fileToAppRoute(file, appDir, type, matcher) {
|
|
|
613
638
|
}
|
|
614
639
|
return directoryToAppRoute(dir, appDir, matcher, type === "page" ? path.join(appDir, file) : null, type === "route" ? path.join(appDir, file) : null);
|
|
615
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* `dir` and `appDir` must both be forward-slash. `dir` is split on
|
|
643
|
+
* `path.posix.sep` and joined onto `appDir` with `path.posix.join`, and `appDir`
|
|
644
|
+
* is threaded to the layout/slot/boundary discovery below, which build paths the
|
|
645
|
+
* same way.
|
|
646
|
+
*/
|
|
616
647
|
function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
617
|
-
const segments = dir === "." ? [] : dir.split(path.sep);
|
|
648
|
+
const segments = dir === "." ? [] : dir.split(path.posix.sep);
|
|
618
649
|
const params = [];
|
|
619
650
|
let isDynamic = false;
|
|
620
651
|
const convertedRoute = convertSegmentsToRouteParts(segments);
|
|
@@ -631,7 +662,7 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
|
631
662
|
const errorEntries = discoverSegmentErrors(segments, appDir, matcher);
|
|
632
663
|
const errorPaths = errorEntries.map((entry) => entry.path);
|
|
633
664
|
const errorTreePositions = errorEntries.map((entry) => entry.treePosition);
|
|
634
|
-
const routeDir = dir === "." ? appDir : path.join(appDir, dir);
|
|
665
|
+
const routeDir = dir === "." ? appDir : path.posix.join(appDir, dir);
|
|
635
666
|
const loadingPath = findFile(routeDir, "loading", matcher);
|
|
636
667
|
const errorPath = findFile(routeDir, "error", matcher);
|
|
637
668
|
const notFoundPath = discoverBoundaryFile(segments, appDir, "not-found", matcher);
|
|
@@ -863,6 +894,10 @@ function discoverBoundaryFilePerLayout(layouts, fileName, matcher) {
|
|
|
863
894
|
* Walk from appDir through each segment to the route's directory. At each level
|
|
864
895
|
* that has @slot dirs, collect them. Slots at the route's own directory level
|
|
865
896
|
* use page.tsx; slots at ancestor levels use default.tsx only.
|
|
897
|
+
*
|
|
898
|
+
* `appDir` and `routeDir` must be forward-slash — `currentDir` descends from
|
|
899
|
+
* `appDir` via `path.posix.join`, and the `dir === routeDir` active-level test
|
|
900
|
+
* below only matches when both share the canonical separator.
|
|
866
901
|
*/
|
|
867
902
|
function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
|
|
868
903
|
const slotMap = /* @__PURE__ */ new Map();
|
|
@@ -875,7 +910,7 @@ function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
|
|
|
875
910
|
segmentIndex: 0
|
|
876
911
|
});
|
|
877
912
|
for (let i = 0; i < segments.length; i++) {
|
|
878
|
-
currentDir = path.join(currentDir, segments[i]);
|
|
913
|
+
currentDir = path.posix.join(currentDir, segments[i]);
|
|
879
914
|
if (findFile(currentDir, "layout", matcher)) layoutIdx++;
|
|
880
915
|
dirsToCheck.push({
|
|
881
916
|
dir: currentDir,
|
|
@@ -902,9 +937,12 @@ function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
|
|
|
902
937
|
slotPatternParts = [...ownerUrl?.urlSegments ?? [], ...mirror.slotUrlSegments];
|
|
903
938
|
slotParamNames = [...ownerUrl?.params ?? [], ...mirror.slotParamNames];
|
|
904
939
|
}
|
|
940
|
+
const configLayoutPaths = findSlotConfigLayoutPaths(slot.ownerDir, mirror?.pagePath ?? null, matcher);
|
|
905
941
|
const inheritedSlot = {
|
|
906
942
|
...slot,
|
|
907
943
|
pagePath: mirror?.pagePath ?? null,
|
|
944
|
+
configLayoutPaths,
|
|
945
|
+
configLayoutTreePositions: findSlotConfigLayoutTreePositions(slot.ownerDir, configLayoutPaths),
|
|
908
946
|
layoutIndex: slotLayoutIdx,
|
|
909
947
|
routeSegments: mirror?.segments ?? null,
|
|
910
948
|
slotPatternParts,
|
|
@@ -1035,6 +1073,9 @@ function patternsStructurallyEquivalent(a, b) {
|
|
|
1035
1073
|
*
|
|
1036
1074
|
* Returns the absolute page path, or null if no root-level page is found.
|
|
1037
1075
|
*
|
|
1076
|
+
* `slotDir` must be forward-slash: the `path.posix.join` descent stays a
|
|
1077
|
+
* canonical id only when the base already is.
|
|
1078
|
+
*
|
|
1038
1079
|
* Only descends into route-group directories (those whose name starts with `(`
|
|
1039
1080
|
* and ends with `)`). Dynamic segments, regular named dirs, and `@slot` dirs
|
|
1040
1081
|
* are not transparent and are therefore not searched.
|
|
@@ -1051,7 +1092,7 @@ function findSlotRootPage(slotDir, matcher) {
|
|
|
1051
1092
|
for (const entry of entries) {
|
|
1052
1093
|
if (!entry.isDirectory()) continue;
|
|
1053
1094
|
if (!entry.name.startsWith("(") || !entry.name.endsWith(")")) continue;
|
|
1054
|
-
const found = findSlotRootPage(path.join(slotDir, entry.name), matcher);
|
|
1095
|
+
const found = findSlotRootPage(path.posix.join(slotDir, entry.name), matcher);
|
|
1055
1096
|
if (found) return found;
|
|
1056
1097
|
}
|
|
1057
1098
|
return null;
|
|
@@ -1068,13 +1109,14 @@ function discoverParallelSlots(dir, appDir, matcher) {
|
|
|
1068
1109
|
if (!entry.isDirectory() || !entry.name.startsWith("@")) continue;
|
|
1069
1110
|
if (entry.name === "@children") continue;
|
|
1070
1111
|
const slotName = entry.name.slice(1);
|
|
1071
|
-
const slotDir = path.join(dir, entry.name);
|
|
1112
|
+
const slotDir = path.posix.join(dir, entry.name);
|
|
1072
1113
|
const pagePath = findSlotRootPage(slotDir, matcher);
|
|
1073
1114
|
const defaultPath = findFile(slotDir, "default", matcher);
|
|
1074
1115
|
const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);
|
|
1075
1116
|
if (!pagePath && !defaultPath && interceptingRoutes.length === 0) continue;
|
|
1076
1117
|
const ownerSegments = path.relative(appDir, dir).split(path.sep).filter((segment) => segment.length > 0);
|
|
1077
1118
|
const ownerTreePath = createAppRouteGraphTreePath(ownerSegments, ownerSegments.length);
|
|
1119
|
+
const configLayoutPaths = findSlotConfigLayoutPaths(slotDir, pagePath, matcher);
|
|
1078
1120
|
slots.push({
|
|
1079
1121
|
id: createAppRouteGraphSlotId(slotName, ownerTreePath),
|
|
1080
1122
|
key: `${slotName}@${path.relative(appDir, slotDir).replace(/\\/g, "/")}`,
|
|
@@ -1085,6 +1127,8 @@ function discoverParallelSlots(dir, appDir, matcher) {
|
|
|
1085
1127
|
pagePath,
|
|
1086
1128
|
defaultPath,
|
|
1087
1129
|
layoutPath: findFile(slotDir, "layout", matcher),
|
|
1130
|
+
configLayoutPaths,
|
|
1131
|
+
configLayoutTreePositions: findSlotConfigLayoutTreePositions(slotDir, configLayoutPaths),
|
|
1088
1132
|
loadingPath: findFile(slotDir, "loading", matcher),
|
|
1089
1133
|
errorPath: findFile(slotDir, "error", matcher),
|
|
1090
1134
|
interceptingRoutes,
|
|
@@ -1272,8 +1316,12 @@ function collectInterceptingPages(currentDir, interceptRoot, convention, interce
|
|
|
1272
1316
|
if (targetPattern) {
|
|
1273
1317
|
const sourceMatchPattern = computeInterceptSourceMatchPattern(interceptParentDir, appDir);
|
|
1274
1318
|
results.push({
|
|
1319
|
+
branchSegments: [interceptSegment, ...normalizePathSeparators(path.relative(interceptRoot, path.dirname(page))).split("/").filter(Boolean)],
|
|
1275
1320
|
convention,
|
|
1276
1321
|
layoutPaths: [...layoutPaths],
|
|
1322
|
+
layoutSegments: layoutPaths.map((layoutPath) => {
|
|
1323
|
+
return [interceptSegment, ...path.relative(interceptRoot, path.dirname(layoutPath)).split(path.sep).filter(Boolean)];
|
|
1324
|
+
}),
|
|
1277
1325
|
targetPattern: targetPattern.pattern,
|
|
1278
1326
|
sourceMatchPattern,
|
|
1279
1327
|
pagePath: page,
|
|
@@ -12,11 +12,16 @@ declare function invalidateAppRouteCache(): void;
|
|
|
12
12
|
* TODO(#726): Layer 4 should consume this read model directly once the
|
|
13
13
|
* navigation planner owns route graph facts.
|
|
14
14
|
*
|
|
15
|
+
* `appDir` must be forward-slash — callers normalize it at their entry, and it
|
|
16
|
+
* flows into `buildAppRouteGraph`, which builds every path with `path.posix.*`.
|
|
17
|
+
*
|
|
15
18
|
* @internal
|
|
16
19
|
*/
|
|
17
20
|
declare function appRouteGraph(appDir: string, pageExtensions?: readonly string[], matcher?: ValidFileMatcher): Promise<AppRouteGraph>;
|
|
18
21
|
/**
|
|
19
22
|
* Scan the app/ directory and return a list of routes.
|
|
23
|
+
*
|
|
24
|
+
* `appDir` must be forward-slash — it is forwarded to `appRouteGraph`.
|
|
20
25
|
*/
|
|
21
26
|
declare function appRouter(appDir: string, pageExtensions?: readonly string[], matcher?: ValidFileMatcher): Promise<AppRouteGraphRoute[]>;
|
|
22
27
|
/**
|
|
@@ -30,6 +30,9 @@ function invalidateAppRouteCache() {
|
|
|
30
30
|
* TODO(#726): Layer 4 should consume this read model directly once the
|
|
31
31
|
* navigation planner owns route graph facts.
|
|
32
32
|
*
|
|
33
|
+
* `appDir` must be forward-slash — callers normalize it at their entry, and it
|
|
34
|
+
* flows into `buildAppRouteGraph`, which builds every path with `path.posix.*`.
|
|
35
|
+
*
|
|
33
36
|
* @internal
|
|
34
37
|
*/
|
|
35
38
|
async function appRouteGraph(appDir, pageExtensions, matcher) {
|
|
@@ -44,6 +47,8 @@ async function appRouteGraph(appDir, pageExtensions, matcher) {
|
|
|
44
47
|
}
|
|
45
48
|
/**
|
|
46
49
|
* Scan the app/ directory and return a list of routes.
|
|
50
|
+
*
|
|
51
|
+
* `appDir` must be forward-slash — it is forwarded to `appRouteGraph`.
|
|
47
52
|
*/
|
|
48
53
|
async function appRouter(appDir, pageExtensions, matcher) {
|
|
49
54
|
return (await appRouteGraph(appDir, pageExtensions, matcher)).routes;
|
|
@@ -54,6 +54,11 @@ declare function buildViteResolveExtensions(pageExtensions?: readonly string[] |
|
|
|
54
54
|
declare function normalizeViteResolveExtensions(extensions: readonly string[]): string[];
|
|
55
55
|
/**
|
|
56
56
|
* Use function-form exclude for Node < 22.14 compatibility.
|
|
57
|
+
*
|
|
58
|
+
* Yields forward-slash relative paths: node's glob emits native (backslash)
|
|
59
|
+
* separators on Windows, so each match is normalized — this is the entry point
|
|
60
|
+
* that lets downstream consumers treat the scanned paths as canonical
|
|
61
|
+
* forward-slash ids.
|
|
57
62
|
*/
|
|
58
63
|
declare function scanWithExtensions(stem: string, cwd: string, extensions: readonly string[], exclude?: (name: string) => boolean): AsyncGenerator<string>;
|
|
59
64
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePathSeparators } from "../utils/path.js";
|
|
1
2
|
import { escapeRegExp } from "../utils/regex.js";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
@@ -135,13 +136,18 @@ function normalizeViteResolveExtensions(extensions) {
|
|
|
135
136
|
}
|
|
136
137
|
/**
|
|
137
138
|
* Use function-form exclude for Node < 22.14 compatibility.
|
|
139
|
+
*
|
|
140
|
+
* Yields forward-slash relative paths: node's glob emits native (backslash)
|
|
141
|
+
* separators on Windows, so each match is normalized — this is the entry point
|
|
142
|
+
* that lets downstream consumers treat the scanned paths as canonical
|
|
143
|
+
* forward-slash ids.
|
|
138
144
|
*/
|
|
139
145
|
async function* scanWithExtensions(stem, cwd, extensions, exclude) {
|
|
140
146
|
const pattern = buildExtensionGlob(stem, extensions);
|
|
141
147
|
for await (const file of glob(pattern, {
|
|
142
148
|
cwd,
|
|
143
149
|
...exclude ? { exclude } : {}
|
|
144
|
-
})) yield file;
|
|
150
|
+
})) yield normalizePathSeparators(file);
|
|
145
151
|
}
|
|
146
152
|
//#endregion
|
|
147
153
|
export { buildViteResolveExtensions, createValidFileMatcher, findFileWithExtensions, findFileWithExts, normalizePageExtensions, normalizeViteResolveExtensions, scanWithExtensions };
|
|
@@ -45,6 +45,7 @@ type CommitNavigationHistoryOptions = {
|
|
|
45
45
|
targetHistoryIndex?: number | null;
|
|
46
46
|
stageClientParams: () => void;
|
|
47
47
|
};
|
|
48
|
+
declare function createCanonicalBrowserHistoryHref(href: string): string;
|
|
48
49
|
/**
|
|
49
50
|
* Owns App Router browser-history metadata and traversal bookkeeping behind a
|
|
50
51
|
* typed seam: traversal index allocation/commit, push/replace/traverse/hash-only
|
|
@@ -101,4 +102,4 @@ declare class AppBrowserHistoryController {
|
|
|
101
102
|
restoreHistorySnapshot(options: RestoreHistorySnapshotOptions): boolean;
|
|
102
103
|
}
|
|
103
104
|
//#endregion
|
|
104
|
-
export { AppBrowserHistoryController, RestorableSnapshotCandidate };
|
|
105
|
+
export { AppBrowserHistoryController, RestorableSnapshotCandidate, createCanonicalBrowserHistoryHref };
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { RestorableClientStateController, createHistoryStateWithNavigationMetadata, readHistoryStateBfcacheIds, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
|
|
2
2
|
//#region src/server/app-browser-history-controller.ts
|
|
3
|
+
function createCanonicalBrowserHistoryHref(href) {
|
|
4
|
+
const url = new URL(href);
|
|
5
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
6
|
+
}
|
|
3
7
|
function stripVinextScrollState(state) {
|
|
4
8
|
if (!state || typeof state !== "object") return state;
|
|
5
9
|
const nextState = {};
|
|
@@ -166,7 +170,7 @@ var AppBrowserHistoryController = class {
|
|
|
166
170
|
this.#replaceHistoryState(createHistoryStateWithNavigationMetadata(this.#readHistoryState(), {
|
|
167
171
|
previousNextUrl: null,
|
|
168
172
|
traversalIndex: this.#currentHistoryTraversalIndex
|
|
169
|
-
}), this.#readCurrentHref());
|
|
173
|
+
}), createCanonicalBrowserHistoryHref(this.#readCurrentHref()));
|
|
170
174
|
}
|
|
171
175
|
/** History write performed on the first committed (hydrated) render. */
|
|
172
176
|
writeHydratedHistoryMetadata(options) {
|
|
@@ -207,4 +211,4 @@ function areBfcacheIdMapsEqual(a, b) {
|
|
|
207
211
|
return aEntries.every(([key, value]) => b[key] === value);
|
|
208
212
|
}
|
|
209
213
|
//#endregion
|
|
210
|
-
export { AppBrowserHistoryController };
|
|
214
|
+
export { AppBrowserHistoryController, createCanonicalBrowserHistoryHref };
|
|
@@ -75,7 +75,7 @@ type AppFallbackRendererCallContext = {
|
|
|
75
75
|
sourcePageSegments?: readonly string[] | null;
|
|
76
76
|
};
|
|
77
77
|
type AppFallbackRenderer<TModule extends AppPageModule = AppPageModule> = {
|
|
78
|
-
renderErrorBoundary: (route: AppPageBoundaryRoute<TModule> | null, error: unknown, isRscRequest: boolean, request: Request, matchedParams: AppPageParams | undefined, scriptNonce: string | undefined, middlewareContext: AppPageMiddlewareContext, callContext?: AppFallbackRendererCallContext) => Promise<Response | null>;
|
|
78
|
+
renderErrorBoundary: (route: AppPageBoundaryRoute<TModule> | null, error: unknown, isRscRequest: boolean, request: Request, matchedParams: AppPageParams | undefined, scriptNonce: string | undefined, middlewareContext: AppPageMiddlewareContext, callContext?: AppFallbackRendererCallContext, errorOrigin?: "rsc" | "ssr") => Promise<Response | null>;
|
|
79
79
|
renderHttpAccessFallback: (route: AppPageBoundaryRoute<TModule> | null, statusCode: number, isRscRequest: boolean, request: Request, opts: {
|
|
80
80
|
boundaryComponent?: AppPageComponent | null;
|
|
81
81
|
boundaryModule?: TModule | null;
|
|
@@ -97,7 +97,7 @@ function createAppFallbackRenderer(options) {
|
|
|
97
97
|
renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext) {
|
|
98
98
|
return this.renderHttpAccessFallback(route, 404, isRscRequest, request, { matchedParams }, scriptNonce, middlewareContext, callContext);
|
|
99
99
|
},
|
|
100
|
-
renderErrorBoundary(route, error, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext) {
|
|
100
|
+
renderErrorBoundary(route, error, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext, errorOrigin = "rsc") {
|
|
101
101
|
return renderAppPageErrorBoundary({
|
|
102
102
|
applyFileBasedMetadata,
|
|
103
103
|
basePath,
|
|
@@ -108,6 +108,7 @@ function createAppFallbackRenderer(options) {
|
|
|
108
108
|
return buildRscOnErrorHandler(request, pathname, routePath);
|
|
109
109
|
},
|
|
110
110
|
error,
|
|
111
|
+
errorOrigin,
|
|
111
112
|
getFontLinks: fontProviders.getFontLinks,
|
|
112
113
|
getFontPreloads: fontProviders.getFontPreloads,
|
|
113
114
|
getFontStyles: fontProviders.getFontStyles,
|
|
@@ -75,6 +75,7 @@ type RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppP
|
|
|
75
75
|
} & AppPageBoundaryRenderCommonOptions<TModule>;
|
|
76
76
|
type RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {
|
|
77
77
|
error: unknown;
|
|
78
|
+
errorOrigin?: "rsc" | "ssr";
|
|
78
79
|
matchedParams?: AppPageParams | null;
|
|
79
80
|
route?: AppPageBoundaryRoute<TModule> | null;
|
|
80
81
|
sanitizeErrorForClient: (error: Error) => Error;
|
|
@@ -3,7 +3,7 @@ import { AppElementsWire } from "./app-elements-wire.js";
|
|
|
3
3
|
import "./app-elements.js";
|
|
4
4
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
5
5
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
6
|
-
import { ErrorBoundary, GlobalErrorBoundary } from "../shims/error-boundary.js";
|
|
6
|
+
import { ErrorBoundary, GlobalErrorBoundary, SerializedErrorBoundary } from "../shims/error-boundary.js";
|
|
7
7
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
8
8
|
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
9
9
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
@@ -215,7 +215,7 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
215
215
|
if (!errorBoundary.component) return null;
|
|
216
216
|
const rawError = options.error instanceof Error ? options.error : new Error(String(options.error));
|
|
217
217
|
rewriteClientHookError(rawError);
|
|
218
|
-
const errorObject = options.sanitizeErrorForClient(rawError);
|
|
218
|
+
const errorObject = options.errorOrigin === "ssr" ? rawError : options.sanitizeErrorForClient(rawError);
|
|
219
219
|
const matchedParams = options.matchedParams ?? options.route?.params ?? {};
|
|
220
220
|
const layoutModules = options.route?.layouts ?? options.rootLayouts;
|
|
221
221
|
const pathname = new URL(options.requestUrl).pathname;
|
|
@@ -249,7 +249,16 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
249
249
|
console.error(`[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`, error);
|
|
250
250
|
}
|
|
251
251
|
const buildElement = (BoundaryComponent) => {
|
|
252
|
-
const
|
|
252
|
+
const serializedError = {
|
|
253
|
+
digest: "digest" in errorObject ? String(errorObject.digest) : void 0,
|
|
254
|
+
message: errorObject.message,
|
|
255
|
+
name: errorObject.name,
|
|
256
|
+
stack: process.env.NODE_ENV !== "production" ? errorObject.stack : void 0
|
|
257
|
+
};
|
|
258
|
+
const boundaryElement = errorBoundary.isGlobalError && BoundaryComponent !== DEFAULT_GLOBAL_ERROR_COMPONENT ? createElement(SerializedErrorBoundary, {
|
|
259
|
+
error: serializedError,
|
|
260
|
+
fallback: BoundaryComponent
|
|
261
|
+
}) : createElement(BoundaryComponent, { error: errorObject });
|
|
253
262
|
return wrapRenderedBoundaryElement({
|
|
254
263
|
element: createElement(Fragment, null, ...headElements, errorBoundary.isGlobalError ? createElement(GlobalErrorBoundary, {
|
|
255
264
|
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
@@ -30,6 +30,7 @@ type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
|
30
30
|
isrRscKey: AppPageRscCacheKeyBuilder;
|
|
31
31
|
isrSet: AppPageCacheSetter;
|
|
32
32
|
interceptionContext?: string | null;
|
|
33
|
+
omitPendingDynamicCacheState?: boolean;
|
|
33
34
|
preserveClientResponseHeaders?: boolean;
|
|
34
35
|
expireSeconds?: number;
|
|
35
36
|
revalidateSeconds: number | null;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { NEXTJS_CACHE_HEADER, VINEXT_CACHE_HEADER } from "./headers.js";
|
|
1
2
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
2
3
|
import { applyCdnResponseHeaders } from "./cache-control.js";
|
|
3
4
|
import { buildAppPageCacheValue } from "./isr-cache.js";
|
|
4
5
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
5
6
|
import { createEmptyAppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
6
7
|
//#region src/server/app-page-cache-finalizer.ts
|
|
7
|
-
function applyPendingDynamicCdnHeaders(headers, tags) {
|
|
8
|
+
function applyPendingDynamicCdnHeaders(headers, tags, options = {}) {
|
|
8
9
|
applyCdnResponseHeaders(headers, {
|
|
9
10
|
cacheControl: headers.get("Cache-Control") ?? "",
|
|
10
11
|
pendingDynamicCheck: true,
|
|
11
12
|
tags
|
|
12
13
|
});
|
|
14
|
+
if (options.omitCacheState === true) {
|
|
15
|
+
headers.delete(VINEXT_CACHE_HEADER);
|
|
16
|
+
headers.delete(NEXTJS_CACHE_HEADER);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
13
19
|
setCacheStateHeaders(headers, "MISS");
|
|
14
20
|
}
|
|
15
21
|
function resolveAppPageCacheWritePolicy(options) {
|
|
@@ -30,7 +36,7 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
|
|
|
30
36
|
const htmlKey = options.isrHtmlKey(options.cleanPathname);
|
|
31
37
|
const rscKey = options.isrRscKey(options.cleanPathname, null, void 0, options.interceptionContext);
|
|
32
38
|
const clientHeaders = new Headers(response.headers);
|
|
33
|
-
if (options.preserveClientResponseHeaders !== true) applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags());
|
|
39
|
+
if (options.preserveClientResponseHeaders !== true) applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
|
|
34
40
|
const cachePromise = (async () => {
|
|
35
41
|
try {
|
|
36
42
|
const cachedHtml = await readStreamAsText(streamForCache);
|
|
@@ -34,7 +34,10 @@ type AppPageBackgroundRegenerationErrorContext = {
|
|
|
34
34
|
type AppPageBackgroundRegenerator = (key: string, renderFn: () => Promise<void>, errorContext?: AppPageBackgroundRegenerationErrorContext) => void;
|
|
35
35
|
type AppPageDispatchIntercept<TPage = unknown> = {
|
|
36
36
|
interceptLayouts?: readonly unknown[] | null;
|
|
37
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
38
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
37
39
|
matchedParams: AppPageParams;
|
|
40
|
+
sourceMatchedParams?: AppPageParams;
|
|
38
41
|
page: TPage;
|
|
39
42
|
slotId?: string | null;
|
|
40
43
|
slotKey: string;
|
|
@@ -44,6 +47,8 @@ type AppPageDispatchIntercept<TPage = unknown> = {
|
|
|
44
47
|
type AppPageDispatchInterceptOptions<TPage = unknown> = {
|
|
45
48
|
interceptionContext: string | null;
|
|
46
49
|
interceptLayouts?: readonly unknown[] | null;
|
|
50
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
51
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
47
52
|
interceptPage: TPage;
|
|
48
53
|
interceptParams: AppPageParams;
|
|
49
54
|
interceptSlotId?: string | null;
|
|
@@ -104,7 +109,10 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
104
109
|
* `next.config`. Undefined falls back to the React default downstream.
|
|
105
110
|
*/
|
|
106
111
|
reactMaxHeadersLength?: number;
|
|
107
|
-
buildPageElement: (route: TRoute, params: AppPageParams, opts: AppPageDispatchInterceptOptions | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker
|
|
112
|
+
buildPageElement: (route: TRoute, params: AppPageParams, opts: AppPageDispatchInterceptOptions | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker, options?: {
|
|
113
|
+
observeMetadataSearchParamsAccess?: boolean;
|
|
114
|
+
observePageSearchParamsAccess?: boolean;
|
|
115
|
+
}) => Promise<AppPageElement>;
|
|
108
116
|
clientReuseManifest?: ClientReuseManifestParseResult;
|
|
109
117
|
cleanPathname: string;
|
|
110
118
|
displayPathname?: string;
|
|
@@ -170,9 +178,9 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
170
178
|
staticParamsValidationParams?: AppPageParams;
|
|
171
179
|
rootParams?: RootParams;
|
|
172
180
|
probeLayoutAt: (layoutIndex: number, layoutParamAccess?: AppLayoutParamAccessTracker) => unknown;
|
|
173
|
-
probePage: () => unknown;
|
|
181
|
+
probePage: (searchParams?: URLSearchParams) => unknown;
|
|
174
182
|
expireSeconds?: number;
|
|
175
|
-
renderErrorBoundaryPage: (error: unknown) => Promise<Response | null>;
|
|
183
|
+
renderErrorBoundaryPage: (error: unknown, errorOrigin?: "rsc" | "ssr") => Promise<Response | null>;
|
|
176
184
|
renderHttpAccessFallbackPage: (statusCode: number, opts: {
|
|
177
185
|
boundaryComponent?: unknown;
|
|
178
186
|
boundaryModule?: AppPageModule | null;
|
|
@@ -3,7 +3,7 @@ import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
|
3
3
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
4
4
|
import { shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
|
|
5
5
|
import "./app-elements.js";
|
|
6
|
-
import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, markDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
|
|
6
|
+
import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersContext, isDraftModeRequest, markDynamicUsage, peekDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
|
|
7
7
|
import { _consumeRequestScopedCacheLife, _peekRequestScopedCacheLife } from "../shims/cache-request-state.js";
|
|
8
8
|
import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
|
|
9
9
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
@@ -107,6 +107,7 @@ async function runAppPageRevalidationContext(options, renderFn) {
|
|
|
107
107
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
108
108
|
return runWithRequestContext(createRequestContext({
|
|
109
109
|
headersContext: createStaticGenerationHeadersContext({
|
|
110
|
+
draftModeEnabled: false,
|
|
110
111
|
draftModeSecret: options.draftModeSecret,
|
|
111
112
|
dynamicConfig: options.dynamicConfig,
|
|
112
113
|
routeKind: "page",
|
|
@@ -131,6 +132,8 @@ function toInterceptOptions(interceptionContext, intercept) {
|
|
|
131
132
|
return {
|
|
132
133
|
interceptionContext,
|
|
133
134
|
interceptLayouts: intercept.interceptLayouts,
|
|
135
|
+
interceptLayoutSegments: intercept.interceptLayoutSegments,
|
|
136
|
+
interceptBranchSegments: intercept.interceptBranchSegments,
|
|
134
137
|
interceptPage: intercept.page,
|
|
135
138
|
interceptParams: intercept.matchedParams,
|
|
136
139
|
interceptSlotId: intercept.slotId ?? null,
|
|
@@ -152,7 +155,11 @@ async function dispatchAppPageInner(options) {
|
|
|
152
155
|
const isDynamicError = dynamicConfig === "error";
|
|
153
156
|
const isForceDynamic = dynamicConfig === "force-dynamic";
|
|
154
157
|
const isDraftMode = isDraftModeRequest(options.request, options.draftModeSecret);
|
|
158
|
+
const requestHeadersContext = getHeadersContext();
|
|
159
|
+
const hasRequestSearchParams = !isForceStatic && hasSearchParams(options.searchParams);
|
|
160
|
+
const pageSearchParams = isForceStatic ? new URLSearchParams() : options.searchParams;
|
|
155
161
|
const layoutParamAccess = createAppLayoutParamAccessTracker();
|
|
162
|
+
const hasActiveLoadingBoundary = shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") ? false : Boolean(route.loading?.default);
|
|
156
163
|
setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
|
|
157
164
|
setCurrentFetchCacheMode(options.fetchCache ?? null);
|
|
158
165
|
setCurrentForceDynamicFetchDefault(isForceDynamic);
|
|
@@ -172,9 +179,10 @@ async function dispatchAppPageInner(options) {
|
|
|
172
179
|
options.clearRequestContext();
|
|
173
180
|
return methodResponse;
|
|
174
181
|
}
|
|
175
|
-
if (
|
|
182
|
+
if (isForceStatic || isDynamicError) {
|
|
176
183
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
177
184
|
setHeadersContext(createStaticGenerationHeadersContext({
|
|
185
|
+
draftModeEnabled: isDraftMode,
|
|
178
186
|
draftModeSecret: options.draftModeSecret,
|
|
179
187
|
dynamicConfig,
|
|
180
188
|
routeKind: "page",
|
|
@@ -200,7 +208,7 @@ async function dispatchAppPageInner(options) {
|
|
|
200
208
|
const cachedPageResponse = await readAppPageCacheResponse({
|
|
201
209
|
cleanPathname: options.cleanPathname,
|
|
202
210
|
clearRequestContext: options.clearRequestContext,
|
|
203
|
-
hasRequestSearchParams
|
|
211
|
+
hasRequestSearchParams,
|
|
204
212
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
205
213
|
isRscRequest: options.isRscRequest,
|
|
206
214
|
isrDebug: options.isrDebug,
|
|
@@ -234,19 +242,23 @@ async function dispatchAppPageInner(options) {
|
|
|
234
242
|
});
|
|
235
243
|
revalidationTarget.navigationParams = resolveAppPageNavigationParams(revalidationTarget.route, revalidationTarget.navigationParams, options.cleanPathname, revalidationTarget.interceptOpts);
|
|
236
244
|
await options.ensureRouteLoaded?.(revalidationTarget.route);
|
|
245
|
+
const revalidationDynamicConfig = options.resolveRouteDynamicConfig?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? dynamicConfig : void 0);
|
|
237
246
|
return runAppPageRevalidationContext({
|
|
238
247
|
cleanPathname: options.cleanPathname,
|
|
239
248
|
displayPathname: options.displayPathname,
|
|
240
249
|
currentFetchCacheMode: options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
|
|
241
250
|
draftModeSecret: options.draftModeSecret,
|
|
242
|
-
dynamicConfig:
|
|
251
|
+
dynamicConfig: revalidationDynamicConfig,
|
|
243
252
|
params: revalidationTarget.navigationParams,
|
|
244
253
|
routePattern: revalidationTarget.route.pattern,
|
|
245
254
|
routeSegments: revalidationTarget.route.routeSegments,
|
|
246
255
|
setNavigationContext: options.setNavigationContext
|
|
247
256
|
}, async () => {
|
|
248
257
|
const { renderAppPageCacheArtifacts } = await import("./app-page-cache-render.js");
|
|
249
|
-
const revalidatedElement = await options.buildPageElement(revalidationTarget.route, revalidationTarget.params, revalidationTarget.interceptOpts, new URLSearchParams()
|
|
258
|
+
const revalidatedElement = await options.buildPageElement(revalidationTarget.route, revalidationTarget.params, revalidationTarget.interceptOpts, new URLSearchParams(), void 0, {
|
|
259
|
+
observeMetadataSearchParamsAccess: revalidationDynamicConfig !== "force-static",
|
|
260
|
+
observePageSearchParamsAccess: revalidationDynamicConfig !== "force-static"
|
|
261
|
+
});
|
|
250
262
|
const revalidatedOnError = options.createRscOnErrorHandler(options.cleanPathname, revalidationTarget.route.pattern);
|
|
251
263
|
const rendered = await renderAppPageCacheArtifacts({
|
|
252
264
|
basePath: options.basePath,
|
|
@@ -301,12 +313,27 @@ async function dispatchAppPageInner(options) {
|
|
|
301
313
|
}
|
|
302
314
|
const fallbackShellResponse = options.pprRuntime ? await options.pprRuntime.tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) : null;
|
|
303
315
|
if (fallbackShellResponse) return fallbackShellResponse;
|
|
316
|
+
let interceptDynamicConfig;
|
|
317
|
+
let interceptDynamicConfigResolved = false;
|
|
304
318
|
const interceptResult = await resolveAppPageIntercept({
|
|
305
319
|
async buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess) {
|
|
306
|
-
|
|
320
|
+
const sourceDynamicConfig = interceptDynamicConfigResolved ? interceptDynamicConfig : options.resolveRouteDynamicConfig?.(interceptRoute);
|
|
321
|
+
if (sourceDynamicConfig === "force-static" || sourceDynamicConfig === "error") {
|
|
322
|
+
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
323
|
+
setHeadersContext(createStaticGenerationHeadersContext({
|
|
324
|
+
draftModeEnabled: isDraftMode,
|
|
325
|
+
draftModeSecret: options.draftModeSecret,
|
|
326
|
+
dynamicConfig: sourceDynamicConfig,
|
|
327
|
+
routeKind: "page",
|
|
328
|
+
routePattern: interceptRoute.pattern
|
|
329
|
+
}));
|
|
330
|
+
} else setHeadersContext(requestHeadersContext);
|
|
307
331
|
setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(interceptRoute) ?? null);
|
|
308
|
-
setCurrentForceDynamicFetchDefault(
|
|
309
|
-
return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess
|
|
332
|
+
setCurrentForceDynamicFetchDefault(sourceDynamicConfig === "force-dynamic");
|
|
333
|
+
return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess, {
|
|
334
|
+
observeMetadataSearchParamsAccess: sourceDynamicConfig !== "force-static",
|
|
335
|
+
observePageSearchParamsAccess: sourceDynamicConfig !== "force-static"
|
|
336
|
+
});
|
|
310
337
|
},
|
|
311
338
|
cleanPathname: options.cleanPathname,
|
|
312
339
|
currentRoute: route,
|
|
@@ -338,6 +365,12 @@ async function dispatchAppPageInner(options) {
|
|
|
338
365
|
headers: interceptHeaders
|
|
339
366
|
});
|
|
340
367
|
},
|
|
368
|
+
async resolveSearchParams(sourceRoute, searchParams) {
|
|
369
|
+
await options.ensureRouteLoaded?.(sourceRoute);
|
|
370
|
+
interceptDynamicConfig = options.resolveRouteDynamicConfig?.(sourceRoute);
|
|
371
|
+
interceptDynamicConfigResolved = true;
|
|
372
|
+
return interceptDynamicConfig === "force-static" ? new URLSearchParams() : searchParams;
|
|
373
|
+
},
|
|
341
374
|
searchParams: options.searchParams,
|
|
342
375
|
setNavigationContext: options.setNavigationContext,
|
|
343
376
|
toInterceptOpts(intercept) {
|
|
@@ -348,12 +381,15 @@ async function dispatchAppPageInner(options) {
|
|
|
348
381
|
const buildCurrentPageElement = () => buildAppPageElement({
|
|
349
382
|
buildPageElement() {
|
|
350
383
|
if (options.actionFailed) throw options.actionError;
|
|
351
|
-
return options.buildPageElement(route, options.params, interceptResult.interceptOpts,
|
|
384
|
+
return options.buildPageElement(route, options.params, interceptResult.interceptOpts, pageSearchParams, layoutParamAccess, {
|
|
385
|
+
observeMetadataSearchParamsAccess: !isForceStatic,
|
|
386
|
+
observePageSearchParamsAccess: !isForceStatic
|
|
387
|
+
});
|
|
352
388
|
},
|
|
353
389
|
async probePageSpecialError() {
|
|
354
390
|
if (!shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") && route.loading?.default) return null;
|
|
355
391
|
return resolveAppPageSpecialError(await probeAppPageThrownError({
|
|
356
|
-
probePage: options.probePage,
|
|
392
|
+
probePage: () => options.probePage(pageSearchParams),
|
|
357
393
|
runWithSuppressedHookWarning(probe) {
|
|
358
394
|
return options.runWithSuppressedHookWarning(probe);
|
|
359
395
|
}
|
|
@@ -384,7 +420,7 @@ async function dispatchAppPageInner(options) {
|
|
|
384
420
|
const navigationParams = resolveAppPageNavigationParams(route, options.params, options.cleanPathname, interceptResult.interceptOpts);
|
|
385
421
|
options.setNavigationContext({
|
|
386
422
|
pathname: options.displayPathname ?? options.cleanPathname,
|
|
387
|
-
searchParams:
|
|
423
|
+
searchParams: pageSearchParams,
|
|
388
424
|
params: navigationParams
|
|
389
425
|
});
|
|
390
426
|
const layoutClassifications = getEffectiveLayoutClassifications(route, options.debugClassification);
|
|
@@ -398,6 +434,7 @@ async function dispatchAppPageInner(options) {
|
|
|
398
434
|
cleanPathname: options.cleanPathname,
|
|
399
435
|
clearRequestContext: options.clearRequestContext,
|
|
400
436
|
consumeDynamicUsage,
|
|
437
|
+
peekDynamicUsage,
|
|
401
438
|
consumeInvalidDynamicUsageError,
|
|
402
439
|
consumeRenderObservationState: consumeAppPageRenderObservationState,
|
|
403
440
|
createRscOnErrorHandler(pathname, routePath) {
|
|
@@ -420,7 +457,8 @@ async function dispatchAppPageInner(options) {
|
|
|
420
457
|
return _peekRequestScopedCacheLife();
|
|
421
458
|
},
|
|
422
459
|
handlerStart: options.handlerStart,
|
|
423
|
-
hasLoadingBoundary:
|
|
460
|
+
hasLoadingBoundary: hasActiveLoadingBoundary,
|
|
461
|
+
omitPendingDynamicCacheState: !options.isRscRequest && hasRequestSearchParams,
|
|
424
462
|
formState: options.formState ?? null,
|
|
425
463
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
426
464
|
isDynamicError,
|
|
@@ -459,8 +497,9 @@ async function dispatchAppPageInner(options) {
|
|
|
459
497
|
return options.probeLayoutAt(layoutIndex, layoutParamAccess);
|
|
460
498
|
},
|
|
461
499
|
probePage() {
|
|
462
|
-
return options.probePage();
|
|
500
|
+
return options.probePage(pageSearchParams);
|
|
463
501
|
},
|
|
502
|
+
probePageBeforeRender: options.isRscRequest,
|
|
464
503
|
classification: {
|
|
465
504
|
getLayoutId(index) {
|
|
466
505
|
const treePosition = route.layoutTreePositions?.[index] ?? 0;
|
|
@@ -489,8 +528,8 @@ async function dispatchAppPageInner(options) {
|
|
|
489
528
|
revalidateSeconds: currentRevalidateSeconds,
|
|
490
529
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
491
530
|
renderMode: options.renderMode ?? "navigation",
|
|
492
|
-
renderErrorBoundaryResponse(renderError) {
|
|
493
|
-
return options.renderErrorBoundaryPage(renderError);
|
|
531
|
+
renderErrorBoundaryResponse(renderError, errorOrigin) {
|
|
532
|
+
return options.renderErrorBoundaryPage(renderError, errorOrigin);
|
|
494
533
|
},
|
|
495
534
|
renderLayoutSpecialError(specialError, layoutIndex) {
|
|
496
535
|
return renderLayoutSpecialError(options, specialError, layoutIndex);
|