vinext 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/client-build-config.d.ts +4 -6
- package/dist/build/client-build-config.js +27 -7
- package/dist/build/prerender.js +1 -2
- package/dist/check.d.ts +18 -0
- package/dist/check.js +37 -17
- package/dist/cli.js +2 -2
- package/dist/config/next-config.d.ts +2 -1
- package/dist/config/next-config.js +3 -0
- package/dist/config/server-external-packages.d.ts +4 -0
- package/dist/config/server-external-packages.js +91 -0
- package/dist/deploy.d.ts +7 -0
- package/dist/deploy.js +25 -18
- package/dist/entries/app-rsc-entry.d.ts +2 -1
- package/dist/entries/app-rsc-entry.js +89 -20
- package/dist/entries/app-rsc-manifest.js +8 -0
- package/dist/entries/pages-client-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +1 -0
- package/dist/index.js +87 -34
- package/dist/init.js +2 -1
- package/dist/plugins/middleware-server-only.d.ts +8 -6
- package/dist/plugins/middleware-server-only.js +8 -7
- package/dist/plugins/og-assets.js +6 -6
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/remove-console.js +1 -1
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/routing/app-route-graph.d.ts +6 -2
- package/dist/routing/app-route-graph.js +61 -13
- package/dist/routing/app-router.d.ts +5 -0
- package/dist/routing/app-router.js +5 -0
- package/dist/routing/file-matcher.d.ts +5 -0
- package/dist/routing/file-matcher.js +7 -1
- package/dist/server/app-action-request.d.ts +4 -0
- package/dist/server/app-action-request.js +9 -0
- package/dist/server/app-bfcache-identity.d.ts +12 -2
- package/dist/server/app-bfcache-identity.js +52 -23
- package/dist/server/app-browser-entry.js +42 -147
- package/dist/server/app-browser-history-controller.d.ts +2 -1
- package/dist/server/app-browser-history-controller.js +6 -2
- package/dist/server/app-browser-server-action-client.d.ts +32 -0
- package/dist/server/app-browser-server-action-client.js +128 -0
- package/dist/server/app-fallback-renderer.d.ts +3 -1
- package/dist/server/app-fallback-renderer.js +6 -2
- package/dist/server/app-history-state.d.ts +1 -2
- package/dist/server/app-history-state.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +3 -0
- package/dist/server/app-page-boundary-render.js +14 -3
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +8 -2
- package/dist/server/app-page-dispatch.d.ts +33 -4
- package/dist/server/app-page-dispatch.js +62 -90
- package/dist/server/app-page-element-builder.d.ts +7 -1
- package/dist/server/app-page-element-builder.js +56 -19
- package/dist/server/app-page-head.d.ts +16 -1
- package/dist/server/app-page-head.js +44 -22
- package/dist/server/app-page-method.js +1 -1
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +8 -1
- package/dist/server/app-page-ppr-runtime.d.ts +7 -0
- package/dist/server/app-page-ppr-runtime.js +70 -0
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +1 -1
- package/dist/server/app-page-render.d.ts +4 -1
- package/dist/server/app-page-render.js +8 -3
- package/dist/server/app-page-request.d.ts +8 -1
- package/dist/server/app-page-request.js +23 -11
- package/dist/server/app-page-route-wiring.d.ts +6 -1
- package/dist/server/app-page-route-wiring.js +30 -8
- package/dist/server/app-page-search-params-observation.d.ts +4 -2
- package/dist/server/app-page-search-params-observation.js +11 -7
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
- package/dist/server/app-route-handler-cache.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +3 -2
- package/dist/server/app-route-handler-execution.js +5 -3
- package/dist/server/app-route-handler-policy.d.ts +1 -1
- package/dist/server/app-route-handler-policy.js +1 -6
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.js +7 -6
- package/dist/server/app-rsc-errors.d.ts +12 -1
- package/dist/server/app-rsc-errors.js +29 -3
- package/dist/server/app-rsc-handler.d.ts +15 -13
- package/dist/server/app-rsc-handler.js +28 -33
- package/dist/server/app-rsc-response-finalizer.js +5 -1
- package/dist/server/app-rsc-route-matching.d.ts +7 -0
- package/dist/server/app-rsc-route-matching.js +36 -3
- package/dist/server/app-segment-config.d.ts +1 -0
- package/dist/server/app-segment-config.js +32 -2
- package/dist/server/app-server-action-execution.d.ts +4 -0
- package/dist/server/app-server-action-execution.js +42 -11
- package/dist/server/app-ssr-entry.js +11 -6
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +1 -0
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/metadata-route-response.d.ts +1 -1
- package/dist/server/prod-server.js +15 -6
- package/dist/server/worker-utils.d.ts +2 -1
- package/dist/server/worker-utils.js +7 -1
- package/dist/shims/dynamic.js +1 -1
- package/dist/shims/error-boundary.d.ts +19 -1
- package/dist/shims/error-boundary.js +11 -1
- package/dist/shims/headers.d.ts +3 -1
- package/dist/shims/headers.js +16 -5
- package/dist/shims/link.js +16 -12
- package/dist/shims/metadata.d.ts +3 -2
- package/dist/shims/metadata.js +8 -4
- package/dist/shims/router.js +13 -2
- package/dist/typegen.js +6 -5
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +1 -1
- package/dist/utils/project.d.ts +4 -0
- package/dist/utils/project.js +5 -1
- package/package.json +7 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { normalizePathSeparators } from "../utils/path.js";
|
|
2
1
|
import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
|
|
2
|
+
import { normalizePathSeparators } from "../utils/path.js";
|
|
3
3
|
import { findFileWithExts, scanWithExtensions } from "./file-matcher.js";
|
|
4
4
|
import { validateRoutePatterns } from "./route-validation.js";
|
|
5
5
|
import { compareStrings } from "../utils/compare.js";
|
|
@@ -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,4 +1,5 @@
|
|
|
1
1
|
import { escapeRegExp } from "../utils/regex.js";
|
|
2
|
+
import { normalizePathSeparators } from "../utils/path.js";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { glob } from "node:fs/promises";
|
|
@@ -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 };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "./headers.js";
|
|
2
|
+
//#region src/server/app-action-request.ts
|
|
3
|
+
function isPossibleAppRouteActionRequest(request) {
|
|
4
|
+
if (request.method.toUpperCase() !== "POST") return false;
|
|
5
|
+
const contentType = request.headers.get("content-type");
|
|
6
|
+
return request.headers.has("x-rsc-action") || request.headers.has("next-action") || contentType === "application/x-www-form-urlencoded" || contentType?.startsWith("multipart/form-data") === true;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { isPossibleAppRouteActionRequest };
|
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
import { AppElements } from "./app-elements-wire.js";
|
|
1
|
+
import { AppElements, AppElementsWire } from "./app-elements-wire.js";
|
|
2
2
|
import { BfcacheIdMap } from "./app-history-state.js";
|
|
3
3
|
|
|
4
4
|
//#region src/server/app-bfcache-identity.d.ts
|
|
5
5
|
type BfcacheStateKeyMap = Readonly<Record<string, string>>;
|
|
6
|
+
type InitialBfcacheMaps = Readonly<{
|
|
7
|
+
bfcacheIds: BfcacheIdMap;
|
|
8
|
+
stateKeys: BfcacheStateKeyMap;
|
|
9
|
+
}>;
|
|
10
|
+
type AppElementsMetadata = ReturnType<typeof AppElementsWire.readMetadata>;
|
|
6
11
|
declare function createInitialBfcacheIdMap(elements: AppElements): BfcacheIdMap;
|
|
7
12
|
declare function createBfcacheSegmentStateKeyMap(options: {
|
|
8
13
|
elements: AppElements;
|
|
9
14
|
pathname: string;
|
|
10
15
|
}): BfcacheStateKeyMap;
|
|
16
|
+
declare function createInitialBfcacheMaps(options: {
|
|
17
|
+
elements: AppElements;
|
|
18
|
+
metadata: AppElementsMetadata;
|
|
19
|
+
pathname: string;
|
|
20
|
+
}): InitialBfcacheMaps;
|
|
11
21
|
declare function createNextBfcacheIdMap(options: {
|
|
12
22
|
current: BfcacheIdMap;
|
|
13
23
|
currentElements: AppElements;
|
|
@@ -23,4 +33,4 @@ declare function preserveBfcacheIdsForMergedElements(options: {
|
|
|
23
33
|
previous: BfcacheIdMap;
|
|
24
34
|
}): BfcacheIdMap;
|
|
25
35
|
//#endregion
|
|
26
|
-
export { BfcacheStateKeyMap, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
36
|
+
export { BfcacheStateKeyMap, InitialBfcacheMaps, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createInitialBfcacheMaps, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
@@ -3,7 +3,6 @@ import { normalizePath } from "./normalize-path.js";
|
|
|
3
3
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
4
4
|
import "./app-elements.js";
|
|
5
5
|
import "./app-bfcache-id.js";
|
|
6
|
-
import { isBfcacheSegmentId } from "./app-history-state.js";
|
|
7
6
|
//#region src/server/app-bfcache-identity.ts
|
|
8
7
|
let nextBfcacheId = 0;
|
|
9
8
|
function rememberBfcacheId(value) {
|
|
@@ -24,6 +23,14 @@ function getTreePathIdentityPrefix(pathname, treePath) {
|
|
|
24
23
|
if (consumedPathnameSegments === 0) return "/";
|
|
25
24
|
return `/${pathnameSegments.slice(0, consumedPathnameSegments).join("/")}`;
|
|
26
25
|
}
|
|
26
|
+
function indexAppElementsMetadata(metadata) {
|
|
27
|
+
const slotBindingsBySlotId = /* @__PURE__ */ new Map();
|
|
28
|
+
for (const binding of metadata.slotBindings) slotBindingsBySlotId.set(binding.slotId, binding);
|
|
29
|
+
return {
|
|
30
|
+
metadata,
|
|
31
|
+
slotBindingsBySlotId
|
|
32
|
+
};
|
|
33
|
+
}
|
|
27
34
|
function readAppElementsMetadata(elements) {
|
|
28
35
|
let metadata;
|
|
29
36
|
try {
|
|
@@ -31,12 +38,11 @@ function readAppElementsMetadata(elements) {
|
|
|
31
38
|
} catch {
|
|
32
39
|
return null;
|
|
33
40
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
41
|
+
return indexAppElementsMetadata(metadata);
|
|
42
|
+
}
|
|
43
|
+
function parseBfcacheSegmentKey(id) {
|
|
44
|
+
const parsed = AppElementsWire.parseElementKey(id);
|
|
45
|
+
return parsed !== null && parsed.kind !== "route" ? parsed : null;
|
|
40
46
|
}
|
|
41
47
|
function createActiveSlotIdentity(id, parsed) {
|
|
42
48
|
const activeSlotBinding = parsed?.slotBindingsBySlotId.get(id);
|
|
@@ -50,9 +56,7 @@ function createActiveSlotIdentity(id, parsed) {
|
|
|
50
56
|
* contained here until vinext has a route-manifest authority equivalent to
|
|
51
57
|
* Next.js CacheNode or segment-cache state.
|
|
52
58
|
*/
|
|
53
|
-
function createBfcacheSegmentIdentity(id, options) {
|
|
54
|
-
const parsed = AppElementsWire.parseElementKey(id);
|
|
55
|
-
if (!parsed) return null;
|
|
59
|
+
function createBfcacheSegmentIdentity(id, parsed, options) {
|
|
56
60
|
if (parsed.kind === "page") return `${id}@${options.pathname}`;
|
|
57
61
|
if (parsed.kind === "slot") {
|
|
58
62
|
const activeSlotIdentity = createActiveSlotIdentity(id, options.metadata);
|
|
@@ -62,16 +66,15 @@ function createBfcacheSegmentIdentity(id, options) {
|
|
|
62
66
|
if (parsed.kind === "layout" || parsed.kind === "template") return `${id}@${getTreePathIdentityPrefix(options.pathname, parsed.treePath)}`;
|
|
63
67
|
return null;
|
|
64
68
|
}
|
|
65
|
-
function
|
|
69
|
+
function collectBfcacheSegmentIdCandidates(elements, metadata = readAppElementsMetadata(elements)) {
|
|
66
70
|
const ids = new Set(Object.keys(elements));
|
|
67
|
-
const metadata = parsed === void 0 ? readAppElementsMetadata(elements) : parsed;
|
|
68
71
|
for (const layoutId of metadata?.metadata.layoutIds ?? []) ids.add(layoutId);
|
|
69
|
-
return
|
|
72
|
+
return ids;
|
|
70
73
|
}
|
|
71
74
|
function createInitialBfcacheIdMap(elements) {
|
|
72
|
-
const
|
|
73
|
-
for (const id of
|
|
74
|
-
return
|
|
75
|
+
const bfcacheIds = {};
|
|
76
|
+
for (const id of collectBfcacheSegmentIdCandidates(elements)) if (parseBfcacheSegmentKey(id) !== null) bfcacheIds[id] = "0";
|
|
77
|
+
return bfcacheIds;
|
|
75
78
|
}
|
|
76
79
|
function normalizeBfcachePathname(pathname) {
|
|
77
80
|
const normalized = normalizePath(normalizePathnameForRouteMatch(pathname));
|
|
@@ -81,8 +84,10 @@ function createBfcacheSegmentStateKeyMap(options) {
|
|
|
81
84
|
const metadata = readAppElementsMetadata(options.elements);
|
|
82
85
|
const normalizedPathname = normalizeBfcachePathname(options.pathname);
|
|
83
86
|
const stateKeys = {};
|
|
84
|
-
for (const id of
|
|
85
|
-
const
|
|
87
|
+
for (const id of collectBfcacheSegmentIdCandidates(options.elements, metadata)) {
|
|
88
|
+
const parsed = parseBfcacheSegmentKey(id);
|
|
89
|
+
if (parsed === null) continue;
|
|
90
|
+
const stateKey = createBfcacheSegmentIdentity(id, parsed, {
|
|
86
91
|
metadata,
|
|
87
92
|
pathname: normalizedPathname
|
|
88
93
|
});
|
|
@@ -90,6 +95,27 @@ function createBfcacheSegmentStateKeyMap(options) {
|
|
|
90
95
|
}
|
|
91
96
|
return stateKeys;
|
|
92
97
|
}
|
|
98
|
+
function createInitialBfcacheMaps(options) {
|
|
99
|
+
const metadata = indexAppElementsMetadata(options.metadata);
|
|
100
|
+
const ids = collectBfcacheSegmentIdCandidates(options.elements, metadata);
|
|
101
|
+
const normalizedPathname = normalizeBfcachePathname(options.pathname);
|
|
102
|
+
const bfcacheIds = {};
|
|
103
|
+
const stateKeys = {};
|
|
104
|
+
for (const id of ids) {
|
|
105
|
+
const parsed = parseBfcacheSegmentKey(id);
|
|
106
|
+
if (parsed === null) continue;
|
|
107
|
+
bfcacheIds[id] = "0";
|
|
108
|
+
const stateKey = createBfcacheSegmentIdentity(id, parsed, {
|
|
109
|
+
metadata,
|
|
110
|
+
pathname: normalizedPathname
|
|
111
|
+
});
|
|
112
|
+
if (stateKey !== null) stateKeys[id] = stateKey;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
bfcacheIds,
|
|
116
|
+
stateKeys
|
|
117
|
+
};
|
|
118
|
+
}
|
|
93
119
|
function createNextBfcacheIdMap(options) {
|
|
94
120
|
const current = options.reuseCurrent === false ? {} : options.current;
|
|
95
121
|
for (const value of Object.values(current)) rememberBfcacheId(value);
|
|
@@ -99,11 +125,13 @@ function createNextBfcacheIdMap(options) {
|
|
|
99
125
|
const currentPathname = normalizeBfcachePathname(options.currentPathname);
|
|
100
126
|
const nextPathname = normalizeBfcachePathname(options.nextPathname);
|
|
101
127
|
const ids = {};
|
|
102
|
-
for (const id of
|
|
103
|
-
const
|
|
128
|
+
for (const id of collectBfcacheSegmentIdCandidates(options.elements, nextMetadata)) {
|
|
129
|
+
const parsed = parseBfcacheSegmentKey(id);
|
|
130
|
+
if (parsed === null) continue;
|
|
131
|
+
const currentValue = createBfcacheSegmentIdentity(id, parsed, {
|
|
104
132
|
metadata: currentMetadata,
|
|
105
133
|
pathname: currentPathname
|
|
106
|
-
}) === createBfcacheSegmentIdentity(id, {
|
|
134
|
+
}) === createBfcacheSegmentIdentity(id, parsed, {
|
|
107
135
|
metadata: nextMetadata,
|
|
108
136
|
pathname: nextPathname
|
|
109
137
|
}) ? current[id] : void 0;
|
|
@@ -115,7 +143,8 @@ function createNextBfcacheIdMap(options) {
|
|
|
115
143
|
}
|
|
116
144
|
function preserveBfcacheIdsForMergedElements(options) {
|
|
117
145
|
const ids = {};
|
|
118
|
-
for (const id of
|
|
146
|
+
for (const id of collectBfcacheSegmentIdCandidates(options.elements)) {
|
|
147
|
+
if (parseBfcacheSegmentKey(id) === null) continue;
|
|
119
148
|
const value = options.next[id] ?? options.previous[id];
|
|
120
149
|
if (value === void 0) continue;
|
|
121
150
|
ids[id] = value;
|
|
@@ -124,4 +153,4 @@ function preserveBfcacheIdsForMergedElements(options) {
|
|
|
124
153
|
return ids;
|
|
125
154
|
}
|
|
126
155
|
//#endregion
|
|
127
|
-
export { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
156
|
+
export { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createInitialBfcacheMaps, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|