@fern-api/fdr-sdk 1.2.39-38c6f9a29c → 1.2.39-438fcc7e23

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 (36) hide show
  1. package/dist/js/client/FdrClient.js +28 -7
  2. package/dist/js/client/FdrClient.js.map +1 -1
  3. package/dist/js/client/FdrClient.mjs +28 -7
  4. package/dist/js/client/FdrClient.mjs.map +1 -1
  5. package/dist/js/index.js +28 -7
  6. package/dist/js/index.js.map +1 -1
  7. package/dist/js/index.mjs +28 -7
  8. package/dist/js/index.mjs.map +1 -1
  9. package/dist/js/navigation/ledger-root-builder.js +294 -84
  10. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  11. package/dist/js/navigation/ledger-root-builder.mjs +294 -84
  12. package/dist/js/navigation/ledger-root-builder.mjs.map +1 -1
  13. package/dist/js/orpc-client.js +30 -7
  14. package/dist/js/orpc-client.js.map +1 -1
  15. package/dist/js/orpc-client.mjs +30 -7
  16. package/dist/js/orpc-client.mjs.map +1 -1
  17. package/dist/tsconfig.tsbuildinfo +1 -1
  18. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts +2 -0
  19. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts.map +1 -0
  20. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  21. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  22. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts +2 -0
  23. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts.map +1 -0
  24. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  25. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  26. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts +2 -0
  27. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts.map +1 -0
  28. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts +2 -0
  29. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts.map +1 -0
  30. package/dist/types/navigation/ledger-root-builder.d.ts +12 -0
  31. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  32. package/dist/types/orpc-client/docs-ledger/contract.d.ts +2190 -170
  33. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  34. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +3456 -104
  35. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  36. package/package.json +1 -1
@@ -94,6 +94,9 @@ var AuthSchemeIdSchema = z2.string();
94
94
  var SubpackageIdSchema = z2.string();
95
95
  var WebSocketMessageIdSchema = z2.string();
96
96
  var FileIdSchema = z2.string();
97
+ function FileId(value) {
98
+ return value;
99
+ }
97
100
  var MultipleAuthTypeSchema = z2.object({
98
101
  schemes: z2.array(AuthSchemeIdSchema)
99
102
  });
@@ -865,6 +868,13 @@ function metaStrArr(metadata, key) {
865
868
  }
866
869
  return void 0;
867
870
  }
871
+ function metaFeatureFlags(metadata) {
872
+ if (metadata != null && typeof metadata === "object" && "featureFlags" in metadata) {
873
+ const v = metadata.featureFlags;
874
+ return Array.isArray(v) && v.length > 0 ? v : void 0;
875
+ }
876
+ return void 0;
877
+ }
868
878
  function toViewers(viewers) {
869
879
  if (viewers == null || viewers.length === 0) {
870
880
  return void 0;
@@ -900,17 +910,17 @@ function scopeKey(seg) {
900
910
  return [seg.product?.id ?? "", seg.version?.id ?? "", seg.variant?.id ?? "", seg.tab?.id ?? ""].join("|");
901
911
  }
902
912
  function withMetadataDefaults(base) {
903
- const { viewers, ...rest } = base;
913
+ const { viewers, featureFlags, ...rest } = base;
904
914
  return {
905
915
  ...rest,
906
916
  canonicalSlug: void 0,
907
- authed: void 0,
917
+ authed: base.authed === true ? true : void 0,
908
918
  collapsed: void 0,
909
919
  // Normalise empty arrays to undefined so unrestricted nodes don't add
910
920
  // filter-level noise; a non-empty array engages the RBAC view gate.
911
921
  viewers: viewers != null && viewers.length > 0 ? viewers : void 0,
912
- orphaned: void 0,
913
- featureFlags: void 0
922
+ orphaned: base.orphaned === true ? true : void 0,
923
+ featureFlags: featureFlags != null && featureFlags.length > 0 ? featureFlags : void 0
914
924
  };
915
925
  }
916
926
  function artifactToNode(ctx, route) {
@@ -933,7 +943,10 @@ function artifactToNode(ctx, route) {
933
943
  slug,
934
944
  icon,
935
945
  hidden: route.hidden,
936
- viewers
946
+ authed: metaBool(md, "authed"),
947
+ viewers,
948
+ orphaned: metaBool(md, "orphaned"),
949
+ featureFlags: metaFeatureFlags(md)
937
950
  }),
938
951
  pageId: PageId(pageId),
939
952
  noindex: metaBool(md, "noindex"),
@@ -949,7 +962,7 @@ function artifactToNode(ctx, route) {
949
962
  title,
950
963
  icon,
951
964
  url: Url(metaStr(md, "url") ?? ""),
952
- target: void 0
965
+ target: metaStr(md, "target")
953
966
  };
954
967
  return node;
955
968
  }
@@ -984,7 +997,10 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
984
997
  slug,
985
998
  icon,
986
999
  hidden: route.hidden,
987
- viewers
1000
+ authed: metaBool(md, "authed"),
1001
+ viewers,
1002
+ orphaned: metaBool(md, "orphaned"),
1003
+ featureFlags: metaFeatureFlags(md)
988
1004
  });
989
1005
  if (route.type === "rest") {
990
1006
  const endpointId = metaStr(md, "endpointId");
@@ -999,7 +1015,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
999
1015
  endpointId: EndpointId(endpointId),
1000
1016
  apiDefinitionId,
1001
1017
  isResponseStream: metaBool(md, "isResponseStream"),
1002
- availability: void 0,
1018
+ availability: metaStr(md, "availability"),
1003
1019
  playground: void 0
1004
1020
  };
1005
1021
  }
@@ -1015,7 +1031,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1015
1031
  method,
1016
1032
  webhookId: WebhookId(webhookId),
1017
1033
  apiDefinitionId,
1018
- availability: void 0
1034
+ availability: metaStr(md, "availability")
1019
1035
  };
1020
1036
  }
1021
1037
  if (route.type === "asyncapi") {
@@ -1028,7 +1044,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1028
1044
  ...meta,
1029
1045
  webSocketId: WebSocketId(webSocketId),
1030
1046
  apiDefinitionId,
1031
- availability: void 0,
1047
+ availability: metaStr(md, "availability"),
1032
1048
  playground: void 0
1033
1049
  };
1034
1050
  }
@@ -1044,7 +1060,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1044
1060
  method,
1045
1061
  grpcId: GrpcId(grpcId),
1046
1062
  apiDefinitionId,
1047
- availability: void 0
1063
+ availability: metaStr(md, "availability")
1048
1064
  };
1049
1065
  }
1050
1066
  if (route.type === "graphql") {
@@ -1060,12 +1076,69 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1060
1076
  graphqlOperationId: GraphQlOperationId(graphqlOperationId),
1061
1077
  graphqlOperationIds: void 0,
1062
1078
  apiDefinitionId,
1063
- availability: void 0,
1079
+ availability: metaStr(md, "availability"),
1064
1080
  playground: void 0
1065
1081
  };
1066
1082
  }
1067
1083
  return void 0;
1068
1084
  }
1085
+ function apiLeafPositionKey(node) {
1086
+ switch (node.type) {
1087
+ case "endpoint":
1088
+ return `endpoint:${node.endpointId}`;
1089
+ case "webhook":
1090
+ return `webhook:${node.webhookId}`;
1091
+ case "webSocket":
1092
+ return `webSocket:${node.webSocketId}`;
1093
+ case "grpc":
1094
+ return `grpc:${node.grpcId}`;
1095
+ case "graphql":
1096
+ return `graphql:${node.graphqlOperationId}`;
1097
+ }
1098
+ }
1099
+ function apiChildPositionKey(node) {
1100
+ switch (node.type) {
1101
+ case "endpoint":
1102
+ case "webhook":
1103
+ case "webSocket":
1104
+ case "grpc":
1105
+ case "graphql":
1106
+ return apiLeafPositionKey(node);
1107
+ default:
1108
+ return void 0;
1109
+ }
1110
+ }
1111
+ function positionedApiLeafChildren(ctx, nav, apiDefinitionId) {
1112
+ const rawLeafNodes = [];
1113
+ const leafPositions = /* @__PURE__ */ new Map();
1114
+ const nonApiLeafNodes = [];
1115
+ for (let i = 0; i < nav.length; i++) {
1116
+ const route = nav[i];
1117
+ const pos = route.displaySortOrder ?? i;
1118
+ const apiLeaf = apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId);
1119
+ if (apiLeaf != null) {
1120
+ rawLeafNodes.push(apiLeaf);
1121
+ const key = apiLeafPositionKey(apiLeaf);
1122
+ leafPositions.set(key, Math.min(leafPositions.get(key) ?? pos, pos));
1123
+ continue;
1124
+ }
1125
+ const node = artifactToNode(ctx, route);
1126
+ if (node?.type === "page" || node?.type === "link") {
1127
+ nonApiLeafNodes.push({ node, pos });
1128
+ }
1129
+ }
1130
+ const apiLeafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1131
+ const positionedApiLeafNodes = apiLeafNodes.map((node, index) => {
1132
+ if (node.type === "endpointPair") {
1133
+ const streamPos = leafPositions.get(apiLeafPositionKey(node.stream)) ?? index;
1134
+ const nonStreamPos = leafPositions.get(apiLeafPositionKey(node.nonStream)) ?? index;
1135
+ return { node, pos: Math.min(streamPos, nonStreamPos) };
1136
+ }
1137
+ const key = apiChildPositionKey(node);
1138
+ return { node, pos: key != null ? leafPositions.get(key) ?? index : index };
1139
+ });
1140
+ return [...positionedApiLeafNodes, ...nonApiLeafNodes];
1141
+ }
1069
1142
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1070
1143
  const ctx = createBuildContext(basePath);
1071
1144
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1167,17 +1240,22 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1167
1240
  slug,
1168
1241
  icon: metaStr(seg.metadata, "icon"),
1169
1242
  hidden: seg.hidden,
1170
- viewers: mergeVariantViewers(seg)
1243
+ authed: metaBool(seg.metadata, "authed"),
1244
+ viewers: mergeVariantViewers(seg),
1245
+ orphaned: metaBool(seg.metadata, "orphaned"),
1246
+ featureFlags: metaFeatureFlags(seg.metadata)
1171
1247
  });
1172
1248
  return {
1173
1249
  type: "section",
1174
1250
  ...defaults,
1175
- collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1251
+ // V2 convention: collapsed:false in docs.yml maps to "open-by-default"
1252
+ // so getInitiallyOpenByDefaultNodes picks it up and the UI starts open.
1253
+ collapsed: metaCollapsed(seg.metadata) === false ? "open-by-default" : metaCollapsed(seg.metadata) ?? defaults.collapsed,
1176
1254
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1177
- noindex: void 0,
1255
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1178
1256
  collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1179
1257
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1180
- availability: void 0,
1258
+ availability: metaStr(seg.metadata, "availability"),
1181
1259
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1182
1260
  children: mergeChildrenByPosition(ctx, nav, sectionChildren)
1183
1261
  };
@@ -1200,8 +1278,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1200
1278
  }
1201
1279
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1202
1280
  const { seg, nav } = scoped;
1203
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1204
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1281
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1205
1282
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1206
1283
  const packageNodes = childPackages.map((child) => ({
1207
1284
  node: apiPackageChildNode(
@@ -1215,18 +1292,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1215
1292
  }));
1216
1293
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1217
1294
  if (!hasChildIndex) {
1218
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1219
- }
1220
- const leafPositions = [];
1221
- for (const route of nav) {
1222
- if (route.displaySortOrder != null) {
1223
- leafPositions.push(route.displaySortOrder);
1224
- }
1295
+ return [...leafNodes, ...packageNodes.map((p) => ({ node: p.node, pos: Number.MAX_SAFE_INTEGER }))].sort((a, b) => a.pos - b.pos).map((p) => p.node);
1225
1296
  }
1226
1297
  const positioned = [];
1227
- for (let i = 0; i < leafNodes.length; i++) {
1228
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1229
- }
1298
+ positioned.push(...leafNodes);
1230
1299
  for (const p of packageNodes) {
1231
1300
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1232
1301
  }
@@ -1254,12 +1323,15 @@ function apiPackageChildNode(ctx, scoped, scopeSegs, parentApiDefinitionId, scop
1254
1323
  slug,
1255
1324
  icon: metaStr(seg.metadata, "icon"),
1256
1325
  hidden: seg.hidden,
1257
- viewers: toViewers(metaStrArr(seg.metadata, "viewers"))
1326
+ authed: metaBool(seg.metadata, "authed"),
1327
+ viewers: toViewers(metaStrArr(seg.metadata, "viewers")),
1328
+ orphaned: metaBool(seg.metadata, "orphaned"),
1329
+ featureFlags: metaFeatureFlags(seg.metadata)
1258
1330
  }),
1259
1331
  apiDefinitionId: ApiDefinitionId(apiDefinitionId),
1260
1332
  availability: metaStr(seg.metadata, "availability"),
1261
1333
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1262
- noindex: void 0,
1334
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1263
1335
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1264
1336
  children,
1265
1337
  playground: void 0
@@ -1339,12 +1411,15 @@ function apiReferenceNode(ctx, scoped, scopeSegs, scopePrefix) {
1339
1411
  slug,
1340
1412
  icon: metaStr(seg.metadata, "icon"),
1341
1413
  hidden: seg.hidden,
1342
- viewers: mergeVariantViewers(seg)
1414
+ authed: metaBool(seg.metadata, "authed"),
1415
+ viewers: mergeVariantViewers(seg),
1416
+ orphaned: metaBool(seg.metadata, "orphaned"),
1417
+ featureFlags: metaFeatureFlags(seg.metadata)
1343
1418
  }),
1344
1419
  apiDefinitionId: ApiDefinitionId(apiDefinitionId),
1345
- availability: void 0,
1420
+ availability: metaStr(seg.metadata, "availability"),
1346
1421
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1347
- noindex: void 0,
1422
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1348
1423
  paginated: true,
1349
1424
  showErrors: metaBool(seg.metadata, "showErrors"),
1350
1425
  hideTitle: metaBool(seg.metadata, "hideTitle"),
@@ -1397,12 +1472,15 @@ function changelogNode(ctx, scoped, scopePrefix) {
1397
1472
  slug: ctx.contentSlug(r.fullPath ?? ""),
1398
1473
  icon: metaStr(r.metadata, "icon"),
1399
1474
  hidden: r.hidden,
1400
- viewers: toViewers(metaStrArr(r.metadata, "viewers"))
1475
+ authed: metaBool(r.metadata, "authed"),
1476
+ viewers: toViewers(metaStrArr(r.metadata, "viewers")),
1477
+ orphaned: metaBool(r.metadata, "orphaned"),
1478
+ featureFlags: metaFeatureFlags(r.metadata)
1401
1479
  }),
1402
1480
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1403
- noindex: void 0,
1481
+ noindex: metaBool(r.metadata, "noindex"),
1404
1482
  date: dateStr ?? "",
1405
- tags: void 0
1483
+ tags: metaStrArr(r.metadata, "tags")
1406
1484
  };
1407
1485
  let months = byYear.get(year);
1408
1486
  if (months == null) {
@@ -1446,10 +1524,13 @@ function changelogNode(ctx, scoped, scopePrefix) {
1446
1524
  slug: baseSlug,
1447
1525
  icon: metaStr(seg.metadata, "icon"),
1448
1526
  hidden: seg.hidden,
1449
- viewers: mergeVariantViewers(seg)
1527
+ authed: metaBool(seg.metadata, "authed"),
1528
+ viewers: mergeVariantViewers(seg),
1529
+ orphaned: metaBool(seg.metadata, "orphaned"),
1530
+ featureFlags: metaFeatureFlags(seg.metadata)
1450
1531
  }),
1451
1532
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1452
- noindex: void 0,
1533
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1453
1534
  children: years
1454
1535
  };
1455
1536
  }
@@ -1506,17 +1587,55 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1506
1587
  return { node, childIndex };
1507
1588
  });
1508
1589
  }
1590
+ function computeSiblingSortBoundaries(ordered) {
1591
+ const result = /* @__PURE__ */ new Map();
1592
+ const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1593
+ const rootSections = [];
1594
+ for (const s of ordered) {
1595
+ const type = metaStr(s.seg.metadata, "type");
1596
+ const sec = s.seg.section;
1597
+ if (type !== "section" || sec === "") {
1598
+ continue;
1599
+ }
1600
+ const parent = parentSectionPath(sec);
1601
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1602
+ if (isRootLevel) {
1603
+ rootSections.push(s);
1604
+ }
1605
+ }
1606
+ const byPath = /* @__PURE__ */ new Map();
1607
+ for (const s of rootSections) {
1608
+ const group = byPath.get(s.seg.section) ?? [];
1609
+ group.push(s);
1610
+ byPath.set(s.seg.section, group);
1611
+ }
1612
+ for (const [, siblings] of byPath) {
1613
+ if (siblings.length <= 1) {
1614
+ continue;
1615
+ }
1616
+ for (let i = 0; i < siblings.length; i++) {
1617
+ const lo = siblings[i].seg.sortOrder;
1618
+ const hi = i + 1 < siblings.length ? siblings[i + 1].seg.sortOrder : Number.MAX_SAFE_INTEGER;
1619
+ result.set(siblings[i], { lo, hi });
1620
+ }
1621
+ }
1622
+ return result;
1623
+ }
1509
1624
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1510
1625
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1511
1626
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1512
1627
  const annotated = [];
1513
1628
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1629
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1514
1630
  for (const s of ordered) {
1515
1631
  const type = metaStr(s.seg.metadata, "type");
1516
1632
  const sec = s.seg.section;
1517
1633
  if (hasOwningApiReference(s, scopeSegs)) {
1518
1634
  continue;
1519
1635
  }
1636
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1637
+ continue;
1638
+ }
1520
1639
  if (type === "tabRoot" || sec === "" && type !== "section") {
1521
1640
  for (const r of s.nav) {
1522
1641
  const node = artifactToNode(ctx, r);
@@ -1544,14 +1663,21 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1544
1663
  } else if (type === "changelog") {
1545
1664
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1546
1665
  } else {
1666
+ const bounds = siblingBoundaries.get(s);
1667
+ const ownedSegs = bounds != null ? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi) : scopeSegs;
1547
1668
  node = sectionNode(
1548
1669
  ctx,
1549
1670
  s,
1550
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1671
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1551
1672
  scopePrefix
1552
1673
  );
1553
1674
  }
1554
- annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1675
+ const isSharedSection = siblingBoundaries.size > 0 && scopePrefix !== "" && sec !== "" && !sec.startsWith(scopePrefix);
1676
+ annotated.push({
1677
+ node,
1678
+ pos: isSharedSection ? void 0 : metaNum(s.seg.metadata, "childIndex"),
1679
+ isLeaf: false
1680
+ });
1555
1681
  }
1556
1682
  }
1557
1683
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1603,13 +1729,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1603
1729
  };
1604
1730
  }
1605
1731
  function buildFullRootFromSegments(options) {
1606
- const { basePath, title, segments, navBySegment } = options;
1732
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1607
1733
  const ctx = createBuildContext(basePath);
1608
1734
  const scoped = segments.filter((seg) => {
1609
1735
  const t = metaStr(seg.metadata, "type");
1610
1736
  return t !== "files" && t !== "redirects";
1611
1737
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1612
- const rootSlug = asSlug(basePath);
1738
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1613
1739
  const scopesByKey = /* @__PURE__ */ new Map();
1614
1740
  for (const s of scoped) {
1615
1741
  const key = scopeKey(s.seg);
@@ -1622,9 +1748,9 @@ function buildFullRootFromSegments(options) {
1622
1748
  const tabs = uniqueDetails(scoped, "tab");
1623
1749
  let child;
1624
1750
  if (products.length > 0) {
1625
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1751
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1626
1752
  } else if (versions.length > 0) {
1627
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1753
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1628
1754
  } else {
1629
1755
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1630
1756
  }
@@ -1635,6 +1761,24 @@ function buildFullRootFromSegments(options) {
1635
1761
  } else if (child.type === "versioned") {
1636
1762
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1637
1763
  rootPointsTo = defaultVersion?.pointsTo;
1764
+ } else if (child.type === "unversioned") {
1765
+ if (tabs.length > 0) {
1766
+ const firstTab = tabs[0];
1767
+ const pt = firstTab != null ? metaStr(firstTab.metadata, "pointsTo") : void 0;
1768
+ rootPointsTo = pt != null ? pointsToSlug(pt) : void 0;
1769
+ } else {
1770
+ const sorted = [...scoped].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1771
+ for (const s of sorted) {
1772
+ if (s.seg.hidden) {
1773
+ continue;
1774
+ }
1775
+ const pt = metaStr(s.seg.metadata, "pointsTo");
1776
+ if (pt != null) {
1777
+ rootPointsTo = pointsToSlug(pt);
1778
+ break;
1779
+ }
1780
+ }
1781
+ }
1638
1782
  }
1639
1783
  const root = {
1640
1784
  type: "root",
@@ -1647,21 +1791,22 @@ function buildFullRootFromSegments(options) {
1647
1791
  return root;
1648
1792
  }
1649
1793
  function uniqueDetails(scoped, dim) {
1650
- const bySlug = /* @__PURE__ */ new Map();
1794
+ const byKey = /* @__PURE__ */ new Map();
1651
1795
  for (const s of scoped) {
1652
1796
  const d = s.seg[dim];
1653
1797
  if (d == null) {
1654
1798
  continue;
1655
1799
  }
1656
1800
  const slug = detailSlug(d);
1657
- const existing = bySlug.get(slug);
1801
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1802
+ const existing = byKey.get(key);
1658
1803
  if (existing == null) {
1659
- bySlug.set(slug, d);
1804
+ byKey.set(key, d);
1660
1805
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1661
- bySlug.set(slug, d);
1806
+ byKey.set(key, d);
1662
1807
  }
1663
1808
  }
1664
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1809
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1665
1810
  }
1666
1811
  function scopeSlugPrefix(rootSlug, ...details) {
1667
1812
  const parts = [rootSlug];
@@ -1695,7 +1840,7 @@ function buildVariantedNode(ctx, variants, scopeSegs, scopePrefix) {
1695
1840
  default: detailIsDefault(variant),
1696
1841
  variantId: VariantId(String(variant.id)),
1697
1842
  subtitle: metaStr(variant.metadata, "subtitle") ?? void 0,
1698
- image: void 0,
1843
+ image: metaStr(variant.metadata, "image") != null ? FileId(metaStr(variant.metadata, "image")) : void 0,
1699
1844
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1700
1845
  children
1701
1846
  };
@@ -1744,7 +1889,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1744
1889
  title: tab.displayName,
1745
1890
  icon: tab.icon ?? void 0,
1746
1891
  url: Url(metaStr(tab.metadata, "url") ?? ""),
1747
- target: void 0
1892
+ target: metaStr(tab.metadata, "target")
1748
1893
  };
1749
1894
  }
1750
1895
  if (tabType === "changelog") {
@@ -1805,16 +1950,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1805
1950
  type: "unversioned",
1806
1951
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1807
1952
  collapsed: void 0,
1808
- landingPage: void 0,
1953
+ landingPage: buildLandingPage(ctx, scopeSegs),
1809
1954
  // The enclosing scope prefix (product slug, or rootSlug at the top
1810
1955
  // level) roots structural sections so they share the scope's slug
1811
1956
  // namespace.
1812
1957
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1813
1958
  };
1814
1959
  }
1815
- function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1960
+ function mergeSharedSections(defaultSegs, allScoped, defaultVersion, versionSlugs) {
1961
+ const defaultTabsByName = /* @__PURE__ */ new Map();
1962
+ for (const s of defaultSegs) {
1963
+ if (s.seg.tab != null) {
1964
+ const tabName = s.seg.tab.displayName;
1965
+ if (!defaultTabsByName.has(tabName)) {
1966
+ defaultTabsByName.set(tabName, s.seg.tab);
1967
+ }
1968
+ }
1969
+ }
1970
+ const existingSections = new Set(
1971
+ defaultSegs.filter((s) => metaStr(s.seg.metadata, "type") === "section").map((s) => s.seg.section)
1972
+ );
1973
+ const maxSortOrder = defaultSegs.reduce((max, s) => Math.max(max, s.seg.sortOrder), 0);
1974
+ let nextSortOrder = maxSortOrder + 1;
1975
+ const merged = [...defaultSegs];
1976
+ for (const s of allScoped) {
1977
+ if (s.seg.version?.id === defaultVersion.id) {
1978
+ continue;
1979
+ }
1980
+ const type = metaStr(s.seg.metadata, "type");
1981
+ if (type !== "section") {
1982
+ continue;
1983
+ }
1984
+ const sectionPath = s.seg.section;
1985
+ if (versionSlugs.some((vs) => sectionPath === vs || sectionPath.startsWith(vs + "/"))) {
1986
+ continue;
1987
+ }
1988
+ if (existingSections.has(sectionPath)) {
1989
+ continue;
1990
+ }
1991
+ const sourceTabName = s.seg.tab?.displayName ?? "";
1992
+ const targetTab = defaultTabsByName.get(sourceTabName);
1993
+ if (targetTab == null) {
1994
+ continue;
1995
+ }
1996
+ const metadata = s.seg.metadata != null ? { ...s.seg.metadata, childIndex: void 0 } : s.seg.metadata;
1997
+ merged.push({
1998
+ seg: {
1999
+ ...s.seg,
2000
+ tab: targetTab,
2001
+ version: defaultVersion,
2002
+ sortOrder: nextSortOrder++,
2003
+ metadata
2004
+ },
2005
+ nav: s.nav
2006
+ });
2007
+ existingSections.add(sectionPath);
2008
+ }
2009
+ return merged;
2010
+ }
2011
+ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix, skipSharedSectionMerge) {
2012
+ const versionSlugs = versions.map((v) => detailSlug(v)).filter((s) => s !== "");
1816
2013
  const children = versions.map((version) => {
1817
- const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2014
+ let versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2015
+ if (detailIsDefault(version) && !skipSharedSectionMerge) {
2016
+ versionSegs = mergeSharedSections(versionSegs, scoped, version, versionSlugs);
2017
+ }
1818
2018
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1819
2019
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1820
2020
  const versionSegment = detailSlug(version);
@@ -1832,7 +2032,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1832
2032
  default: detailIsDefault(version),
1833
2033
  versionId: VersionId(version.id),
1834
2034
  availability: void 0,
1835
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2035
+ landingPage: buildLandingPage(ctx, versionSegs),
1836
2036
  announcement: void 0,
1837
2037
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1838
2038
  // The version's full slug roots structural sections so the whole
@@ -1913,34 +2113,41 @@ function crossVersionDedupKeys(node, parents) {
1913
2113
  keys.push([...parentTitles, node.title].join("###"));
1914
2114
  return keys;
1915
2115
  }
1916
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1917
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1918
- if (tablessSegs.length === 0) {
2116
+ function routeToLandingPage(ctx, route) {
2117
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1919
2118
  return void 0;
1920
2119
  }
1921
- for (const s of tablessSegs) {
1922
- for (const r of s.nav) {
1923
- if (r.type === "markdown" && r.fullPath != null) {
1924
- const md = r.metadata;
1925
- const pageId = metaStr(md, "pageId") ?? "";
1926
- const slug = ctx.contentSlug(r.fullPath);
1927
- return {
1928
- type: "landingPage",
1929
- ...withMetadataDefaults({
1930
- id: ctx.nodeId(`landing:${slug}`),
1931
- title: metaStr(md, "title") ?? "",
1932
- slug,
1933
- icon: metaStr(md, "icon"),
1934
- hidden: r.hidden,
1935
- viewers: toViewers(metaStrArr(md, "viewers"))
1936
- }),
1937
- pageId: PageId(pageId),
1938
- noindex: metaBool(md, "noindex")
1939
- };
1940
- }
1941
- }
2120
+ const md = route.metadata;
2121
+ const pageId = metaStr(md, "pageId");
2122
+ if (pageId == null) {
2123
+ return void 0;
1942
2124
  }
1943
- return void 0;
2125
+ const slug = ctx.contentSlug(route.fullPath);
2126
+ return {
2127
+ type: "landingPage",
2128
+ ...withMetadataDefaults({
2129
+ id: ctx.nodeId(`landing:${slug}`),
2130
+ title: metaStr(md, "title") ?? "",
2131
+ slug,
2132
+ icon: metaStr(md, "icon"),
2133
+ hidden: route.hidden,
2134
+ authed: metaBool(md, "authed"),
2135
+ viewers: toViewers(metaStrArr(md, "viewers")),
2136
+ orphaned: metaBool(md, "orphaned"),
2137
+ featureFlags: metaFeatureFlags(md)
2138
+ }),
2139
+ pageId: PageId(pageId),
2140
+ noindex: metaBool(md, "noindex")
2141
+ };
2142
+ }
2143
+ function buildLandingPage(ctx, scopeSegs) {
2144
+ const landingSegment = scopeSegs.find(
2145
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2146
+ );
2147
+ return routeToLandingPage(
2148
+ ctx,
2149
+ landingSegment?.nav.find((route) => route.type === "markdown")
2150
+ );
1944
2151
  }
1945
2152
  function markCrossVersionCanonicalSlugs(versionNodes) {
1946
2153
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -1975,13 +2182,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
1975
2182
  });
1976
2183
  }
1977
2184
  }
1978
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2185
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
1979
2186
  const children = products.map((product) => {
1980
2187
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
1981
2188
  const versions = uniqueDetails(productSegs, "version");
1982
2189
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
1983
2190
  const productPrefix = scopeSlugPrefix(rootSlug, product);
1984
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2191
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix, skipSharedSectionMerge) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
1985
2192
  const node = {
1986
2193
  type: "product",
1987
2194
  ...withMetadataDefaults({
@@ -2000,7 +2207,7 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2000
2207
  // here; sourcing it from the hash makes that filter match nothing.
2001
2208
  productId: ProductId(product.displayName),
2002
2209
  subtitle: metaStr(product.metadata, "subtitle") ?? "",
2003
- image: void 0,
2210
+ image: metaStr(product.metadata, "image") != null ? FileId(metaStr(product.metadata, "image")) : void 0,
2004
2211
  announcement: void 0,
2005
2212
  pointsTo: metaStr(product.metadata, "pointsTo") != null ? pointsToSlug(metaStr(product.metadata, "pointsTo")) : void 0,
2006
2213
  child: productChild
@@ -2011,7 +2218,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2011
2218
  type: "productgroup",
2012
2219
  id: ctx.nodeId("productgroup"),
2013
2220
  collapsed: void 0,
2014
- landingPage: void 0,
2221
+ landingPage: buildLandingPage(
2222
+ ctx,
2223
+ scoped.filter((s) => s.seg.product == null)
2224
+ ),
2015
2225
  children
2016
2226
  };
2017
2227
  }