@fern-api/fdr-sdk 1.2.39-cc5ce5c5b6 → 1.2.39-dc3805e7f9

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 (94) hide show
  1. package/dist/js/client/FdrClient.js +1 -0
  2. package/dist/js/client/FdrClient.js.map +1 -1
  3. package/dist/js/client/FdrClient.mjs +1 -0
  4. package/dist/js/client/FdrClient.mjs.map +1 -1
  5. package/dist/js/converters/index.js +1 -6
  6. package/dist/js/converters/index.js.map +1 -1
  7. package/dist/js/converters/index.mjs +1 -6
  8. package/dist/js/converters/index.mjs.map +1 -1
  9. package/dist/js/index.js +2 -6
  10. package/dist/js/index.js.map +1 -1
  11. package/dist/js/index.mjs +2 -6
  12. package/dist/js/index.mjs.map +1 -1
  13. package/dist/js/navigation/index.js +1 -6
  14. package/dist/js/navigation/index.js.map +1 -1
  15. package/dist/js/navigation/index.mjs +1 -6
  16. package/dist/js/navigation/index.mjs.map +1 -1
  17. package/dist/js/navigation/ledger-root-builder.js +228 -58
  18. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  19. package/dist/js/navigation/ledger-root-builder.mjs +228 -58
  20. package/dist/js/navigation/ledger-root-builder.mjs.map +1 -1
  21. package/dist/js/orpc-client.js +1 -0
  22. package/dist/js/orpc-client.js.map +1 -1
  23. package/dist/js/orpc-client.mjs +1 -0
  24. package/dist/js/orpc-client.mjs.map +1 -1
  25. package/dist/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts +2 -0
  26. package/dist/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts.map +1 -0
  27. package/dist/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.js +85 -0
  28. package/dist/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.js.map +1 -0
  29. package/dist/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts +2 -0
  30. package/dist/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts.map +1 -0
  31. package/dist/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.js +85 -0
  32. package/dist/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.js.map +1 -0
  33. package/dist/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  34. package/dist/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  35. package/dist/navigation/__test__/ledger-root-builder.landingPage.test.js +82 -0
  36. package/dist/navigation/__test__/ledger-root-builder.landingPage.test.js.map +1 -0
  37. package/dist/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts +2 -0
  38. package/dist/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts.map +1 -0
  39. package/dist/navigation/__test__/ledger-root-builder.metadataPreservation.test.js +1031 -0
  40. package/dist/navigation/__test__/ledger-root-builder.metadataPreservation.test.js.map +1 -0
  41. package/dist/navigation/__test__/ledger-root-builder.rootChildOrder.test.js +22 -9
  42. package/dist/navigation/__test__/ledger-root-builder.rootChildOrder.test.js.map +1 -1
  43. package/dist/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  44. package/dist/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  45. package/dist/navigation/__test__/ledger-root-builder.rootSlug.test.js +47 -0
  46. package/dist/navigation/__test__/ledger-root-builder.rootSlug.test.js.map +1 -0
  47. package/dist/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts +2 -0
  48. package/dist/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts.map +1 -0
  49. package/dist/navigation/__test__/ledger-root-builder.skipSlugTabs.test.js +284 -0
  50. package/dist/navigation/__test__/ledger-root-builder.skipSlugTabs.test.js.map +1 -0
  51. package/dist/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts +2 -0
  52. package/dist/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts.map +1 -0
  53. package/dist/navigation/__test__/ledger-root-builder.variantSharedSegments.test.js +262 -0
  54. package/dist/navigation/__test__/ledger-root-builder.variantSharedSegments.test.js.map +1 -0
  55. package/dist/navigation/ledger-root-builder.d.ts +12 -0
  56. package/dist/navigation/ledger-root-builder.d.ts.map +1 -1
  57. package/dist/navigation/ledger-root-builder.js +298 -69
  58. package/dist/navigation/ledger-root-builder.js.map +1 -1
  59. package/dist/navigation/utils/findNode.d.ts.map +1 -1
  60. package/dist/navigation/utils/findNode.js +0 -8
  61. package/dist/navigation/utils/findNode.js.map +1 -1
  62. package/dist/navigation/utils/followRedirect.d.ts.map +1 -1
  63. package/dist/navigation/utils/followRedirect.js +2 -0
  64. package/dist/navigation/utils/followRedirect.js.map +1 -1
  65. package/dist/orpc-client/docs-ledger/contract.d.ts +50 -0
  66. package/dist/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  67. package/dist/orpc-client/docs-ledger/contract.js +1 -0
  68. package/dist/orpc-client/docs-ledger/contract.js.map +1 -1
  69. package/dist/orpc-client/docs-ledger/ledger-manifest.d.ts +12 -0
  70. package/dist/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts +2 -0
  73. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts.map +1 -0
  74. package/dist/types/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts +2 -0
  75. package/dist/types/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts.map +1 -0
  76. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  77. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  78. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts +2 -0
  79. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts.map +1 -0
  80. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  81. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  82. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts +2 -0
  83. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts.map +1 -0
  84. package/dist/types/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts +2 -0
  85. package/dist/types/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts.map +1 -0
  86. package/dist/types/navigation/ledger-root-builder.d.ts +12 -0
  87. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  88. package/dist/types/navigation/utils/findNode.d.ts.map +1 -1
  89. package/dist/types/navigation/utils/followRedirect.d.ts.map +1 -1
  90. package/dist/types/orpc-client/docs-ledger/contract.d.ts +50 -0
  91. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  92. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +12 -0
  93. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  94. package/package.json +1 -1
@@ -1082,6 +1082,63 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1082
1082
  }
1083
1083
  return void 0;
1084
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
+ }
1085
1142
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1086
1143
  const ctx = createBuildContext(basePath);
1087
1144
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1191,12 +1248,10 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1191
1248
  return {
1192
1249
  type: "section",
1193
1250
  ...defaults,
1194
- // V2 convention: collapsed:false in docs.yml maps to "open-by-default"
1195
- // so getInitiallyOpenByDefaultNodes picks it up and the UI starts open.
1196
- collapsed: metaCollapsed(seg.metadata) === false ? "open-by-default" : metaCollapsed(seg.metadata) ?? defaults.collapsed,
1251
+ collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1197
1252
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1198
1253
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1199
- collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1254
+ collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1200
1255
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1201
1256
  availability: metaStr(seg.metadata, "availability"),
1202
1257
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1221,8 +1276,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1221
1276
  }
1222
1277
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1223
1278
  const { seg, nav } = scoped;
1224
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1225
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1279
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1226
1280
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1227
1281
  const packageNodes = childPackages.map((child) => ({
1228
1282
  node: apiPackageChildNode(
@@ -1236,18 +1290,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1236
1290
  }));
1237
1291
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1238
1292
  if (!hasChildIndex) {
1239
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1240
- }
1241
- const leafPositions = [];
1242
- for (const route of nav) {
1243
- if (route.displaySortOrder != null) {
1244
- leafPositions.push(route.displaySortOrder);
1245
- }
1293
+ return [...leafNodes, ...packageNodes.map((p) => ({ node: p.node, pos: Number.MAX_SAFE_INTEGER }))].sort((a, b) => a.pos - b.pos).map((p) => p.node);
1246
1294
  }
1247
1295
  const positioned = [];
1248
- for (let i = 0; i < leafNodes.length; i++) {
1249
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1250
- }
1296
+ positioned.push(...leafNodes);
1251
1297
  for (const p of packageNodes) {
1252
1298
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1253
1299
  }
@@ -1432,7 +1478,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1432
1478
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1433
1479
  noindex: metaBool(r.metadata, "noindex"),
1434
1480
  date: dateStr ?? "",
1435
- tags: void 0
1481
+ tags: metaStrArr(r.metadata, "tags")
1436
1482
  };
1437
1483
  let months = byYear.get(year);
1438
1484
  if (months == null) {
@@ -1539,17 +1585,55 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1539
1585
  return { node, childIndex };
1540
1586
  });
1541
1587
  }
1588
+ function computeSiblingSortBoundaries(ordered) {
1589
+ const result = /* @__PURE__ */ new Map();
1590
+ const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1591
+ const rootSections = [];
1592
+ for (const s of ordered) {
1593
+ const type = metaStr(s.seg.metadata, "type");
1594
+ const sec = s.seg.section;
1595
+ if (type !== "section" || sec === "") {
1596
+ continue;
1597
+ }
1598
+ const parent = parentSectionPath(sec);
1599
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1600
+ if (isRootLevel) {
1601
+ rootSections.push(s);
1602
+ }
1603
+ }
1604
+ const byPath = /* @__PURE__ */ new Map();
1605
+ for (const s of rootSections) {
1606
+ const group = byPath.get(s.seg.section) ?? [];
1607
+ group.push(s);
1608
+ byPath.set(s.seg.section, group);
1609
+ }
1610
+ for (const [, siblings] of byPath) {
1611
+ if (siblings.length <= 1) {
1612
+ continue;
1613
+ }
1614
+ for (let i = 0; i < siblings.length; i++) {
1615
+ const lo = siblings[i].seg.sortOrder;
1616
+ const hi = i + 1 < siblings.length ? siblings[i + 1].seg.sortOrder : Number.MAX_SAFE_INTEGER;
1617
+ result.set(siblings[i], { lo, hi });
1618
+ }
1619
+ }
1620
+ return result;
1621
+ }
1542
1622
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1543
1623
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1544
1624
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1545
1625
  const annotated = [];
1546
1626
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1627
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1547
1628
  for (const s of ordered) {
1548
1629
  const type = metaStr(s.seg.metadata, "type");
1549
1630
  const sec = s.seg.section;
1550
1631
  if (hasOwningApiReference(s, scopeSegs)) {
1551
1632
  continue;
1552
1633
  }
1634
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1635
+ continue;
1636
+ }
1553
1637
  if (type === "tabRoot" || sec === "" && type !== "section") {
1554
1638
  for (const r of s.nav) {
1555
1639
  const node = artifactToNode(ctx, r);
@@ -1577,14 +1661,21 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1577
1661
  } else if (type === "changelog") {
1578
1662
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1579
1663
  } else {
1664
+ const bounds = siblingBoundaries.get(s);
1665
+ const ownedSegs = bounds != null ? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi) : scopeSegs;
1580
1666
  node = sectionNode(
1581
1667
  ctx,
1582
1668
  s,
1583
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1669
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1584
1670
  scopePrefix
1585
1671
  );
1586
1672
  }
1587
- annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1673
+ const isSharedSection = siblingBoundaries.size > 0 && scopePrefix !== "" && sec !== "" && !sec.startsWith(scopePrefix);
1674
+ annotated.push({
1675
+ node,
1676
+ pos: isSharedSection ? void 0 : metaNum(s.seg.metadata, "childIndex"),
1677
+ isLeaf: false
1678
+ });
1588
1679
  }
1589
1680
  }
1590
1681
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1636,13 +1727,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1636
1727
  };
1637
1728
  }
1638
1729
  function buildFullRootFromSegments(options) {
1639
- const { basePath, title, segments, navBySegment } = options;
1730
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1640
1731
  const ctx = createBuildContext(basePath);
1641
1732
  const scoped = segments.filter((seg) => {
1642
1733
  const t = metaStr(seg.metadata, "type");
1643
1734
  return t !== "files" && t !== "redirects";
1644
1735
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1645
- const rootSlug = asSlug(basePath);
1736
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1646
1737
  const scopesByKey = /* @__PURE__ */ new Map();
1647
1738
  for (const s of scoped) {
1648
1739
  const key = scopeKey(s.seg);
@@ -1655,9 +1746,9 @@ function buildFullRootFromSegments(options) {
1655
1746
  const tabs = uniqueDetails(scoped, "tab");
1656
1747
  let child;
1657
1748
  if (products.length > 0) {
1658
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1749
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1659
1750
  } else if (versions.length > 0) {
1660
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1751
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1661
1752
  } else {
1662
1753
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1663
1754
  }
@@ -1705,7 +1796,7 @@ function uniqueDetails(scoped, dim) {
1705
1796
  continue;
1706
1797
  }
1707
1798
  const slug = detailSlug(d);
1708
- const key = slug !== "" ? slug : d.id;
1799
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1709
1800
  const existing = byKey.get(key);
1710
1801
  if (existing == null) {
1711
1802
  byKey.set(key, d);
@@ -1764,20 +1855,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1764
1855
  if (variants.length <= 1) {
1765
1856
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1766
1857
  }
1858
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1767
1859
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1860
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1768
1861
  const first = scopeSegs[0];
1769
1862
  return {
1770
1863
  type: "sidebarRoot",
1771
1864
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1772
1865
  collapsed: void 0,
1773
- children: [variantedNode]
1866
+ children: [...sharedChildren, variantedNode]
1774
1867
  };
1775
1868
  }
1776
1869
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1777
1870
  if (!tabsPresent) {
1778
1871
  const variants = uniqueDetails(scopeSegs, "variant");
1779
1872
  if (variants.length > 1) {
1780
- return buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1873
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1874
+ const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1875
+ if (sharedSegs.length > 0) {
1876
+ const sharedChildren = buildSidebarRootChildren(ctx, sharedSegs, scopePrefix);
1877
+ const first2 = scopeSegs[0];
1878
+ return {
1879
+ type: "sidebarRoot",
1880
+ id: ctx.nodeId(`sidebar:${first2 != null ? scopeKey(first2.seg) : "root"}`),
1881
+ collapsed: void 0,
1882
+ children: [...sharedChildren, variantedNode]
1883
+ };
1884
+ }
1885
+ return variantedNode;
1781
1886
  }
1782
1887
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1783
1888
  }
@@ -1857,16 +1962,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1857
1962
  type: "unversioned",
1858
1963
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1859
1964
  collapsed: void 0,
1860
- landingPage: void 0,
1965
+ landingPage: buildLandingPage(ctx, scopeSegs),
1861
1966
  // The enclosing scope prefix (product slug, or rootSlug at the top
1862
1967
  // level) roots structural sections so they share the scope's slug
1863
1968
  // namespace.
1864
1969
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1865
1970
  };
1866
1971
  }
1867
- function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1972
+ function mergeSharedSections(defaultSegs, allScoped, defaultVersion, versionSlugs) {
1973
+ const defaultTabsByName = /* @__PURE__ */ new Map();
1974
+ for (const s of defaultSegs) {
1975
+ if (s.seg.tab != null) {
1976
+ const tabName = s.seg.tab.displayName;
1977
+ if (!defaultTabsByName.has(tabName)) {
1978
+ defaultTabsByName.set(tabName, s.seg.tab);
1979
+ }
1980
+ }
1981
+ }
1982
+ const existingSections = new Set(
1983
+ defaultSegs.filter((s) => metaStr(s.seg.metadata, "type") === "section").map((s) => s.seg.section)
1984
+ );
1985
+ const maxSortOrder = defaultSegs.reduce((max, s) => Math.max(max, s.seg.sortOrder), 0);
1986
+ let nextSortOrder = maxSortOrder + 1;
1987
+ const merged = [...defaultSegs];
1988
+ for (const s of allScoped) {
1989
+ if (s.seg.version?.id === defaultVersion.id) {
1990
+ continue;
1991
+ }
1992
+ const type = metaStr(s.seg.metadata, "type");
1993
+ if (type !== "section") {
1994
+ continue;
1995
+ }
1996
+ const sectionPath = s.seg.section;
1997
+ if (versionSlugs.some((vs) => sectionPath === vs || sectionPath.startsWith(vs + "/"))) {
1998
+ continue;
1999
+ }
2000
+ if (existingSections.has(sectionPath)) {
2001
+ continue;
2002
+ }
2003
+ const sourceTabName = s.seg.tab?.displayName ?? "";
2004
+ const targetTab = defaultTabsByName.get(sourceTabName);
2005
+ if (targetTab == null) {
2006
+ continue;
2007
+ }
2008
+ const metadata = s.seg.metadata != null ? { ...s.seg.metadata, childIndex: void 0 } : s.seg.metadata;
2009
+ merged.push({
2010
+ seg: {
2011
+ ...s.seg,
2012
+ tab: targetTab,
2013
+ version: defaultVersion,
2014
+ sortOrder: nextSortOrder++,
2015
+ metadata
2016
+ },
2017
+ nav: s.nav
2018
+ });
2019
+ existingSections.add(sectionPath);
2020
+ }
2021
+ return merged;
2022
+ }
2023
+ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix, skipSharedSectionMerge) {
2024
+ const versionSlugs = versions.map((v) => detailSlug(v)).filter((s) => s !== "");
1868
2025
  const children = versions.map((version) => {
1869
- const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2026
+ let versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2027
+ if (detailIsDefault(version) && !skipSharedSectionMerge) {
2028
+ versionSegs = mergeSharedSections(versionSegs, scoped, version, versionSlugs);
2029
+ }
1870
2030
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1871
2031
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1872
2032
  const versionSegment = detailSlug(version);
@@ -1884,7 +2044,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1884
2044
  default: detailIsDefault(version),
1885
2045
  versionId: VersionId(version.id),
1886
2046
  availability: void 0,
1887
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2047
+ landingPage: buildLandingPage(ctx, versionSegs),
1888
2048
  announcement: void 0,
1889
2049
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1890
2050
  // The version's full slug roots structural sections so the whole
@@ -1965,34 +2125,41 @@ function crossVersionDedupKeys(node, parents) {
1965
2125
  keys.push([...parentTitles, node.title].join("###"));
1966
2126
  return keys;
1967
2127
  }
1968
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1969
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1970
- if (tablessSegs.length === 0) {
2128
+ function routeToLandingPage(ctx, route) {
2129
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1971
2130
  return void 0;
1972
2131
  }
1973
- for (const s of tablessSegs) {
1974
- for (const r of s.nav) {
1975
- if (r.type === "markdown" && r.fullPath != null) {
1976
- const md = r.metadata;
1977
- const pageId = metaStr(md, "pageId") ?? "";
1978
- const slug = ctx.contentSlug(r.fullPath);
1979
- return {
1980
- type: "landingPage",
1981
- ...withMetadataDefaults({
1982
- id: ctx.nodeId(`landing:${slug}`),
1983
- title: metaStr(md, "title") ?? "",
1984
- slug,
1985
- icon: metaStr(md, "icon"),
1986
- hidden: r.hidden,
1987
- viewers: toViewers(metaStrArr(md, "viewers"))
1988
- }),
1989
- pageId: PageId(pageId),
1990
- noindex: metaBool(md, "noindex")
1991
- };
1992
- }
1993
- }
2132
+ const md = route.metadata;
2133
+ const pageId = metaStr(md, "pageId");
2134
+ if (pageId == null) {
2135
+ return void 0;
1994
2136
  }
1995
- return void 0;
2137
+ const slug = ctx.contentSlug(route.fullPath);
2138
+ return {
2139
+ type: "landingPage",
2140
+ ...withMetadataDefaults({
2141
+ id: ctx.nodeId(`landing:${slug}`),
2142
+ title: metaStr(md, "title") ?? "",
2143
+ slug,
2144
+ icon: metaStr(md, "icon"),
2145
+ hidden: route.hidden,
2146
+ authed: metaBool(md, "authed"),
2147
+ viewers: toViewers(metaStrArr(md, "viewers")),
2148
+ orphaned: metaBool(md, "orphaned"),
2149
+ featureFlags: metaFeatureFlags(md)
2150
+ }),
2151
+ pageId: PageId(pageId),
2152
+ noindex: metaBool(md, "noindex")
2153
+ };
2154
+ }
2155
+ function buildLandingPage(ctx, scopeSegs) {
2156
+ const landingSegment = scopeSegs.find(
2157
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2158
+ );
2159
+ return routeToLandingPage(
2160
+ ctx,
2161
+ landingSegment?.nav.find((route) => route.type === "markdown")
2162
+ );
1996
2163
  }
1997
2164
  function markCrossVersionCanonicalSlugs(versionNodes) {
1998
2165
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2027,13 +2194,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2027
2194
  });
2028
2195
  }
2029
2196
  }
2030
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2197
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2031
2198
  const children = products.map((product) => {
2032
2199
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2033
2200
  const versions = uniqueDetails(productSegs, "version");
2034
2201
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2035
2202
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2036
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2203
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix, skipSharedSectionMerge) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2037
2204
  const node = {
2038
2205
  type: "product",
2039
2206
  ...withMetadataDefaults({
@@ -2063,7 +2230,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2063
2230
  type: "productgroup",
2064
2231
  id: ctx.nodeId("productgroup"),
2065
2232
  collapsed: void 0,
2066
- landingPage: void 0,
2233
+ landingPage: buildLandingPage(
2234
+ ctx,
2235
+ scoped.filter((s) => s.seg.product == null)
2236
+ ),
2067
2237
  children
2068
2238
  };
2069
2239
  }