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.
Files changed (114) hide show
  1. package/dist/build/client-build-config.d.ts +4 -6
  2. package/dist/build/client-build-config.js +27 -7
  3. package/dist/build/prerender.js +1 -2
  4. package/dist/check.d.ts +18 -0
  5. package/dist/check.js +37 -17
  6. package/dist/cli.js +2 -2
  7. package/dist/config/next-config.d.ts +2 -1
  8. package/dist/config/next-config.js +3 -0
  9. package/dist/config/server-external-packages.d.ts +4 -0
  10. package/dist/config/server-external-packages.js +91 -0
  11. package/dist/deploy.d.ts +7 -0
  12. package/dist/deploy.js +25 -18
  13. package/dist/entries/app-rsc-entry.d.ts +2 -1
  14. package/dist/entries/app-rsc-entry.js +89 -20
  15. package/dist/entries/app-rsc-manifest.js +8 -0
  16. package/dist/entries/pages-client-entry.js +1 -0
  17. package/dist/entries/pages-server-entry.js +1 -0
  18. package/dist/index.js +87 -34
  19. package/dist/init.js +2 -1
  20. package/dist/plugins/middleware-server-only.d.ts +8 -6
  21. package/dist/plugins/middleware-server-only.js +8 -7
  22. package/dist/plugins/og-assets.js +6 -6
  23. package/dist/plugins/optimize-imports.js +1 -1
  24. package/dist/plugins/remove-console.js +1 -1
  25. package/dist/plugins/strip-server-exports.js +2 -1
  26. package/dist/routing/app-route-graph.d.ts +6 -2
  27. package/dist/routing/app-route-graph.js +61 -13
  28. package/dist/routing/app-router.d.ts +5 -0
  29. package/dist/routing/app-router.js +5 -0
  30. package/dist/routing/file-matcher.d.ts +5 -0
  31. package/dist/routing/file-matcher.js +7 -1
  32. package/dist/server/app-action-request.d.ts +4 -0
  33. package/dist/server/app-action-request.js +9 -0
  34. package/dist/server/app-bfcache-identity.d.ts +12 -2
  35. package/dist/server/app-bfcache-identity.js +52 -23
  36. package/dist/server/app-browser-entry.js +42 -147
  37. package/dist/server/app-browser-history-controller.d.ts +2 -1
  38. package/dist/server/app-browser-history-controller.js +6 -2
  39. package/dist/server/app-browser-server-action-client.d.ts +32 -0
  40. package/dist/server/app-browser-server-action-client.js +128 -0
  41. package/dist/server/app-fallback-renderer.d.ts +3 -1
  42. package/dist/server/app-fallback-renderer.js +6 -2
  43. package/dist/server/app-history-state.d.ts +1 -2
  44. package/dist/server/app-history-state.js +1 -1
  45. package/dist/server/app-page-boundary-render.d.ts +3 -0
  46. package/dist/server/app-page-boundary-render.js +14 -3
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +8 -2
  49. package/dist/server/app-page-dispatch.d.ts +33 -4
  50. package/dist/server/app-page-dispatch.js +62 -90
  51. package/dist/server/app-page-element-builder.d.ts +7 -1
  52. package/dist/server/app-page-element-builder.js +56 -19
  53. package/dist/server/app-page-head.d.ts +16 -1
  54. package/dist/server/app-page-head.js +44 -22
  55. package/dist/server/app-page-method.js +1 -1
  56. package/dist/server/app-page-params.d.ts +2 -1
  57. package/dist/server/app-page-params.js +8 -1
  58. package/dist/server/app-page-ppr-runtime.d.ts +7 -0
  59. package/dist/server/app-page-ppr-runtime.js +70 -0
  60. package/dist/server/app-page-probe.d.ts +1 -0
  61. package/dist/server/app-page-probe.js +1 -1
  62. package/dist/server/app-page-render.d.ts +4 -1
  63. package/dist/server/app-page-render.js +8 -3
  64. package/dist/server/app-page-request.d.ts +8 -1
  65. package/dist/server/app-page-request.js +23 -11
  66. package/dist/server/app-page-route-wiring.d.ts +6 -1
  67. package/dist/server/app-page-route-wiring.js +30 -8
  68. package/dist/server/app-page-search-params-observation.d.ts +4 -2
  69. package/dist/server/app-page-search-params-observation.js +11 -7
  70. package/dist/server/app-page-stream.js +2 -1
  71. package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
  72. package/dist/server/app-route-handler-cache.js +1 -1
  73. package/dist/server/app-route-handler-dispatch.js +3 -2
  74. package/dist/server/app-route-handler-execution.js +5 -3
  75. package/dist/server/app-route-handler-policy.d.ts +1 -1
  76. package/dist/server/app-route-handler-policy.js +1 -6
  77. package/dist/server/app-route-module-loader.d.ts +2 -0
  78. package/dist/server/app-route-module-loader.js +1 -0
  79. package/dist/server/app-router-entry.js +7 -6
  80. package/dist/server/app-rsc-errors.d.ts +12 -1
  81. package/dist/server/app-rsc-errors.js +29 -3
  82. package/dist/server/app-rsc-handler.d.ts +15 -13
  83. package/dist/server/app-rsc-handler.js +28 -33
  84. package/dist/server/app-rsc-response-finalizer.js +5 -1
  85. package/dist/server/app-rsc-route-matching.d.ts +7 -0
  86. package/dist/server/app-rsc-route-matching.js +36 -3
  87. package/dist/server/app-segment-config.d.ts +1 -0
  88. package/dist/server/app-segment-config.js +32 -2
  89. package/dist/server/app-server-action-execution.d.ts +4 -0
  90. package/dist/server/app-server-action-execution.js +42 -11
  91. package/dist/server/app-ssr-entry.js +11 -6
  92. package/dist/server/app-static-generation.d.ts +1 -0
  93. package/dist/server/app-static-generation.js +1 -0
  94. package/dist/server/headers.d.ts +3 -1
  95. package/dist/server/headers.js +3 -1
  96. package/dist/server/metadata-route-response.d.ts +1 -1
  97. package/dist/server/prod-server.js +15 -6
  98. package/dist/server/worker-utils.d.ts +2 -1
  99. package/dist/server/worker-utils.js +7 -1
  100. package/dist/shims/dynamic.js +1 -1
  101. package/dist/shims/error-boundary.d.ts +19 -1
  102. package/dist/shims/error-boundary.js +11 -1
  103. package/dist/shims/headers.d.ts +3 -1
  104. package/dist/shims/headers.js +16 -5
  105. package/dist/shims/link.js +16 -12
  106. package/dist/shims/metadata.d.ts +3 -2
  107. package/dist/shims/metadata.js +8 -4
  108. package/dist/shims/router.js +13 -2
  109. package/dist/typegen.js +6 -5
  110. package/dist/utils/path.d.ts +2 -1
  111. package/dist/utils/path.js +1 -1
  112. package/dist/utils/project.d.ts +4 -0
  113. package/dist/utils/project.js +5 -1
  114. 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) return {
438
- ...slot,
439
- pagePath: subPage,
440
- routeSegments: rawSegments
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,4 @@
1
+ //#region src/server/app-action-request.d.ts
2
+ declare function isPossibleAppRouteActionRequest(request: Pick<Request, "headers" | "method">): boolean;
3
+ //#endregion
4
+ export { isPossibleAppRouteActionRequest };
@@ -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
- const slotBindingsBySlotId = /* @__PURE__ */ new Map();
35
- for (const binding of metadata.slotBindings) slotBindingsBySlotId.set(binding.slotId, binding);
36
- return {
37
- metadata,
38
- slotBindingsBySlotId
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 collectBfcacheSegmentIds(elements, parsed) {
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 Array.from(ids).filter(isBfcacheSegmentId);
72
+ return ids;
70
73
  }
71
74
  function createInitialBfcacheIdMap(elements) {
72
- const ids = {};
73
- for (const id of collectBfcacheSegmentIds(elements)) ids[id] = "0";
74
- return ids;
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 collectBfcacheSegmentIds(options.elements, metadata)) {
85
- const stateKey = createBfcacheSegmentIdentity(id, {
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 collectBfcacheSegmentIds(options.elements, nextMetadata)) {
103
- const currentValue = createBfcacheSegmentIdentity(id, {
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 collectBfcacheSegmentIds(options.elements)) {
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 };