@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
@@ -1123,6 +1123,63 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1123
1123
  }
1124
1124
  return void 0;
1125
1125
  }
1126
+ function apiLeafPositionKey(node) {
1127
+ switch (node.type) {
1128
+ case "endpoint":
1129
+ return `endpoint:${node.endpointId}`;
1130
+ case "webhook":
1131
+ return `webhook:${node.webhookId}`;
1132
+ case "webSocket":
1133
+ return `webSocket:${node.webSocketId}`;
1134
+ case "grpc":
1135
+ return `grpc:${node.grpcId}`;
1136
+ case "graphql":
1137
+ return `graphql:${node.graphqlOperationId}`;
1138
+ }
1139
+ }
1140
+ function apiChildPositionKey(node) {
1141
+ switch (node.type) {
1142
+ case "endpoint":
1143
+ case "webhook":
1144
+ case "webSocket":
1145
+ case "grpc":
1146
+ case "graphql":
1147
+ return apiLeafPositionKey(node);
1148
+ default:
1149
+ return void 0;
1150
+ }
1151
+ }
1152
+ function positionedApiLeafChildren(ctx, nav, apiDefinitionId) {
1153
+ const rawLeafNodes = [];
1154
+ const leafPositions = /* @__PURE__ */ new Map();
1155
+ const nonApiLeafNodes = [];
1156
+ for (let i = 0; i < nav.length; i++) {
1157
+ const route = nav[i];
1158
+ const pos = route.displaySortOrder ?? i;
1159
+ const apiLeaf = apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId);
1160
+ if (apiLeaf != null) {
1161
+ rawLeafNodes.push(apiLeaf);
1162
+ const key = apiLeafPositionKey(apiLeaf);
1163
+ leafPositions.set(key, Math.min(leafPositions.get(key) ?? pos, pos));
1164
+ continue;
1165
+ }
1166
+ const node = artifactToNode(ctx, route);
1167
+ if (node?.type === "page" || node?.type === "link") {
1168
+ nonApiLeafNodes.push({ node, pos });
1169
+ }
1170
+ }
1171
+ const apiLeafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1172
+ const positionedApiLeafNodes = apiLeafNodes.map((node, index) => {
1173
+ if (node.type === "endpointPair") {
1174
+ const streamPos = leafPositions.get(apiLeafPositionKey(node.stream)) ?? index;
1175
+ const nonStreamPos = leafPositions.get(apiLeafPositionKey(node.nonStream)) ?? index;
1176
+ return { node, pos: Math.min(streamPos, nonStreamPos) };
1177
+ }
1178
+ const key = apiChildPositionKey(node);
1179
+ return { node, pos: key != null ? leafPositions.get(key) ?? index : index };
1180
+ });
1181
+ return [...positionedApiLeafNodes, ...nonApiLeafNodes];
1182
+ }
1126
1183
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1127
1184
  const ctx = createBuildContext(basePath);
1128
1185
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1232,12 +1289,10 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1232
1289
  return {
1233
1290
  type: "section",
1234
1291
  ...defaults,
1235
- // V2 convention: collapsed:false in docs.yml maps to "open-by-default"
1236
- // so getInitiallyOpenByDefaultNodes picks it up and the UI starts open.
1237
- collapsed: metaCollapsed(seg.metadata) === false ? "open-by-default" : metaCollapsed(seg.metadata) ?? defaults.collapsed,
1292
+ collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1238
1293
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1239
1294
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1240
- collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1295
+ collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1241
1296
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1242
1297
  availability: metaStr(seg.metadata, "availability"),
1243
1298
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1262,8 +1317,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1262
1317
  }
1263
1318
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1264
1319
  const { seg, nav } = scoped;
1265
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1266
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1320
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1267
1321
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1268
1322
  const packageNodes = childPackages.map((child) => ({
1269
1323
  node: apiPackageChildNode(
@@ -1277,18 +1331,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1277
1331
  }));
1278
1332
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1279
1333
  if (!hasChildIndex) {
1280
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1281
- }
1282
- const leafPositions = [];
1283
- for (const route of nav) {
1284
- if (route.displaySortOrder != null) {
1285
- leafPositions.push(route.displaySortOrder);
1286
- }
1334
+ return [...leafNodes, ...packageNodes.map((p) => ({ node: p.node, pos: Number.MAX_SAFE_INTEGER }))].sort((a, b) => a.pos - b.pos).map((p) => p.node);
1287
1335
  }
1288
1336
  const positioned = [];
1289
- for (let i = 0; i < leafNodes.length; i++) {
1290
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1291
- }
1337
+ positioned.push(...leafNodes);
1292
1338
  for (const p of packageNodes) {
1293
1339
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1294
1340
  }
@@ -1473,7 +1519,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1473
1519
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1474
1520
  noindex: metaBool(r.metadata, "noindex"),
1475
1521
  date: dateStr ?? "",
1476
- tags: void 0
1522
+ tags: metaStrArr(r.metadata, "tags")
1477
1523
  };
1478
1524
  let months = byYear.get(year);
1479
1525
  if (months == null) {
@@ -1580,17 +1626,55 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1580
1626
  return { node, childIndex };
1581
1627
  });
1582
1628
  }
1629
+ function computeSiblingSortBoundaries(ordered) {
1630
+ const result = /* @__PURE__ */ new Map();
1631
+ const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1632
+ const rootSections = [];
1633
+ for (const s of ordered) {
1634
+ const type = metaStr(s.seg.metadata, "type");
1635
+ const sec = s.seg.section;
1636
+ if (type !== "section" || sec === "") {
1637
+ continue;
1638
+ }
1639
+ const parent = parentSectionPath(sec);
1640
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1641
+ if (isRootLevel) {
1642
+ rootSections.push(s);
1643
+ }
1644
+ }
1645
+ const byPath = /* @__PURE__ */ new Map();
1646
+ for (const s of rootSections) {
1647
+ const group = byPath.get(s.seg.section) ?? [];
1648
+ group.push(s);
1649
+ byPath.set(s.seg.section, group);
1650
+ }
1651
+ for (const [, siblings] of byPath) {
1652
+ if (siblings.length <= 1) {
1653
+ continue;
1654
+ }
1655
+ for (let i = 0; i < siblings.length; i++) {
1656
+ const lo = siblings[i].seg.sortOrder;
1657
+ const hi = i + 1 < siblings.length ? siblings[i + 1].seg.sortOrder : Number.MAX_SAFE_INTEGER;
1658
+ result.set(siblings[i], { lo, hi });
1659
+ }
1660
+ }
1661
+ return result;
1662
+ }
1583
1663
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1584
1664
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1585
1665
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1586
1666
  const annotated = [];
1587
1667
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1668
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1588
1669
  for (const s of ordered) {
1589
1670
  const type = metaStr(s.seg.metadata, "type");
1590
1671
  const sec = s.seg.section;
1591
1672
  if (hasOwningApiReference(s, scopeSegs)) {
1592
1673
  continue;
1593
1674
  }
1675
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1676
+ continue;
1677
+ }
1594
1678
  if (type === "tabRoot" || sec === "" && type !== "section") {
1595
1679
  for (const r of s.nav) {
1596
1680
  const node = artifactToNode(ctx, r);
@@ -1618,14 +1702,21 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1618
1702
  } else if (type === "changelog") {
1619
1703
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1620
1704
  } else {
1705
+ const bounds = siblingBoundaries.get(s);
1706
+ const ownedSegs = bounds != null ? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi) : scopeSegs;
1621
1707
  node = sectionNode(
1622
1708
  ctx,
1623
1709
  s,
1624
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1710
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1625
1711
  scopePrefix
1626
1712
  );
1627
1713
  }
1628
- annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1714
+ const isSharedSection = siblingBoundaries.size > 0 && scopePrefix !== "" && sec !== "" && !sec.startsWith(scopePrefix);
1715
+ annotated.push({
1716
+ node,
1717
+ pos: isSharedSection ? void 0 : metaNum(s.seg.metadata, "childIndex"),
1718
+ isLeaf: false
1719
+ });
1629
1720
  }
1630
1721
  }
1631
1722
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1677,13 +1768,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1677
1768
  };
1678
1769
  }
1679
1770
  function buildFullRootFromSegments(options) {
1680
- const { basePath, title, segments, navBySegment } = options;
1771
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1681
1772
  const ctx = createBuildContext(basePath);
1682
1773
  const scoped = segments.filter((seg) => {
1683
1774
  const t = metaStr(seg.metadata, "type");
1684
1775
  return t !== "files" && t !== "redirects";
1685
1776
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1686
- const rootSlug = asSlug(basePath);
1777
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1687
1778
  const scopesByKey = /* @__PURE__ */ new Map();
1688
1779
  for (const s of scoped) {
1689
1780
  const key = scopeKey(s.seg);
@@ -1696,9 +1787,9 @@ function buildFullRootFromSegments(options) {
1696
1787
  const tabs = uniqueDetails(scoped, "tab");
1697
1788
  let child;
1698
1789
  if (products.length > 0) {
1699
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1790
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1700
1791
  } else if (versions.length > 0) {
1701
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1792
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1702
1793
  } else {
1703
1794
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1704
1795
  }
@@ -1746,7 +1837,7 @@ function uniqueDetails(scoped, dim) {
1746
1837
  continue;
1747
1838
  }
1748
1839
  const slug = detailSlug(d);
1749
- const key = slug !== "" ? slug : d.id;
1840
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1750
1841
  const existing = byKey.get(key);
1751
1842
  if (existing == null) {
1752
1843
  byKey.set(key, d);
@@ -1805,20 +1896,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1805
1896
  if (variants.length <= 1) {
1806
1897
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1807
1898
  }
1899
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1808
1900
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1901
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1809
1902
  const first = scopeSegs[0];
1810
1903
  return {
1811
1904
  type: "sidebarRoot",
1812
1905
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1813
1906
  collapsed: void 0,
1814
- children: [variantedNode]
1907
+ children: [...sharedChildren, variantedNode]
1815
1908
  };
1816
1909
  }
1817
1910
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1818
1911
  if (!tabsPresent) {
1819
1912
  const variants = uniqueDetails(scopeSegs, "variant");
1820
1913
  if (variants.length > 1) {
1821
- return buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1914
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1915
+ const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1916
+ if (sharedSegs.length > 0) {
1917
+ const sharedChildren = buildSidebarRootChildren(ctx, sharedSegs, scopePrefix);
1918
+ const first2 = scopeSegs[0];
1919
+ return {
1920
+ type: "sidebarRoot",
1921
+ id: ctx.nodeId(`sidebar:${first2 != null ? scopeKey(first2.seg) : "root"}`),
1922
+ collapsed: void 0,
1923
+ children: [...sharedChildren, variantedNode]
1924
+ };
1925
+ }
1926
+ return variantedNode;
1822
1927
  }
1823
1928
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1824
1929
  }
@@ -1898,16 +2003,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1898
2003
  type: "unversioned",
1899
2004
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1900
2005
  collapsed: void 0,
1901
- landingPage: void 0,
2006
+ landingPage: buildLandingPage(ctx, scopeSegs),
1902
2007
  // The enclosing scope prefix (product slug, or rootSlug at the top
1903
2008
  // level) roots structural sections so they share the scope's slug
1904
2009
  // namespace.
1905
2010
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1906
2011
  };
1907
2012
  }
1908
- function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
2013
+ function mergeSharedSections(defaultSegs, allScoped, defaultVersion, versionSlugs) {
2014
+ const defaultTabsByName = /* @__PURE__ */ new Map();
2015
+ for (const s of defaultSegs) {
2016
+ if (s.seg.tab != null) {
2017
+ const tabName = s.seg.tab.displayName;
2018
+ if (!defaultTabsByName.has(tabName)) {
2019
+ defaultTabsByName.set(tabName, s.seg.tab);
2020
+ }
2021
+ }
2022
+ }
2023
+ const existingSections = new Set(
2024
+ defaultSegs.filter((s) => metaStr(s.seg.metadata, "type") === "section").map((s) => s.seg.section)
2025
+ );
2026
+ const maxSortOrder = defaultSegs.reduce((max, s) => Math.max(max, s.seg.sortOrder), 0);
2027
+ let nextSortOrder = maxSortOrder + 1;
2028
+ const merged = [...defaultSegs];
2029
+ for (const s of allScoped) {
2030
+ if (s.seg.version?.id === defaultVersion.id) {
2031
+ continue;
2032
+ }
2033
+ const type = metaStr(s.seg.metadata, "type");
2034
+ if (type !== "section") {
2035
+ continue;
2036
+ }
2037
+ const sectionPath = s.seg.section;
2038
+ if (versionSlugs.some((vs) => sectionPath === vs || sectionPath.startsWith(vs + "/"))) {
2039
+ continue;
2040
+ }
2041
+ if (existingSections.has(sectionPath)) {
2042
+ continue;
2043
+ }
2044
+ const sourceTabName = s.seg.tab?.displayName ?? "";
2045
+ const targetTab = defaultTabsByName.get(sourceTabName);
2046
+ if (targetTab == null) {
2047
+ continue;
2048
+ }
2049
+ const metadata = s.seg.metadata != null ? { ...s.seg.metadata, childIndex: void 0 } : s.seg.metadata;
2050
+ merged.push({
2051
+ seg: {
2052
+ ...s.seg,
2053
+ tab: targetTab,
2054
+ version: defaultVersion,
2055
+ sortOrder: nextSortOrder++,
2056
+ metadata
2057
+ },
2058
+ nav: s.nav
2059
+ });
2060
+ existingSections.add(sectionPath);
2061
+ }
2062
+ return merged;
2063
+ }
2064
+ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix, skipSharedSectionMerge) {
2065
+ const versionSlugs = versions.map((v) => detailSlug(v)).filter((s) => s !== "");
1909
2066
  const children = versions.map((version) => {
1910
- const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2067
+ let versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2068
+ if (detailIsDefault(version) && !skipSharedSectionMerge) {
2069
+ versionSegs = mergeSharedSections(versionSegs, scoped, version, versionSlugs);
2070
+ }
1911
2071
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1912
2072
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1913
2073
  const versionSegment = detailSlug(version);
@@ -1925,7 +2085,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1925
2085
  default: detailIsDefault(version),
1926
2086
  versionId: VersionId(version.id),
1927
2087
  availability: void 0,
1928
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2088
+ landingPage: buildLandingPage(ctx, versionSegs),
1929
2089
  announcement: void 0,
1930
2090
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1931
2091
  // The version's full slug roots structural sections so the whole
@@ -2006,34 +2166,41 @@ function crossVersionDedupKeys(node, parents) {
2006
2166
  keys.push([...parentTitles, node.title].join("###"));
2007
2167
  return keys;
2008
2168
  }
2009
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
2010
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
2011
- if (tablessSegs.length === 0) {
2169
+ function routeToLandingPage(ctx, route) {
2170
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
2012
2171
  return void 0;
2013
2172
  }
2014
- for (const s of tablessSegs) {
2015
- for (const r of s.nav) {
2016
- if (r.type === "markdown" && r.fullPath != null) {
2017
- const md = r.metadata;
2018
- const pageId = metaStr(md, "pageId") ?? "";
2019
- const slug = ctx.contentSlug(r.fullPath);
2020
- return {
2021
- type: "landingPage",
2022
- ...withMetadataDefaults({
2023
- id: ctx.nodeId(`landing:${slug}`),
2024
- title: metaStr(md, "title") ?? "",
2025
- slug,
2026
- icon: metaStr(md, "icon"),
2027
- hidden: r.hidden,
2028
- viewers: toViewers(metaStrArr(md, "viewers"))
2029
- }),
2030
- pageId: PageId(pageId),
2031
- noindex: metaBool(md, "noindex")
2032
- };
2033
- }
2034
- }
2173
+ const md = route.metadata;
2174
+ const pageId = metaStr(md, "pageId");
2175
+ if (pageId == null) {
2176
+ return void 0;
2035
2177
  }
2036
- return void 0;
2178
+ const slug = ctx.contentSlug(route.fullPath);
2179
+ return {
2180
+ type: "landingPage",
2181
+ ...withMetadataDefaults({
2182
+ id: ctx.nodeId(`landing:${slug}`),
2183
+ title: metaStr(md, "title") ?? "",
2184
+ slug,
2185
+ icon: metaStr(md, "icon"),
2186
+ hidden: route.hidden,
2187
+ authed: metaBool(md, "authed"),
2188
+ viewers: toViewers(metaStrArr(md, "viewers")),
2189
+ orphaned: metaBool(md, "orphaned"),
2190
+ featureFlags: metaFeatureFlags(md)
2191
+ }),
2192
+ pageId: PageId(pageId),
2193
+ noindex: metaBool(md, "noindex")
2194
+ };
2195
+ }
2196
+ function buildLandingPage(ctx, scopeSegs) {
2197
+ const landingSegment = scopeSegs.find(
2198
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2199
+ );
2200
+ return routeToLandingPage(
2201
+ ctx,
2202
+ landingSegment?.nav.find((route) => route.type === "markdown")
2203
+ );
2037
2204
  }
2038
2205
  function markCrossVersionCanonicalSlugs(versionNodes) {
2039
2206
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2068,13 +2235,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2068
2235
  });
2069
2236
  }
2070
2237
  }
2071
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2238
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2072
2239
  const children = products.map((product) => {
2073
2240
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2074
2241
  const versions = uniqueDetails(productSegs, "version");
2075
2242
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2076
2243
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2077
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2244
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix, skipSharedSectionMerge) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2078
2245
  const node = {
2079
2246
  type: "product",
2080
2247
  ...withMetadataDefaults({
@@ -2104,7 +2271,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2104
2271
  type: "productgroup",
2105
2272
  id: ctx.nodeId("productgroup"),
2106
2273
  collapsed: void 0,
2107
- landingPage: void 0,
2274
+ landingPage: buildLandingPage(
2275
+ ctx,
2276
+ scoped.filter((s) => s.seg.product == null)
2277
+ ),
2108
2278
  children
2109
2279
  };
2110
2280
  }