@fern-api/fdr-sdk 1.2.39-b5d93657fe → 1.2.39-bcfd2ff480

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 (55) 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 +4 -9
  6. package/dist/js/converters/index.js.map +1 -1
  7. package/dist/js/converters/index.mjs +4 -9
  8. package/dist/js/converters/index.mjs.map +1 -1
  9. package/dist/js/index.js +5 -9
  10. package/dist/js/index.js.map +1 -1
  11. package/dist/js/index.mjs +5 -9
  12. package/dist/js/index.mjs.map +1 -1
  13. package/dist/js/navigation/index.js +4 -9
  14. package/dist/js/navigation/index.js.map +1 -1
  15. package/dist/js/navigation/index.mjs +4 -9
  16. package/dist/js/navigation/index.mjs.map +1 -1
  17. package/dist/js/navigation/ledger-root-builder.js +265 -66
  18. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  19. package/dist/js/navigation/ledger-root-builder.mjs +265 -66
  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/tsconfig.tsbuildinfo +1 -1
  26. package/dist/types/navigation/__test__/findNode.authedRedirect.test.d.ts +2 -0
  27. package/dist/types/navigation/__test__/findNode.authedRedirect.test.d.ts.map +1 -0
  28. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts +2 -0
  29. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts.map +1 -0
  30. package/dist/types/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts +2 -0
  31. package/dist/types/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts.map +1 -0
  32. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  33. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  34. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts +2 -0
  35. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts.map +1 -0
  36. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  37. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  38. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugApiReference.test.d.ts +2 -0
  39. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugApiReference.test.d.ts.map +1 -0
  40. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts +2 -0
  41. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts.map +1 -0
  42. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts +2 -0
  43. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts.map +1 -0
  44. package/dist/types/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts +2 -0
  45. package/dist/types/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts.map +1 -0
  46. package/dist/types/navigation/ledger-root-builder.d.ts +17 -1
  47. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  48. package/dist/types/navigation/utils/findNode.d.ts +1 -0
  49. package/dist/types/navigation/utils/findNode.d.ts.map +1 -1
  50. package/dist/types/navigation/utils/followRedirect.d.ts.map +1 -1
  51. package/dist/types/orpc-client/docs-ledger/contract.d.ts +50 -0
  52. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  53. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +12 -0
  54. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  55. package/package.json +1 -1
@@ -805,6 +805,14 @@ function traverseDF(node, visit) {
805
805
  }
806
806
 
807
807
  // src/navigation/ledger-root-builder.ts
808
+ var STRUCTURAL_SEGMENT_TYPES = /* @__PURE__ */ new Set([
809
+ "section",
810
+ "apiReference",
811
+ "apiPackage",
812
+ "changelog"
813
+ ]);
814
+ var API_NODE_SEGMENT_TYPES = /* @__PURE__ */ new Set(["apiReference", "apiPackage"]);
815
+ var INFRA_SEGMENT_TYPES = /* @__PURE__ */ new Set(["files", "redirects"]);
808
816
  function createBuildContext(basePath) {
809
817
  const seen = /* @__PURE__ */ new Map();
810
818
  const basePrefix = basePath.replace(/^\/+|\/+$/g, "");
@@ -882,7 +890,7 @@ function toViewers(viewers) {
882
890
  return viewers.map((v) => RoleId(v));
883
891
  }
884
892
  function mergeVariantViewers(seg) {
885
- const segViewers = seg.metadata.type === "section" || seg.metadata.type === "apiReference" || seg.metadata.type === "apiPackage" || seg.metadata.type === "changelog" ? seg.metadata.viewers : void 0;
893
+ const segViewers = STRUCTURAL_SEGMENT_TYPES.has(seg.metadata.type) ? seg.metadata.viewers : void 0;
886
894
  const variantViewers = seg.variant?.viewers;
887
895
  if ((segViewers == null || segViewers.length === 0) && (variantViewers == null || variantViewers.length === 0)) {
888
896
  return void 0;
@@ -1082,6 +1090,63 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1082
1090
  }
1083
1091
  return void 0;
1084
1092
  }
1093
+ function apiLeafPositionKey(node) {
1094
+ switch (node.type) {
1095
+ case "endpoint":
1096
+ return `endpoint:${node.endpointId}`;
1097
+ case "webhook":
1098
+ return `webhook:${node.webhookId}`;
1099
+ case "webSocket":
1100
+ return `webSocket:${node.webSocketId}`;
1101
+ case "grpc":
1102
+ return `grpc:${node.grpcId}`;
1103
+ case "graphql":
1104
+ return `graphql:${node.graphqlOperationId}`;
1105
+ }
1106
+ }
1107
+ function apiChildPositionKey(node) {
1108
+ switch (node.type) {
1109
+ case "endpoint":
1110
+ case "webhook":
1111
+ case "webSocket":
1112
+ case "grpc":
1113
+ case "graphql":
1114
+ return apiLeafPositionKey(node);
1115
+ default:
1116
+ return void 0;
1117
+ }
1118
+ }
1119
+ function positionedApiLeafChildren(ctx, nav, apiDefinitionId) {
1120
+ const rawLeafNodes = [];
1121
+ const leafPositions = /* @__PURE__ */ new Map();
1122
+ const nonApiLeafNodes = [];
1123
+ for (let i = 0; i < nav.length; i++) {
1124
+ const route = nav[i];
1125
+ const pos = route.displaySortOrder ?? i;
1126
+ const apiLeaf = apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId);
1127
+ if (apiLeaf != null) {
1128
+ rawLeafNodes.push(apiLeaf);
1129
+ const key = apiLeafPositionKey(apiLeaf);
1130
+ leafPositions.set(key, Math.min(leafPositions.get(key) ?? pos, pos));
1131
+ continue;
1132
+ }
1133
+ const node = artifactToNode(ctx, route);
1134
+ if (node?.type === "page" || node?.type === "link") {
1135
+ nonApiLeafNodes.push({ node, pos });
1136
+ }
1137
+ }
1138
+ const apiLeafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1139
+ const positionedApiLeafNodes = apiLeafNodes.map((node, index) => {
1140
+ if (node.type === "endpointPair") {
1141
+ const streamPos = leafPositions.get(apiLeafPositionKey(node.stream)) ?? index;
1142
+ const nonStreamPos = leafPositions.get(apiLeafPositionKey(node.nonStream)) ?? index;
1143
+ return { node, pos: Math.min(streamPos, nonStreamPos) };
1144
+ }
1145
+ const key = apiChildPositionKey(node);
1146
+ return { node, pos: key != null ? leafPositions.get(key) ?? index : index };
1147
+ });
1148
+ return [...positionedApiLeafNodes, ...nonApiLeafNodes];
1149
+ }
1085
1150
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1086
1151
  const ctx = createBuildContext(basePath);
1087
1152
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1194,7 +1259,7 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1194
1259
  collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1195
1260
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1196
1261
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1197
- collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1262
+ collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1198
1263
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1199
1264
  availability: metaStr(seg.metadata, "availability"),
1200
1265
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1219,8 +1284,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1219
1284
  }
1220
1285
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1221
1286
  const { seg, nav } = scoped;
1222
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1223
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1287
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1224
1288
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1225
1289
  const packageNodes = childPackages.map((child) => ({
1226
1290
  node: apiPackageChildNode(
@@ -1234,18 +1298,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1234
1298
  }));
1235
1299
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1236
1300
  if (!hasChildIndex) {
1237
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1238
- }
1239
- const leafPositions = [];
1240
- for (const route of nav) {
1241
- if (route.displaySortOrder != null) {
1242
- leafPositions.push(route.displaySortOrder);
1243
- }
1301
+ return [...leafNodes, ...packageNodes.map((p) => ({ node: p.node, pos: Number.MAX_SAFE_INTEGER }))].sort((a, b) => a.pos - b.pos).map((p) => p.node);
1244
1302
  }
1245
1303
  const positioned = [];
1246
- for (let i = 0; i < leafNodes.length; i++) {
1247
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1248
- }
1304
+ positioned.push(...leafNodes);
1249
1305
  for (const p of packageNodes) {
1250
1306
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1251
1307
  }
@@ -1430,7 +1486,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1430
1486
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1431
1487
  noindex: metaBool(r.metadata, "noindex"),
1432
1488
  date: dateStr ?? "",
1433
- tags: void 0
1489
+ tags: metaStrArr(r.metadata, "tags")
1434
1490
  };
1435
1491
  let months = byYear.get(year);
1436
1492
  if (months == null) {
@@ -1522,7 +1578,7 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1522
1578
  const type = metaStr(s.seg.metadata, "type");
1523
1579
  const childIndex = metaNum(s.seg.metadata, "childIndex");
1524
1580
  let node;
1525
- if (type === "apiReference" || type === "apiPackage") {
1581
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1526
1582
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1527
1583
  } else if (type === "changelog") {
1528
1584
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
@@ -1537,18 +1593,56 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1537
1593
  return { node, childIndex };
1538
1594
  });
1539
1595
  }
1596
+ function computeSiblingSortBoundaries(ordered) {
1597
+ const result = /* @__PURE__ */ new Map();
1598
+ const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1599
+ const rootSections = [];
1600
+ for (const s of ordered) {
1601
+ const type = metaStr(s.seg.metadata, "type");
1602
+ const sec = s.seg.section;
1603
+ if (type !== "section" || sec === "") {
1604
+ continue;
1605
+ }
1606
+ const parent = parentSectionPath(sec);
1607
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1608
+ if (isRootLevel) {
1609
+ rootSections.push(s);
1610
+ }
1611
+ }
1612
+ const byPath = /* @__PURE__ */ new Map();
1613
+ for (const s of rootSections) {
1614
+ const group = byPath.get(s.seg.section) ?? [];
1615
+ group.push(s);
1616
+ byPath.set(s.seg.section, group);
1617
+ }
1618
+ for (const [, siblings] of byPath) {
1619
+ if (siblings.length <= 1) {
1620
+ continue;
1621
+ }
1622
+ for (let i = 0; i < siblings.length; i++) {
1623
+ const lo = siblings[i].seg.sortOrder;
1624
+ const hi = i + 1 < siblings.length ? siblings[i + 1].seg.sortOrder : Number.MAX_SAFE_INTEGER;
1625
+ result.set(siblings[i], { lo, hi });
1626
+ }
1627
+ }
1628
+ return result;
1629
+ }
1540
1630
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1541
1631
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1542
1632
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1543
1633
  const annotated = [];
1544
1634
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1635
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1545
1636
  for (const s of ordered) {
1546
1637
  const type = metaStr(s.seg.metadata, "type");
1547
1638
  const sec = s.seg.section;
1548
1639
  if (hasOwningApiReference(s, scopeSegs)) {
1549
1640
  continue;
1550
1641
  }
1551
- if (type === "tabRoot" || sec === "" && type !== "section") {
1642
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1643
+ continue;
1644
+ }
1645
+ if (type === "tabRoot" || sec === "" && !STRUCTURAL_SEGMENT_TYPES.has(type ?? "")) {
1552
1646
  for (const r of s.nav) {
1553
1647
  const node = artifactToNode(ctx, r);
1554
1648
  if (node != null) {
@@ -1565,24 +1659,31 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1565
1659
  }
1566
1660
  const parent = parentSectionPath(sec);
1567
1661
  const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1568
- if (isRootLevel && hasRootSection) {
1662
+ if (isRootLevel && hasRootSection && sec !== "") {
1569
1663
  continue;
1570
1664
  }
1571
1665
  if (isRootLevel) {
1572
1666
  let node;
1573
- if (type === "apiReference" || type === "apiPackage") {
1667
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1574
1668
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1575
1669
  } else if (type === "changelog") {
1576
1670
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1577
1671
  } else {
1672
+ const bounds = siblingBoundaries.get(s);
1673
+ const ownedSegs = bounds != null ? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi) : scopeSegs;
1578
1674
  node = sectionNode(
1579
1675
  ctx,
1580
1676
  s,
1581
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1677
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1582
1678
  scopePrefix
1583
1679
  );
1584
1680
  }
1585
- annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1681
+ const isSharedSection = siblingBoundaries.size > 0 && scopePrefix !== "" && sec !== "" && !sec.startsWith(scopePrefix);
1682
+ annotated.push({
1683
+ node,
1684
+ pos: isSharedSection ? void 0 : metaNum(s.seg.metadata, "childIndex"),
1685
+ isLeaf: false
1686
+ });
1586
1687
  }
1587
1688
  }
1588
1689
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1634,13 +1735,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1634
1735
  };
1635
1736
  }
1636
1737
  function buildFullRootFromSegments(options) {
1637
- const { basePath, title, segments, navBySegment } = options;
1738
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1638
1739
  const ctx = createBuildContext(basePath);
1639
1740
  const scoped = segments.filter((seg) => {
1640
1741
  const t = metaStr(seg.metadata, "type");
1641
- return t !== "files" && t !== "redirects";
1742
+ return !INFRA_SEGMENT_TYPES.has(t ?? "");
1642
1743
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1643
- const rootSlug = asSlug(basePath);
1744
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1644
1745
  const scopesByKey = /* @__PURE__ */ new Map();
1645
1746
  for (const s of scoped) {
1646
1747
  const key = scopeKey(s.seg);
@@ -1653,9 +1754,9 @@ function buildFullRootFromSegments(options) {
1653
1754
  const tabs = uniqueDetails(scoped, "tab");
1654
1755
  let child;
1655
1756
  if (products.length > 0) {
1656
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1757
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1657
1758
  } else if (versions.length > 0) {
1658
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1759
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1659
1760
  } else {
1660
1761
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1661
1762
  }
@@ -1666,6 +1767,24 @@ function buildFullRootFromSegments(options) {
1666
1767
  } else if (child.type === "versioned") {
1667
1768
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1668
1769
  rootPointsTo = defaultVersion?.pointsTo;
1770
+ } else if (child.type === "unversioned") {
1771
+ if (tabs.length > 0) {
1772
+ const firstTab = tabs[0];
1773
+ const pt = firstTab != null ? metaStr(firstTab.metadata, "pointsTo") : void 0;
1774
+ rootPointsTo = pt != null ? pointsToSlug(pt) : void 0;
1775
+ } else {
1776
+ const sorted = [...scoped].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1777
+ for (const s of sorted) {
1778
+ if (s.seg.hidden) {
1779
+ continue;
1780
+ }
1781
+ const pt = metaStr(s.seg.metadata, "pointsTo");
1782
+ if (pt != null) {
1783
+ rootPointsTo = pointsToSlug(pt);
1784
+ break;
1785
+ }
1786
+ }
1787
+ }
1669
1788
  }
1670
1789
  const root = {
1671
1790
  type: "root",
@@ -1678,21 +1797,22 @@ function buildFullRootFromSegments(options) {
1678
1797
  return root;
1679
1798
  }
1680
1799
  function uniqueDetails(scoped, dim) {
1681
- const bySlug = /* @__PURE__ */ new Map();
1800
+ const byKey = /* @__PURE__ */ new Map();
1682
1801
  for (const s of scoped) {
1683
1802
  const d = s.seg[dim];
1684
1803
  if (d == null) {
1685
1804
  continue;
1686
1805
  }
1687
1806
  const slug = detailSlug(d);
1688
- const existing = bySlug.get(slug);
1807
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1808
+ const existing = byKey.get(key);
1689
1809
  if (existing == null) {
1690
- bySlug.set(slug, d);
1810
+ byKey.set(key, d);
1691
1811
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1692
- bySlug.set(slug, d);
1812
+ byKey.set(key, d);
1693
1813
  }
1694
1814
  }
1695
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1815
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1696
1816
  }
1697
1817
  function scopeSlugPrefix(rootSlug, ...details) {
1698
1818
  const parts = [rootSlug];
@@ -1743,20 +1863,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1743
1863
  if (variants.length <= 1) {
1744
1864
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1745
1865
  }
1866
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1746
1867
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1868
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1747
1869
  const first = scopeSegs[0];
1748
1870
  return {
1749
1871
  type: "sidebarRoot",
1750
1872
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1751
1873
  collapsed: void 0,
1752
- children: [variantedNode]
1874
+ children: [...sharedChildren, variantedNode]
1753
1875
  };
1754
1876
  }
1755
1877
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1756
1878
  if (!tabsPresent) {
1757
1879
  const variants = uniqueDetails(scopeSegs, "variant");
1758
1880
  if (variants.length > 1) {
1759
- return buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1881
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1882
+ const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1883
+ if (sharedSegs.length > 0) {
1884
+ const sharedChildren = buildSidebarRootChildren(ctx, sharedSegs, scopePrefix);
1885
+ const first2 = scopeSegs[0];
1886
+ return {
1887
+ type: "sidebarRoot",
1888
+ id: ctx.nodeId(`sidebar:${first2 != null ? scopeKey(first2.seg) : "root"}`),
1889
+ collapsed: void 0,
1890
+ children: [...sharedChildren, variantedNode]
1891
+ };
1892
+ }
1893
+ return variantedNode;
1760
1894
  }
1761
1895
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1762
1896
  }
@@ -1782,7 +1916,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1782
1916
  const tabSegs2 = scopeSegs.filter((s) => s.seg.tab?.id === tab.id);
1783
1917
  const changelogSeg = tabSegs2.find((s) => metaStr(s.seg.metadata, "type") === "changelog");
1784
1918
  if (changelogSeg != null) {
1785
- return changelogNode(ctx, changelogSeg, scopePrefix);
1919
+ return changelogNode(ctx, changelogSeg, tabSlug);
1786
1920
  }
1787
1921
  return {
1788
1922
  type: "changelog",
@@ -1836,16 +1970,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1836
1970
  type: "unversioned",
1837
1971
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1838
1972
  collapsed: void 0,
1839
- landingPage: void 0,
1973
+ landingPage: buildLandingPage(ctx, scopeSegs),
1840
1974
  // The enclosing scope prefix (product slug, or rootSlug at the top
1841
1975
  // level) roots structural sections so they share the scope's slug
1842
1976
  // namespace.
1843
1977
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1844
1978
  };
1845
1979
  }
1846
- function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1980
+ function mergeSharedSections(defaultSegs, allScoped, defaultVersion, versionSlugs) {
1981
+ const defaultTabsByName = /* @__PURE__ */ new Map();
1982
+ for (const s of defaultSegs) {
1983
+ if (s.seg.tab != null) {
1984
+ const tabName = s.seg.tab.displayName;
1985
+ if (!defaultTabsByName.has(tabName)) {
1986
+ defaultTabsByName.set(tabName, s.seg.tab);
1987
+ }
1988
+ }
1989
+ }
1990
+ const existingSections = new Set(
1991
+ defaultSegs.filter((s) => metaStr(s.seg.metadata, "type") === "section").map((s) => s.seg.section)
1992
+ );
1993
+ const maxSortOrder = defaultSegs.reduce((max, s) => Math.max(max, s.seg.sortOrder), 0);
1994
+ let nextSortOrder = maxSortOrder + 1;
1995
+ const merged = [...defaultSegs];
1996
+ for (const s of allScoped) {
1997
+ if (s.seg.version?.id === defaultVersion.id) {
1998
+ continue;
1999
+ }
2000
+ const type = metaStr(s.seg.metadata, "type");
2001
+ if (type !== "section") {
2002
+ continue;
2003
+ }
2004
+ const sectionPath = s.seg.section;
2005
+ if (versionSlugs.some((vs) => sectionPath === vs || sectionPath.startsWith(vs + "/"))) {
2006
+ continue;
2007
+ }
2008
+ if (existingSections.has(sectionPath)) {
2009
+ continue;
2010
+ }
2011
+ const sourceTabName = s.seg.tab?.displayName ?? "";
2012
+ const targetTab = defaultTabsByName.get(sourceTabName);
2013
+ if (targetTab == null) {
2014
+ continue;
2015
+ }
2016
+ const metadata = s.seg.metadata != null ? { ...s.seg.metadata, childIndex: void 0 } : s.seg.metadata;
2017
+ merged.push({
2018
+ seg: {
2019
+ ...s.seg,
2020
+ tab: targetTab,
2021
+ version: defaultVersion,
2022
+ sortOrder: nextSortOrder++,
2023
+ metadata
2024
+ },
2025
+ nav: s.nav
2026
+ });
2027
+ existingSections.add(sectionPath);
2028
+ }
2029
+ return merged;
2030
+ }
2031
+ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix, skipSharedSectionMerge) {
2032
+ const versionSlugs = versions.map((v) => detailSlug(v)).filter((s) => s !== "");
1847
2033
  const children = versions.map((version) => {
1848
- const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2034
+ let versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2035
+ if (detailIsDefault(version) && !skipSharedSectionMerge) {
2036
+ versionSegs = mergeSharedSections(versionSegs, scoped, version, versionSlugs);
2037
+ }
1849
2038
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1850
2039
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1851
2040
  const versionSegment = detailSlug(version);
@@ -1863,7 +2052,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1863
2052
  default: detailIsDefault(version),
1864
2053
  versionId: VersionId(version.id),
1865
2054
  availability: void 0,
1866
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2055
+ landingPage: buildLandingPage(ctx, versionSegs),
1867
2056
  announcement: void 0,
1868
2057
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1869
2058
  // The version's full slug roots structural sections so the whole
@@ -1944,34 +2133,41 @@ function crossVersionDedupKeys(node, parents) {
1944
2133
  keys.push([...parentTitles, node.title].join("###"));
1945
2134
  return keys;
1946
2135
  }
1947
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1948
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1949
- if (tablessSegs.length === 0) {
2136
+ function routeToLandingPage(ctx, route) {
2137
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1950
2138
  return void 0;
1951
2139
  }
1952
- for (const s of tablessSegs) {
1953
- for (const r of s.nav) {
1954
- if (r.type === "markdown" && r.fullPath != null) {
1955
- const md = r.metadata;
1956
- const pageId = metaStr(md, "pageId") ?? "";
1957
- const slug = ctx.contentSlug(r.fullPath);
1958
- return {
1959
- type: "landingPage",
1960
- ...withMetadataDefaults({
1961
- id: ctx.nodeId(`landing:${slug}`),
1962
- title: metaStr(md, "title") ?? "",
1963
- slug,
1964
- icon: metaStr(md, "icon"),
1965
- hidden: r.hidden,
1966
- viewers: toViewers(metaStrArr(md, "viewers"))
1967
- }),
1968
- pageId: PageId(pageId),
1969
- noindex: metaBool(md, "noindex")
1970
- };
1971
- }
1972
- }
2140
+ const md = route.metadata;
2141
+ const pageId = metaStr(md, "pageId");
2142
+ if (pageId == null) {
2143
+ return void 0;
1973
2144
  }
1974
- return void 0;
2145
+ const slug = ctx.contentSlug(route.fullPath);
2146
+ return {
2147
+ type: "landingPage",
2148
+ ...withMetadataDefaults({
2149
+ id: ctx.nodeId(`landing:${slug}`),
2150
+ title: metaStr(md, "title") ?? "",
2151
+ slug,
2152
+ icon: metaStr(md, "icon"),
2153
+ hidden: route.hidden,
2154
+ authed: metaBool(md, "authed"),
2155
+ viewers: toViewers(metaStrArr(md, "viewers")),
2156
+ orphaned: metaBool(md, "orphaned"),
2157
+ featureFlags: metaFeatureFlags(md)
2158
+ }),
2159
+ pageId: PageId(pageId),
2160
+ noindex: metaBool(md, "noindex")
2161
+ };
2162
+ }
2163
+ function buildLandingPage(ctx, scopeSegs) {
2164
+ const landingSegment = scopeSegs.find(
2165
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2166
+ );
2167
+ return routeToLandingPage(
2168
+ ctx,
2169
+ landingSegment?.nav.find((route) => route.type === "markdown")
2170
+ );
1975
2171
  }
1976
2172
  function markCrossVersionCanonicalSlugs(versionNodes) {
1977
2173
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2006,13 +2202,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2006
2202
  });
2007
2203
  }
2008
2204
  }
2009
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2205
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2010
2206
  const children = products.map((product) => {
2011
2207
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2012
2208
  const versions = uniqueDetails(productSegs, "version");
2013
2209
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2014
2210
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2015
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2211
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix, skipSharedSectionMerge) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2016
2212
  const node = {
2017
2213
  type: "product",
2018
2214
  ...withMetadataDefaults({
@@ -2042,7 +2238,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2042
2238
  type: "productgroup",
2043
2239
  id: ctx.nodeId("productgroup"),
2044
2240
  collapsed: void 0,
2045
- landingPage: void 0,
2241
+ landingPage: buildLandingPage(
2242
+ ctx,
2243
+ scoped.filter((s) => s.seg.product == null)
2244
+ ),
2046
2245
  children
2047
2246
  };
2048
2247
  }