@fern-api/fdr-sdk 1.2.39-b6eaa342cf → 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 (49) 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 +182 -52
  18. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  19. package/dist/js/navigation/ledger-root-builder.mjs +182 -52
  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.collapsedDeterminism.test.d.ts +2 -0
  29. package/dist/types/navigation/__test__/ledger-root-builder.collapsedDeterminism.test.d.ts.map +1 -0
  30. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  31. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  32. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts +2 -0
  33. package/dist/types/navigation/__test__/ledger-root-builder.metadataPreservation.test.d.ts.map +1 -0
  34. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  35. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  36. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugApiReference.test.d.ts +2 -0
  37. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugApiReference.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 +17 -1
  41. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  42. package/dist/types/navigation/utils/findNode.d.ts +1 -0
  43. package/dist/types/navigation/utils/findNode.d.ts.map +1 -1
  44. package/dist/types/navigation/utils/followRedirect.d.ts.map +1 -1
  45. package/dist/types/orpc-client/docs-ledger/contract.d.ts +50 -0
  46. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  47. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +12 -0
  48. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  49. 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;
@@ -1289,12 +1297,10 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1289
1297
  return {
1290
1298
  type: "section",
1291
1299
  ...defaults,
1292
- // V2 convention: collapsed:false in docs.yml maps to "open-by-default"
1293
- // so getInitiallyOpenByDefaultNodes picks it up and the UI starts open.
1294
- collapsed: metaCollapsed(seg.metadata) === false ? "open-by-default" : metaCollapsed(seg.metadata) ?? defaults.collapsed,
1300
+ collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1295
1301
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1296
1302
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1297
- 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),
1298
1304
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1299
1305
  availability: metaStr(seg.metadata, "availability"),
1300
1306
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1521,7 +1527,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1521
1527
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1522
1528
  noindex: metaBool(r.metadata, "noindex"),
1523
1529
  date: dateStr ?? "",
1524
- tags: void 0
1530
+ tags: metaStrArr(r.metadata, "tags")
1525
1531
  };
1526
1532
  let months = byYear.get(year);
1527
1533
  if (months == null) {
@@ -1613,7 +1619,7 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1613
1619
  const type = metaStr(s.seg.metadata, "type");
1614
1620
  const childIndex = metaNum(s.seg.metadata, "childIndex");
1615
1621
  let node;
1616
- if (type === "apiReference" || type === "apiPackage") {
1622
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1617
1623
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1618
1624
  } else if (type === "changelog") {
1619
1625
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
@@ -1628,18 +1634,56 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1628
1634
  return { node, childIndex };
1629
1635
  });
1630
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
+ }
1631
1671
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1632
1672
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1633
1673
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1634
1674
  const annotated = [];
1635
1675
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1676
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1636
1677
  for (const s of ordered) {
1637
1678
  const type = metaStr(s.seg.metadata, "type");
1638
1679
  const sec = s.seg.section;
1639
1680
  if (hasOwningApiReference(s, scopeSegs)) {
1640
1681
  continue;
1641
1682
  }
1642
- 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 ?? "")) {
1643
1687
  for (const r of s.nav) {
1644
1688
  const node = artifactToNode(ctx, r);
1645
1689
  if (node != null) {
@@ -1656,24 +1700,31 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1656
1700
  }
1657
1701
  const parent = parentSectionPath(sec);
1658
1702
  const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1659
- if (isRootLevel && hasRootSection) {
1703
+ if (isRootLevel && hasRootSection && sec !== "") {
1660
1704
  continue;
1661
1705
  }
1662
1706
  if (isRootLevel) {
1663
1707
  let node;
1664
- if (type === "apiReference" || type === "apiPackage") {
1708
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1665
1709
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1666
1710
  } else if (type === "changelog") {
1667
1711
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1668
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;
1669
1715
  node = sectionNode(
1670
1716
  ctx,
1671
1717
  s,
1672
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1718
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1673
1719
  scopePrefix
1674
1720
  );
1675
1721
  }
1676
- 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
+ });
1677
1728
  }
1678
1729
  }
1679
1730
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1725,13 +1776,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1725
1776
  };
1726
1777
  }
1727
1778
  function buildFullRootFromSegments(options) {
1728
- const { basePath, title, segments, navBySegment } = options;
1779
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1729
1780
  const ctx = createBuildContext(basePath);
1730
1781
  const scoped = segments.filter((seg) => {
1731
1782
  const t = metaStr(seg.metadata, "type");
1732
- return t !== "files" && t !== "redirects";
1783
+ return !INFRA_SEGMENT_TYPES.has(t ?? "");
1733
1784
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1734
- const rootSlug = asSlug(basePath);
1785
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1735
1786
  const scopesByKey = /* @__PURE__ */ new Map();
1736
1787
  for (const s of scoped) {
1737
1788
  const key = scopeKey(s.seg);
@@ -1744,9 +1795,9 @@ function buildFullRootFromSegments(options) {
1744
1795
  const tabs = uniqueDetails(scoped, "tab");
1745
1796
  let child;
1746
1797
  if (products.length > 0) {
1747
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1798
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1748
1799
  } else if (versions.length > 0) {
1749
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1800
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1750
1801
  } else {
1751
1802
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1752
1803
  }
@@ -1853,20 +1904,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1853
1904
  if (variants.length <= 1) {
1854
1905
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1855
1906
  }
1907
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1856
1908
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1909
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1857
1910
  const first = scopeSegs[0];
1858
1911
  return {
1859
1912
  type: "sidebarRoot",
1860
1913
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1861
1914
  collapsed: void 0,
1862
- children: [variantedNode]
1915
+ children: [...sharedChildren, variantedNode]
1863
1916
  };
1864
1917
  }
1865
1918
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1866
1919
  if (!tabsPresent) {
1867
1920
  const variants = uniqueDetails(scopeSegs, "variant");
1868
1921
  if (variants.length > 1) {
1869
- 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;
1870
1935
  }
1871
1936
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1872
1937
  }
@@ -1892,7 +1957,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1892
1957
  const tabSegs2 = scopeSegs.filter((s) => s.seg.tab?.id === tab.id);
1893
1958
  const changelogSeg = tabSegs2.find((s) => metaStr(s.seg.metadata, "type") === "changelog");
1894
1959
  if (changelogSeg != null) {
1895
- return changelogNode(ctx, changelogSeg, scopePrefix);
1960
+ return changelogNode(ctx, changelogSeg, tabSlug);
1896
1961
  }
1897
1962
  return {
1898
1963
  type: "changelog",
@@ -1946,16 +2011,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1946
2011
  type: "unversioned",
1947
2012
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1948
2013
  collapsed: void 0,
1949
- landingPage: void 0,
2014
+ landingPage: buildLandingPage(ctx, scopeSegs),
1950
2015
  // The enclosing scope prefix (product slug, or rootSlug at the top
1951
2016
  // level) roots structural sections so they share the scope's slug
1952
2017
  // namespace.
1953
2018
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1954
2019
  };
1955
2020
  }
1956
- 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 !== "");
1957
2074
  const children = versions.map((version) => {
1958
- 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
+ }
1959
2079
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1960
2080
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1961
2081
  const versionSegment = detailSlug(version);
@@ -1973,7 +2093,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1973
2093
  default: detailIsDefault(version),
1974
2094
  versionId: VersionId(version.id),
1975
2095
  availability: void 0,
1976
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2096
+ landingPage: buildLandingPage(ctx, versionSegs),
1977
2097
  announcement: void 0,
1978
2098
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1979
2099
  // The version's full slug roots structural sections so the whole
@@ -2054,34 +2174,41 @@ function crossVersionDedupKeys(node, parents) {
2054
2174
  keys.push([...parentTitles, node.title].join("###"));
2055
2175
  return keys;
2056
2176
  }
2057
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
2058
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
2059
- if (tablessSegs.length === 0) {
2177
+ function routeToLandingPage(ctx, route) {
2178
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
2060
2179
  return void 0;
2061
2180
  }
2062
- for (const s of tablessSegs) {
2063
- for (const r of s.nav) {
2064
- if (r.type === "markdown" && r.fullPath != null) {
2065
- const md = r.metadata;
2066
- const pageId = metaStr(md, "pageId") ?? "";
2067
- const slug = ctx.contentSlug(r.fullPath);
2068
- return {
2069
- type: "landingPage",
2070
- ...withMetadataDefaults({
2071
- id: ctx.nodeId(`landing:${slug}`),
2072
- title: metaStr(md, "title") ?? "",
2073
- slug,
2074
- icon: metaStr(md, "icon"),
2075
- hidden: r.hidden,
2076
- viewers: toViewers(metaStrArr(md, "viewers"))
2077
- }),
2078
- pageId: PageId(pageId),
2079
- noindex: metaBool(md, "noindex")
2080
- };
2081
- }
2082
- }
2181
+ const md = route.metadata;
2182
+ const pageId = metaStr(md, "pageId");
2183
+ if (pageId == null) {
2184
+ return void 0;
2083
2185
  }
2084
- 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
+ );
2085
2212
  }
2086
2213
  function markCrossVersionCanonicalSlugs(versionNodes) {
2087
2214
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2116,13 +2243,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2116
2243
  });
2117
2244
  }
2118
2245
  }
2119
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2246
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2120
2247
  const children = products.map((product) => {
2121
2248
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2122
2249
  const versions = uniqueDetails(productSegs, "version");
2123
2250
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2124
2251
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2125
- 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);
2126
2253
  const node = {
2127
2254
  type: "product",
2128
2255
  ...withMetadataDefaults({
@@ -2152,7 +2279,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2152
2279
  type: "productgroup",
2153
2280
  id: ctx.nodeId("productgroup"),
2154
2281
  collapsed: void 0,
2155
- landingPage: void 0,
2282
+ landingPage: buildLandingPage(
2283
+ ctx,
2284
+ scoped.filter((s) => s.seg.product == null)
2285
+ ),
2156
2286
  children
2157
2287
  };
2158
2288
  }