@fern-api/fdr-sdk 1.2.39-5576c2c80f → 1.2.39-7803ef9da9

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 (48) 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 +250 -59
  18. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  19. package/dist/js/navigation/ledger-root-builder.mjs +250 -59
  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__/ledger-root-builder.apiReferenceChildren.test.d.ts +2 -0
  27. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts.map +1 -0
  28. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  29. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  30. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts +2 -0
  31. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts.map +1 -0
  32. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  33. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  34. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts +2 -0
  35. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts.map +1 -0
  36. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts +2 -0
  37. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts.map +1 -0
  38. package/dist/types/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts +2 -0
  39. package/dist/types/navigation/__test__/ledger-root-builder.variantSharedSegments.test.d.ts.map +1 -0
  40. package/dist/types/navigation/ledger-root-builder.d.ts +12 -0
  41. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  42. package/dist/types/navigation/utils/findNode.d.ts.map +1 -1
  43. package/dist/types/navigation/utils/followRedirect.d.ts.map +1 -1
  44. package/dist/types/orpc-client/docs-ledger/contract.d.ts +50 -0
  45. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  46. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +12 -0
  47. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  48. 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);
@@ -1235,7 +1292,7 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1235
1292
  collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1236
1293
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1237
1294
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1238
- 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),
1239
1296
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1240
1297
  availability: metaStr(seg.metadata, "availability"),
1241
1298
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1260,8 +1317,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1260
1317
  }
1261
1318
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1262
1319
  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);
1320
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1265
1321
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1266
1322
  const packageNodes = childPackages.map((child) => ({
1267
1323
  node: apiPackageChildNode(
@@ -1275,18 +1331,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1275
1331
  }));
1276
1332
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1277
1333
  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
- }
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);
1285
1335
  }
1286
1336
  const positioned = [];
1287
- for (let i = 0; i < leafNodes.length; i++) {
1288
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1289
- }
1337
+ positioned.push(...leafNodes);
1290
1338
  for (const p of packageNodes) {
1291
1339
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1292
1340
  }
@@ -1471,7 +1519,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1471
1519
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1472
1520
  noindex: metaBool(r.metadata, "noindex"),
1473
1521
  date: dateStr ?? "",
1474
- tags: void 0
1522
+ tags: metaStrArr(r.metadata, "tags")
1475
1523
  };
1476
1524
  let months = byYear.get(year);
1477
1525
  if (months == null) {
@@ -1578,17 +1626,55 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1578
1626
  return { node, childIndex };
1579
1627
  });
1580
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
+ }
1581
1663
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1582
1664
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1583
1665
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1584
1666
  const annotated = [];
1585
1667
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1668
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1586
1669
  for (const s of ordered) {
1587
1670
  const type = metaStr(s.seg.metadata, "type");
1588
1671
  const sec = s.seg.section;
1589
1672
  if (hasOwningApiReference(s, scopeSegs)) {
1590
1673
  continue;
1591
1674
  }
1675
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1676
+ continue;
1677
+ }
1592
1678
  if (type === "tabRoot" || sec === "" && type !== "section") {
1593
1679
  for (const r of s.nav) {
1594
1680
  const node = artifactToNode(ctx, r);
@@ -1616,14 +1702,21 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1616
1702
  } else if (type === "changelog") {
1617
1703
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1618
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;
1619
1707
  node = sectionNode(
1620
1708
  ctx,
1621
1709
  s,
1622
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1710
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1623
1711
  scopePrefix
1624
1712
  );
1625
1713
  }
1626
- 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
+ });
1627
1720
  }
1628
1721
  }
1629
1722
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1675,13 +1768,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1675
1768
  };
1676
1769
  }
1677
1770
  function buildFullRootFromSegments(options) {
1678
- const { basePath, title, segments, navBySegment } = options;
1771
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1679
1772
  const ctx = createBuildContext(basePath);
1680
1773
  const scoped = segments.filter((seg) => {
1681
1774
  const t = metaStr(seg.metadata, "type");
1682
1775
  return t !== "files" && t !== "redirects";
1683
1776
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1684
- const rootSlug = asSlug(basePath);
1777
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1685
1778
  const scopesByKey = /* @__PURE__ */ new Map();
1686
1779
  for (const s of scoped) {
1687
1780
  const key = scopeKey(s.seg);
@@ -1694,9 +1787,9 @@ function buildFullRootFromSegments(options) {
1694
1787
  const tabs = uniqueDetails(scoped, "tab");
1695
1788
  let child;
1696
1789
  if (products.length > 0) {
1697
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1790
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1698
1791
  } else if (versions.length > 0) {
1699
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1792
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1700
1793
  } else {
1701
1794
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1702
1795
  }
@@ -1707,6 +1800,24 @@ function buildFullRootFromSegments(options) {
1707
1800
  } else if (child.type === "versioned") {
1708
1801
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1709
1802
  rootPointsTo = defaultVersion?.pointsTo;
1803
+ } else if (child.type === "unversioned") {
1804
+ if (tabs.length > 0) {
1805
+ const firstTab = tabs[0];
1806
+ const pt = firstTab != null ? metaStr(firstTab.metadata, "pointsTo") : void 0;
1807
+ rootPointsTo = pt != null ? pointsToSlug(pt) : void 0;
1808
+ } else {
1809
+ const sorted = [...scoped].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1810
+ for (const s of sorted) {
1811
+ if (s.seg.hidden) {
1812
+ continue;
1813
+ }
1814
+ const pt = metaStr(s.seg.metadata, "pointsTo");
1815
+ if (pt != null) {
1816
+ rootPointsTo = pointsToSlug(pt);
1817
+ break;
1818
+ }
1819
+ }
1820
+ }
1710
1821
  }
1711
1822
  const root = {
1712
1823
  type: "root",
@@ -1719,21 +1830,22 @@ function buildFullRootFromSegments(options) {
1719
1830
  return root;
1720
1831
  }
1721
1832
  function uniqueDetails(scoped, dim) {
1722
- const bySlug = /* @__PURE__ */ new Map();
1833
+ const byKey = /* @__PURE__ */ new Map();
1723
1834
  for (const s of scoped) {
1724
1835
  const d = s.seg[dim];
1725
1836
  if (d == null) {
1726
1837
  continue;
1727
1838
  }
1728
1839
  const slug = detailSlug(d);
1729
- const existing = bySlug.get(slug);
1840
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1841
+ const existing = byKey.get(key);
1730
1842
  if (existing == null) {
1731
- bySlug.set(slug, d);
1843
+ byKey.set(key, d);
1732
1844
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1733
- bySlug.set(slug, d);
1845
+ byKey.set(key, d);
1734
1846
  }
1735
1847
  }
1736
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1848
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1737
1849
  }
1738
1850
  function scopeSlugPrefix(rootSlug, ...details) {
1739
1851
  const parts = [rootSlug];
@@ -1784,20 +1896,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1784
1896
  if (variants.length <= 1) {
1785
1897
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1786
1898
  }
1899
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1787
1900
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1901
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1788
1902
  const first = scopeSegs[0];
1789
1903
  return {
1790
1904
  type: "sidebarRoot",
1791
1905
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1792
1906
  collapsed: void 0,
1793
- children: [variantedNode]
1907
+ children: [...sharedChildren, variantedNode]
1794
1908
  };
1795
1909
  }
1796
1910
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1797
1911
  if (!tabsPresent) {
1798
1912
  const variants = uniqueDetails(scopeSegs, "variant");
1799
1913
  if (variants.length > 1) {
1800
- 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;
1801
1927
  }
1802
1928
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1803
1929
  }
@@ -1877,16 +2003,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1877
2003
  type: "unversioned",
1878
2004
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1879
2005
  collapsed: void 0,
1880
- landingPage: void 0,
2006
+ landingPage: buildLandingPage(ctx, scopeSegs),
1881
2007
  // The enclosing scope prefix (product slug, or rootSlug at the top
1882
2008
  // level) roots structural sections so they share the scope's slug
1883
2009
  // namespace.
1884
2010
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1885
2011
  };
1886
2012
  }
1887
- 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 !== "");
1888
2066
  const children = versions.map((version) => {
1889
- 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
+ }
1890
2071
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1891
2072
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1892
2073
  const versionSegment = detailSlug(version);
@@ -1904,7 +2085,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1904
2085
  default: detailIsDefault(version),
1905
2086
  versionId: VersionId(version.id),
1906
2087
  availability: void 0,
1907
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2088
+ landingPage: buildLandingPage(ctx, versionSegs),
1908
2089
  announcement: void 0,
1909
2090
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1910
2091
  // The version's full slug roots structural sections so the whole
@@ -1985,34 +2166,41 @@ function crossVersionDedupKeys(node, parents) {
1985
2166
  keys.push([...parentTitles, node.title].join("###"));
1986
2167
  return keys;
1987
2168
  }
1988
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1989
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1990
- if (tablessSegs.length === 0) {
2169
+ function routeToLandingPage(ctx, route) {
2170
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1991
2171
  return void 0;
1992
2172
  }
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
- }
2173
+ const md = route.metadata;
2174
+ const pageId = metaStr(md, "pageId");
2175
+ if (pageId == null) {
2176
+ return void 0;
2014
2177
  }
2015
- 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
+ );
2016
2204
  }
2017
2205
  function markCrossVersionCanonicalSlugs(versionNodes) {
2018
2206
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2047,13 +2235,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2047
2235
  });
2048
2236
  }
2049
2237
  }
2050
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2238
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2051
2239
  const children = products.map((product) => {
2052
2240
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2053
2241
  const versions = uniqueDetails(productSegs, "version");
2054
2242
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2055
2243
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2056
- 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);
2057
2245
  const node = {
2058
2246
  type: "product",
2059
2247
  ...withMetadataDefaults({
@@ -2083,7 +2271,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2083
2271
  type: "productgroup",
2084
2272
  id: ctx.nodeId("productgroup"),
2085
2273
  collapsed: void 0,
2086
- landingPage: void 0,
2274
+ landingPage: buildLandingPage(
2275
+ ctx,
2276
+ scoped.filter((s) => s.seg.product == null)
2277
+ ),
2087
2278
  children
2088
2279
  };
2089
2280
  }