@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
@@ -846,6 +846,14 @@ function traverseDF(node, visit) {
846
846
  }
847
847
 
848
848
  // src/navigation/ledger-root-builder.ts
849
+ var STRUCTURAL_SEGMENT_TYPES = /* @__PURE__ */ new Set([
850
+ "section",
851
+ "apiReference",
852
+ "apiPackage",
853
+ "changelog"
854
+ ]);
855
+ var API_NODE_SEGMENT_TYPES = /* @__PURE__ */ new Set(["apiReference", "apiPackage"]);
856
+ var INFRA_SEGMENT_TYPES = /* @__PURE__ */ new Set(["files", "redirects"]);
849
857
  function createBuildContext(basePath) {
850
858
  const seen = /* @__PURE__ */ new Map();
851
859
  const basePrefix = basePath.replace(/^\/+|\/+$/g, "");
@@ -923,7 +931,7 @@ function toViewers(viewers) {
923
931
  return viewers.map((v) => RoleId(v));
924
932
  }
925
933
  function mergeVariantViewers(seg) {
926
- const segViewers = seg.metadata.type === "section" || seg.metadata.type === "apiReference" || seg.metadata.type === "apiPackage" || seg.metadata.type === "changelog" ? seg.metadata.viewers : void 0;
934
+ const segViewers = STRUCTURAL_SEGMENT_TYPES.has(seg.metadata.type) ? seg.metadata.viewers : void 0;
927
935
  const variantViewers = seg.variant?.viewers;
928
936
  if ((segViewers == null || segViewers.length === 0) && (variantViewers == null || variantViewers.length === 0)) {
929
937
  return void 0;
@@ -1123,6 +1131,63 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1123
1131
  }
1124
1132
  return void 0;
1125
1133
  }
1134
+ function apiLeafPositionKey(node) {
1135
+ switch (node.type) {
1136
+ case "endpoint":
1137
+ return `endpoint:${node.endpointId}`;
1138
+ case "webhook":
1139
+ return `webhook:${node.webhookId}`;
1140
+ case "webSocket":
1141
+ return `webSocket:${node.webSocketId}`;
1142
+ case "grpc":
1143
+ return `grpc:${node.grpcId}`;
1144
+ case "graphql":
1145
+ return `graphql:${node.graphqlOperationId}`;
1146
+ }
1147
+ }
1148
+ function apiChildPositionKey(node) {
1149
+ switch (node.type) {
1150
+ case "endpoint":
1151
+ case "webhook":
1152
+ case "webSocket":
1153
+ case "grpc":
1154
+ case "graphql":
1155
+ return apiLeafPositionKey(node);
1156
+ default:
1157
+ return void 0;
1158
+ }
1159
+ }
1160
+ function positionedApiLeafChildren(ctx, nav, apiDefinitionId) {
1161
+ const rawLeafNodes = [];
1162
+ const leafPositions = /* @__PURE__ */ new Map();
1163
+ const nonApiLeafNodes = [];
1164
+ for (let i = 0; i < nav.length; i++) {
1165
+ const route = nav[i];
1166
+ const pos = route.displaySortOrder ?? i;
1167
+ const apiLeaf = apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId);
1168
+ if (apiLeaf != null) {
1169
+ rawLeafNodes.push(apiLeaf);
1170
+ const key = apiLeafPositionKey(apiLeaf);
1171
+ leafPositions.set(key, Math.min(leafPositions.get(key) ?? pos, pos));
1172
+ continue;
1173
+ }
1174
+ const node = artifactToNode(ctx, route);
1175
+ if (node?.type === "page" || node?.type === "link") {
1176
+ nonApiLeafNodes.push({ node, pos });
1177
+ }
1178
+ }
1179
+ const apiLeafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1180
+ const positionedApiLeafNodes = apiLeafNodes.map((node, index) => {
1181
+ if (node.type === "endpointPair") {
1182
+ const streamPos = leafPositions.get(apiLeafPositionKey(node.stream)) ?? index;
1183
+ const nonStreamPos = leafPositions.get(apiLeafPositionKey(node.nonStream)) ?? index;
1184
+ return { node, pos: Math.min(streamPos, nonStreamPos) };
1185
+ }
1186
+ const key = apiChildPositionKey(node);
1187
+ return { node, pos: key != null ? leafPositions.get(key) ?? index : index };
1188
+ });
1189
+ return [...positionedApiLeafNodes, ...nonApiLeafNodes];
1190
+ }
1126
1191
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1127
1192
  const ctx = createBuildContext(basePath);
1128
1193
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1235,7 +1300,7 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1235
1300
  collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1236
1301
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1237
1302
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1238
- collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1303
+ collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1239
1304
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1240
1305
  availability: metaStr(seg.metadata, "availability"),
1241
1306
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1260,8 +1325,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1260
1325
  }
1261
1326
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1262
1327
  const { seg, nav } = scoped;
1263
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1264
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1328
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1265
1329
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1266
1330
  const packageNodes = childPackages.map((child) => ({
1267
1331
  node: apiPackageChildNode(
@@ -1275,18 +1339,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1275
1339
  }));
1276
1340
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1277
1341
  if (!hasChildIndex) {
1278
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1279
- }
1280
- const leafPositions = [];
1281
- for (const route of nav) {
1282
- if (route.displaySortOrder != null) {
1283
- leafPositions.push(route.displaySortOrder);
1284
- }
1342
+ return [...leafNodes, ...packageNodes.map((p) => ({ node: p.node, pos: Number.MAX_SAFE_INTEGER }))].sort((a, b) => a.pos - b.pos).map((p) => p.node);
1285
1343
  }
1286
1344
  const positioned = [];
1287
- for (let i = 0; i < leafNodes.length; i++) {
1288
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1289
- }
1345
+ positioned.push(...leafNodes);
1290
1346
  for (const p of packageNodes) {
1291
1347
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1292
1348
  }
@@ -1471,7 +1527,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1471
1527
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1472
1528
  noindex: metaBool(r.metadata, "noindex"),
1473
1529
  date: dateStr ?? "",
1474
- tags: void 0
1530
+ tags: metaStrArr(r.metadata, "tags")
1475
1531
  };
1476
1532
  let months = byYear.get(year);
1477
1533
  if (months == null) {
@@ -1563,7 +1619,7 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1563
1619
  const type = metaStr(s.seg.metadata, "type");
1564
1620
  const childIndex = metaNum(s.seg.metadata, "childIndex");
1565
1621
  let node;
1566
- if (type === "apiReference" || type === "apiPackage") {
1622
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1567
1623
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1568
1624
  } else if (type === "changelog") {
1569
1625
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
@@ -1578,18 +1634,56 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1578
1634
  return { node, childIndex };
1579
1635
  });
1580
1636
  }
1637
+ function computeSiblingSortBoundaries(ordered) {
1638
+ const result = /* @__PURE__ */ new Map();
1639
+ const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1640
+ const rootSections = [];
1641
+ for (const s of ordered) {
1642
+ const type = metaStr(s.seg.metadata, "type");
1643
+ const sec = s.seg.section;
1644
+ if (type !== "section" || sec === "") {
1645
+ continue;
1646
+ }
1647
+ const parent = parentSectionPath(sec);
1648
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1649
+ if (isRootLevel) {
1650
+ rootSections.push(s);
1651
+ }
1652
+ }
1653
+ const byPath = /* @__PURE__ */ new Map();
1654
+ for (const s of rootSections) {
1655
+ const group = byPath.get(s.seg.section) ?? [];
1656
+ group.push(s);
1657
+ byPath.set(s.seg.section, group);
1658
+ }
1659
+ for (const [, siblings] of byPath) {
1660
+ if (siblings.length <= 1) {
1661
+ continue;
1662
+ }
1663
+ for (let i = 0; i < siblings.length; i++) {
1664
+ const lo = siblings[i].seg.sortOrder;
1665
+ const hi = i + 1 < siblings.length ? siblings[i + 1].seg.sortOrder : Number.MAX_SAFE_INTEGER;
1666
+ result.set(siblings[i], { lo, hi });
1667
+ }
1668
+ }
1669
+ return result;
1670
+ }
1581
1671
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1582
1672
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1583
1673
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1584
1674
  const annotated = [];
1585
1675
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1676
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1586
1677
  for (const s of ordered) {
1587
1678
  const type = metaStr(s.seg.metadata, "type");
1588
1679
  const sec = s.seg.section;
1589
1680
  if (hasOwningApiReference(s, scopeSegs)) {
1590
1681
  continue;
1591
1682
  }
1592
- if (type === "tabRoot" || sec === "" && type !== "section") {
1683
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1684
+ continue;
1685
+ }
1686
+ if (type === "tabRoot" || sec === "" && !STRUCTURAL_SEGMENT_TYPES.has(type ?? "")) {
1593
1687
  for (const r of s.nav) {
1594
1688
  const node = artifactToNode(ctx, r);
1595
1689
  if (node != null) {
@@ -1606,24 +1700,31 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1606
1700
  }
1607
1701
  const parent = parentSectionPath(sec);
1608
1702
  const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1609
- if (isRootLevel && hasRootSection) {
1703
+ if (isRootLevel && hasRootSection && sec !== "") {
1610
1704
  continue;
1611
1705
  }
1612
1706
  if (isRootLevel) {
1613
1707
  let node;
1614
- if (type === "apiReference" || type === "apiPackage") {
1708
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1615
1709
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1616
1710
  } else if (type === "changelog") {
1617
1711
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1618
1712
  } else {
1713
+ const bounds = siblingBoundaries.get(s);
1714
+ const ownedSegs = bounds != null ? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi) : scopeSegs;
1619
1715
  node = sectionNode(
1620
1716
  ctx,
1621
1717
  s,
1622
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1718
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1623
1719
  scopePrefix
1624
1720
  );
1625
1721
  }
1626
- annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1722
+ const isSharedSection = siblingBoundaries.size > 0 && scopePrefix !== "" && sec !== "" && !sec.startsWith(scopePrefix);
1723
+ annotated.push({
1724
+ node,
1725
+ pos: isSharedSection ? void 0 : metaNum(s.seg.metadata, "childIndex"),
1726
+ isLeaf: false
1727
+ });
1627
1728
  }
1628
1729
  }
1629
1730
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1675,13 +1776,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1675
1776
  };
1676
1777
  }
1677
1778
  function buildFullRootFromSegments(options) {
1678
- const { basePath, title, segments, navBySegment } = options;
1779
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1679
1780
  const ctx = createBuildContext(basePath);
1680
1781
  const scoped = segments.filter((seg) => {
1681
1782
  const t = metaStr(seg.metadata, "type");
1682
- return t !== "files" && t !== "redirects";
1783
+ return !INFRA_SEGMENT_TYPES.has(t ?? "");
1683
1784
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1684
- const rootSlug = asSlug(basePath);
1785
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1685
1786
  const scopesByKey = /* @__PURE__ */ new Map();
1686
1787
  for (const s of scoped) {
1687
1788
  const key = scopeKey(s.seg);
@@ -1694,9 +1795,9 @@ function buildFullRootFromSegments(options) {
1694
1795
  const tabs = uniqueDetails(scoped, "tab");
1695
1796
  let child;
1696
1797
  if (products.length > 0) {
1697
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1798
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1698
1799
  } else if (versions.length > 0) {
1699
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1800
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1700
1801
  } else {
1701
1802
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1702
1803
  }
@@ -1707,6 +1808,24 @@ function buildFullRootFromSegments(options) {
1707
1808
  } else if (child.type === "versioned") {
1708
1809
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1709
1810
  rootPointsTo = defaultVersion?.pointsTo;
1811
+ } else if (child.type === "unversioned") {
1812
+ if (tabs.length > 0) {
1813
+ const firstTab = tabs[0];
1814
+ const pt = firstTab != null ? metaStr(firstTab.metadata, "pointsTo") : void 0;
1815
+ rootPointsTo = pt != null ? pointsToSlug(pt) : void 0;
1816
+ } else {
1817
+ const sorted = [...scoped].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1818
+ for (const s of sorted) {
1819
+ if (s.seg.hidden) {
1820
+ continue;
1821
+ }
1822
+ const pt = metaStr(s.seg.metadata, "pointsTo");
1823
+ if (pt != null) {
1824
+ rootPointsTo = pointsToSlug(pt);
1825
+ break;
1826
+ }
1827
+ }
1828
+ }
1710
1829
  }
1711
1830
  const root = {
1712
1831
  type: "root",
@@ -1719,21 +1838,22 @@ function buildFullRootFromSegments(options) {
1719
1838
  return root;
1720
1839
  }
1721
1840
  function uniqueDetails(scoped, dim) {
1722
- const bySlug = /* @__PURE__ */ new Map();
1841
+ const byKey = /* @__PURE__ */ new Map();
1723
1842
  for (const s of scoped) {
1724
1843
  const d = s.seg[dim];
1725
1844
  if (d == null) {
1726
1845
  continue;
1727
1846
  }
1728
1847
  const slug = detailSlug(d);
1729
- const existing = bySlug.get(slug);
1848
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1849
+ const existing = byKey.get(key);
1730
1850
  if (existing == null) {
1731
- bySlug.set(slug, d);
1851
+ byKey.set(key, d);
1732
1852
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1733
- bySlug.set(slug, d);
1853
+ byKey.set(key, d);
1734
1854
  }
1735
1855
  }
1736
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1856
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1737
1857
  }
1738
1858
  function scopeSlugPrefix(rootSlug, ...details) {
1739
1859
  const parts = [rootSlug];
@@ -1784,20 +1904,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1784
1904
  if (variants.length <= 1) {
1785
1905
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1786
1906
  }
1907
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1787
1908
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1909
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1788
1910
  const first = scopeSegs[0];
1789
1911
  return {
1790
1912
  type: "sidebarRoot",
1791
1913
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1792
1914
  collapsed: void 0,
1793
- children: [variantedNode]
1915
+ children: [...sharedChildren, variantedNode]
1794
1916
  };
1795
1917
  }
1796
1918
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1797
1919
  if (!tabsPresent) {
1798
1920
  const variants = uniqueDetails(scopeSegs, "variant");
1799
1921
  if (variants.length > 1) {
1800
- return buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1922
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1923
+ const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1924
+ if (sharedSegs.length > 0) {
1925
+ const sharedChildren = buildSidebarRootChildren(ctx, sharedSegs, scopePrefix);
1926
+ const first2 = scopeSegs[0];
1927
+ return {
1928
+ type: "sidebarRoot",
1929
+ id: ctx.nodeId(`sidebar:${first2 != null ? scopeKey(first2.seg) : "root"}`),
1930
+ collapsed: void 0,
1931
+ children: [...sharedChildren, variantedNode]
1932
+ };
1933
+ }
1934
+ return variantedNode;
1801
1935
  }
1802
1936
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1803
1937
  }
@@ -1823,7 +1957,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1823
1957
  const tabSegs2 = scopeSegs.filter((s) => s.seg.tab?.id === tab.id);
1824
1958
  const changelogSeg = tabSegs2.find((s) => metaStr(s.seg.metadata, "type") === "changelog");
1825
1959
  if (changelogSeg != null) {
1826
- return changelogNode(ctx, changelogSeg, scopePrefix);
1960
+ return changelogNode(ctx, changelogSeg, tabSlug);
1827
1961
  }
1828
1962
  return {
1829
1963
  type: "changelog",
@@ -1877,16 +2011,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1877
2011
  type: "unversioned",
1878
2012
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1879
2013
  collapsed: void 0,
1880
- landingPage: void 0,
2014
+ landingPage: buildLandingPage(ctx, scopeSegs),
1881
2015
  // The enclosing scope prefix (product slug, or rootSlug at the top
1882
2016
  // level) roots structural sections so they share the scope's slug
1883
2017
  // namespace.
1884
2018
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1885
2019
  };
1886
2020
  }
1887
- function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
2021
+ function mergeSharedSections(defaultSegs, allScoped, defaultVersion, versionSlugs) {
2022
+ const defaultTabsByName = /* @__PURE__ */ new Map();
2023
+ for (const s of defaultSegs) {
2024
+ if (s.seg.tab != null) {
2025
+ const tabName = s.seg.tab.displayName;
2026
+ if (!defaultTabsByName.has(tabName)) {
2027
+ defaultTabsByName.set(tabName, s.seg.tab);
2028
+ }
2029
+ }
2030
+ }
2031
+ const existingSections = new Set(
2032
+ defaultSegs.filter((s) => metaStr(s.seg.metadata, "type") === "section").map((s) => s.seg.section)
2033
+ );
2034
+ const maxSortOrder = defaultSegs.reduce((max, s) => Math.max(max, s.seg.sortOrder), 0);
2035
+ let nextSortOrder = maxSortOrder + 1;
2036
+ const merged = [...defaultSegs];
2037
+ for (const s of allScoped) {
2038
+ if (s.seg.version?.id === defaultVersion.id) {
2039
+ continue;
2040
+ }
2041
+ const type = metaStr(s.seg.metadata, "type");
2042
+ if (type !== "section") {
2043
+ continue;
2044
+ }
2045
+ const sectionPath = s.seg.section;
2046
+ if (versionSlugs.some((vs) => sectionPath === vs || sectionPath.startsWith(vs + "/"))) {
2047
+ continue;
2048
+ }
2049
+ if (existingSections.has(sectionPath)) {
2050
+ continue;
2051
+ }
2052
+ const sourceTabName = s.seg.tab?.displayName ?? "";
2053
+ const targetTab = defaultTabsByName.get(sourceTabName);
2054
+ if (targetTab == null) {
2055
+ continue;
2056
+ }
2057
+ const metadata = s.seg.metadata != null ? { ...s.seg.metadata, childIndex: void 0 } : s.seg.metadata;
2058
+ merged.push({
2059
+ seg: {
2060
+ ...s.seg,
2061
+ tab: targetTab,
2062
+ version: defaultVersion,
2063
+ sortOrder: nextSortOrder++,
2064
+ metadata
2065
+ },
2066
+ nav: s.nav
2067
+ });
2068
+ existingSections.add(sectionPath);
2069
+ }
2070
+ return merged;
2071
+ }
2072
+ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix, skipSharedSectionMerge) {
2073
+ const versionSlugs = versions.map((v) => detailSlug(v)).filter((s) => s !== "");
1888
2074
  const children = versions.map((version) => {
1889
- const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2075
+ let versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2076
+ if (detailIsDefault(version) && !skipSharedSectionMerge) {
2077
+ versionSegs = mergeSharedSections(versionSegs, scoped, version, versionSlugs);
2078
+ }
1890
2079
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1891
2080
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1892
2081
  const versionSegment = detailSlug(version);
@@ -1904,7 +2093,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1904
2093
  default: detailIsDefault(version),
1905
2094
  versionId: VersionId(version.id),
1906
2095
  availability: void 0,
1907
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2096
+ landingPage: buildLandingPage(ctx, versionSegs),
1908
2097
  announcement: void 0,
1909
2098
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1910
2099
  // The version's full slug roots structural sections so the whole
@@ -1985,34 +2174,41 @@ function crossVersionDedupKeys(node, parents) {
1985
2174
  keys.push([...parentTitles, node.title].join("###"));
1986
2175
  return keys;
1987
2176
  }
1988
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1989
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1990
- if (tablessSegs.length === 0) {
2177
+ function routeToLandingPage(ctx, route) {
2178
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1991
2179
  return void 0;
1992
2180
  }
1993
- for (const s of tablessSegs) {
1994
- for (const r of s.nav) {
1995
- if (r.type === "markdown" && r.fullPath != null) {
1996
- const md = r.metadata;
1997
- const pageId = metaStr(md, "pageId") ?? "";
1998
- const slug = ctx.contentSlug(r.fullPath);
1999
- return {
2000
- type: "landingPage",
2001
- ...withMetadataDefaults({
2002
- id: ctx.nodeId(`landing:${slug}`),
2003
- title: metaStr(md, "title") ?? "",
2004
- slug,
2005
- icon: metaStr(md, "icon"),
2006
- hidden: r.hidden,
2007
- viewers: toViewers(metaStrArr(md, "viewers"))
2008
- }),
2009
- pageId: PageId(pageId),
2010
- noindex: metaBool(md, "noindex")
2011
- };
2012
- }
2013
- }
2181
+ const md = route.metadata;
2182
+ const pageId = metaStr(md, "pageId");
2183
+ if (pageId == null) {
2184
+ return void 0;
2014
2185
  }
2015
- return void 0;
2186
+ const slug = ctx.contentSlug(route.fullPath);
2187
+ return {
2188
+ type: "landingPage",
2189
+ ...withMetadataDefaults({
2190
+ id: ctx.nodeId(`landing:${slug}`),
2191
+ title: metaStr(md, "title") ?? "",
2192
+ slug,
2193
+ icon: metaStr(md, "icon"),
2194
+ hidden: route.hidden,
2195
+ authed: metaBool(md, "authed"),
2196
+ viewers: toViewers(metaStrArr(md, "viewers")),
2197
+ orphaned: metaBool(md, "orphaned"),
2198
+ featureFlags: metaFeatureFlags(md)
2199
+ }),
2200
+ pageId: PageId(pageId),
2201
+ noindex: metaBool(md, "noindex")
2202
+ };
2203
+ }
2204
+ function buildLandingPage(ctx, scopeSegs) {
2205
+ const landingSegment = scopeSegs.find(
2206
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2207
+ );
2208
+ return routeToLandingPage(
2209
+ ctx,
2210
+ landingSegment?.nav.find((route) => route.type === "markdown")
2211
+ );
2016
2212
  }
2017
2213
  function markCrossVersionCanonicalSlugs(versionNodes) {
2018
2214
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2047,13 +2243,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2047
2243
  });
2048
2244
  }
2049
2245
  }
2050
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2246
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2051
2247
  const children = products.map((product) => {
2052
2248
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2053
2249
  const versions = uniqueDetails(productSegs, "version");
2054
2250
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2055
2251
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2056
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2252
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix, skipSharedSectionMerge) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2057
2253
  const node = {
2058
2254
  type: "product",
2059
2255
  ...withMetadataDefaults({
@@ -2083,7 +2279,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2083
2279
  type: "productgroup",
2084
2280
  id: ctx.nodeId("productgroup"),
2085
2281
  collapsed: void 0,
2086
- landingPage: void 0,
2282
+ landingPage: buildLandingPage(
2283
+ ctx,
2284
+ scoped.filter((s) => s.seg.product == null)
2285
+ ),
2087
2286
  children
2088
2287
  };
2089
2288
  }