@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
@@ -805,6 +805,14 @@ function traverseDF(node, visit) {
805
805
  }
806
806
 
807
807
  // src/navigation/ledger-root-builder.ts
808
+ var STRUCTURAL_SEGMENT_TYPES = /* @__PURE__ */ new Set([
809
+ "section",
810
+ "apiReference",
811
+ "apiPackage",
812
+ "changelog"
813
+ ]);
814
+ var API_NODE_SEGMENT_TYPES = /* @__PURE__ */ new Set(["apiReference", "apiPackage"]);
815
+ var INFRA_SEGMENT_TYPES = /* @__PURE__ */ new Set(["files", "redirects"]);
808
816
  function createBuildContext(basePath) {
809
817
  const seen = /* @__PURE__ */ new Map();
810
818
  const basePrefix = basePath.replace(/^\/+|\/+$/g, "");
@@ -882,7 +890,7 @@ function toViewers(viewers) {
882
890
  return viewers.map((v) => RoleId(v));
883
891
  }
884
892
  function mergeVariantViewers(seg) {
885
- const segViewers = seg.metadata.type === "section" || seg.metadata.type === "apiReference" || seg.metadata.type === "apiPackage" || seg.metadata.type === "changelog" ? seg.metadata.viewers : void 0;
893
+ const segViewers = STRUCTURAL_SEGMENT_TYPES.has(seg.metadata.type) ? seg.metadata.viewers : void 0;
886
894
  const variantViewers = seg.variant?.viewers;
887
895
  if ((segViewers == null || segViewers.length === 0) && (variantViewers == null || variantViewers.length === 0)) {
888
896
  return void 0;
@@ -1248,12 +1256,10 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1248
1256
  return {
1249
1257
  type: "section",
1250
1258
  ...defaults,
1251
- // V2 convention: collapsed:false in docs.yml maps to "open-by-default"
1252
- // so getInitiallyOpenByDefaultNodes picks it up and the UI starts open.
1253
- collapsed: metaCollapsed(seg.metadata) === false ? "open-by-default" : metaCollapsed(seg.metadata) ?? defaults.collapsed,
1259
+ collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
1254
1260
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1255
1261
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1256
- collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1262
+ collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1257
1263
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1258
1264
  availability: metaStr(seg.metadata, "availability"),
1259
1265
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
@@ -1480,7 +1486,7 @@ function changelogNode(ctx, scoped, scopePrefix) {
1480
1486
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1481
1487
  noindex: metaBool(r.metadata, "noindex"),
1482
1488
  date: dateStr ?? "",
1483
- tags: void 0
1489
+ tags: metaStrArr(r.metadata, "tags")
1484
1490
  };
1485
1491
  let months = byYear.get(year);
1486
1492
  if (months == null) {
@@ -1572,7 +1578,7 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1572
1578
  const type = metaStr(s.seg.metadata, "type");
1573
1579
  const childIndex = metaNum(s.seg.metadata, "childIndex");
1574
1580
  let node;
1575
- if (type === "apiReference" || type === "apiPackage") {
1581
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1576
1582
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1577
1583
  } else if (type === "changelog") {
1578
1584
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
@@ -1587,18 +1593,56 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
1587
1593
  return { node, childIndex };
1588
1594
  });
1589
1595
  }
1596
+ function computeSiblingSortBoundaries(ordered) {
1597
+ const result = /* @__PURE__ */ new Map();
1598
+ const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1599
+ const rootSections = [];
1600
+ for (const s of ordered) {
1601
+ const type = metaStr(s.seg.metadata, "type");
1602
+ const sec = s.seg.section;
1603
+ if (type !== "section" || sec === "") {
1604
+ continue;
1605
+ }
1606
+ const parent = parentSectionPath(sec);
1607
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1608
+ if (isRootLevel) {
1609
+ rootSections.push(s);
1610
+ }
1611
+ }
1612
+ const byPath = /* @__PURE__ */ new Map();
1613
+ for (const s of rootSections) {
1614
+ const group = byPath.get(s.seg.section) ?? [];
1615
+ group.push(s);
1616
+ byPath.set(s.seg.section, group);
1617
+ }
1618
+ for (const [, siblings] of byPath) {
1619
+ if (siblings.length <= 1) {
1620
+ continue;
1621
+ }
1622
+ for (let i = 0; i < siblings.length; i++) {
1623
+ const lo = siblings[i].seg.sortOrder;
1624
+ const hi = i + 1 < siblings.length ? siblings[i + 1].seg.sortOrder : Number.MAX_SAFE_INTEGER;
1625
+ result.set(siblings[i], { lo, hi });
1626
+ }
1627
+ }
1628
+ return result;
1629
+ }
1590
1630
  function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1591
1631
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1592
1632
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1593
1633
  const annotated = [];
1594
1634
  const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1635
+ const siblingBoundaries = computeSiblingSortBoundaries(ordered);
1595
1636
  for (const s of ordered) {
1596
1637
  const type = metaStr(s.seg.metadata, "type");
1597
1638
  const sec = s.seg.section;
1598
1639
  if (hasOwningApiReference(s, scopeSegs)) {
1599
1640
  continue;
1600
1641
  }
1601
- if (type === "tabRoot" || sec === "" && type !== "section") {
1642
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1643
+ continue;
1644
+ }
1645
+ if (type === "tabRoot" || sec === "" && !STRUCTURAL_SEGMENT_TYPES.has(type ?? "")) {
1602
1646
  for (const r of s.nav) {
1603
1647
  const node = artifactToNode(ctx, r);
1604
1648
  if (node != null) {
@@ -1615,24 +1659,31 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1615
1659
  }
1616
1660
  const parent = parentSectionPath(sec);
1617
1661
  const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1618
- if (isRootLevel && hasRootSection) {
1662
+ if (isRootLevel && hasRootSection && sec !== "") {
1619
1663
  continue;
1620
1664
  }
1621
1665
  if (isRootLevel) {
1622
1666
  let node;
1623
- if (type === "apiReference" || type === "apiPackage") {
1667
+ if (API_NODE_SEGMENT_TYPES.has(type ?? "")) {
1624
1668
  node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1625
1669
  } else if (type === "changelog") {
1626
1670
  node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1627
1671
  } else {
1672
+ const bounds = siblingBoundaries.get(s);
1673
+ const ownedSegs = bounds != null ? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi) : scopeSegs;
1628
1674
  node = sectionNode(
1629
1675
  ctx,
1630
1676
  s,
1631
- buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1677
+ buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix),
1632
1678
  scopePrefix
1633
1679
  );
1634
1680
  }
1635
- annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1681
+ const isSharedSection = siblingBoundaries.size > 0 && scopePrefix !== "" && sec !== "" && !sec.startsWith(scopePrefix);
1682
+ annotated.push({
1683
+ node,
1684
+ pos: isSharedSection ? void 0 : metaNum(s.seg.metadata, "childIndex"),
1685
+ isLeaf: false
1686
+ });
1636
1687
  }
1637
1688
  }
1638
1689
  const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
@@ -1684,13 +1735,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1684
1735
  };
1685
1736
  }
1686
1737
  function buildFullRootFromSegments(options) {
1687
- const { basePath, title, segments, navBySegment } = options;
1738
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment, skipSharedSectionMerge } = options;
1688
1739
  const ctx = createBuildContext(basePath);
1689
1740
  const scoped = segments.filter((seg) => {
1690
1741
  const t = metaStr(seg.metadata, "type");
1691
- return t !== "files" && t !== "redirects";
1742
+ return !INFRA_SEGMENT_TYPES.has(t ?? "");
1692
1743
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1693
- const rootSlug = asSlug(basePath);
1744
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1694
1745
  const scopesByKey = /* @__PURE__ */ new Map();
1695
1746
  for (const s of scoped) {
1696
1747
  const key = scopeKey(s.seg);
@@ -1703,9 +1754,9 @@ function buildFullRootFromSegments(options) {
1703
1754
  const tabs = uniqueDetails(scoped, "tab");
1704
1755
  let child;
1705
1756
  if (products.length > 0) {
1706
- child = buildProductGroup(ctx, products, scoped, rootSlug);
1757
+ child = buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge);
1707
1758
  } else if (versions.length > 0) {
1708
- child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1759
+ child = buildVersioned(ctx, versions, scoped, rootSlug, void 0, skipSharedSectionMerge);
1709
1760
  } else {
1710
1761
  child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1711
1762
  }
@@ -1812,20 +1863,34 @@ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScop
1812
1863
  if (variants.length <= 1) {
1813
1864
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1814
1865
  }
1866
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1815
1867
  const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1868
+ const sharedChildren = sharedSegs.length > 0 ? buildSidebarRootChildren(ctx, sharedSegs, scopePrefix, changelogScopePrefix) : [];
1816
1869
  const first = scopeSegs[0];
1817
1870
  return {
1818
1871
  type: "sidebarRoot",
1819
1872
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1820
1873
  collapsed: void 0,
1821
- children: [variantedNode]
1874
+ children: [...sharedChildren, variantedNode]
1822
1875
  };
1823
1876
  }
1824
1877
  function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1825
1878
  if (!tabsPresent) {
1826
1879
  const variants = uniqueDetails(scopeSegs, "variant");
1827
1880
  if (variants.length > 1) {
1828
- return buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1881
+ const sharedSegs = scopeSegs.filter((s) => s.seg.variant == null);
1882
+ const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1883
+ if (sharedSegs.length > 0) {
1884
+ const sharedChildren = buildSidebarRootChildren(ctx, sharedSegs, scopePrefix);
1885
+ const first2 = scopeSegs[0];
1886
+ return {
1887
+ type: "sidebarRoot",
1888
+ id: ctx.nodeId(`sidebar:${first2 != null ? scopeKey(first2.seg) : "root"}`),
1889
+ collapsed: void 0,
1890
+ children: [...sharedChildren, variantedNode]
1891
+ };
1892
+ }
1893
+ return variantedNode;
1829
1894
  }
1830
1895
  return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1831
1896
  }
@@ -1851,7 +1916,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1851
1916
  const tabSegs2 = scopeSegs.filter((s) => s.seg.tab?.id === tab.id);
1852
1917
  const changelogSeg = tabSegs2.find((s) => metaStr(s.seg.metadata, "type") === "changelog");
1853
1918
  if (changelogSeg != null) {
1854
- return changelogNode(ctx, changelogSeg, scopePrefix);
1919
+ return changelogNode(ctx, changelogSeg, tabSlug);
1855
1920
  }
1856
1921
  return {
1857
1922
  type: "changelog",
@@ -1905,16 +1970,71 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1905
1970
  type: "unversioned",
1906
1971
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1907
1972
  collapsed: void 0,
1908
- landingPage: void 0,
1973
+ landingPage: buildLandingPage(ctx, scopeSegs),
1909
1974
  // The enclosing scope prefix (product slug, or rootSlug at the top
1910
1975
  // level) roots structural sections so they share the scope's slug
1911
1976
  // namespace.
1912
1977
  child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1913
1978
  };
1914
1979
  }
1915
- function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1980
+ function mergeSharedSections(defaultSegs, allScoped, defaultVersion, versionSlugs) {
1981
+ const defaultTabsByName = /* @__PURE__ */ new Map();
1982
+ for (const s of defaultSegs) {
1983
+ if (s.seg.tab != null) {
1984
+ const tabName = s.seg.tab.displayName;
1985
+ if (!defaultTabsByName.has(tabName)) {
1986
+ defaultTabsByName.set(tabName, s.seg.tab);
1987
+ }
1988
+ }
1989
+ }
1990
+ const existingSections = new Set(
1991
+ defaultSegs.filter((s) => metaStr(s.seg.metadata, "type") === "section").map((s) => s.seg.section)
1992
+ );
1993
+ const maxSortOrder = defaultSegs.reduce((max, s) => Math.max(max, s.seg.sortOrder), 0);
1994
+ let nextSortOrder = maxSortOrder + 1;
1995
+ const merged = [...defaultSegs];
1996
+ for (const s of allScoped) {
1997
+ if (s.seg.version?.id === defaultVersion.id) {
1998
+ continue;
1999
+ }
2000
+ const type = metaStr(s.seg.metadata, "type");
2001
+ if (type !== "section") {
2002
+ continue;
2003
+ }
2004
+ const sectionPath = s.seg.section;
2005
+ if (versionSlugs.some((vs) => sectionPath === vs || sectionPath.startsWith(vs + "/"))) {
2006
+ continue;
2007
+ }
2008
+ if (existingSections.has(sectionPath)) {
2009
+ continue;
2010
+ }
2011
+ const sourceTabName = s.seg.tab?.displayName ?? "";
2012
+ const targetTab = defaultTabsByName.get(sourceTabName);
2013
+ if (targetTab == null) {
2014
+ continue;
2015
+ }
2016
+ const metadata = s.seg.metadata != null ? { ...s.seg.metadata, childIndex: void 0 } : s.seg.metadata;
2017
+ merged.push({
2018
+ seg: {
2019
+ ...s.seg,
2020
+ tab: targetTab,
2021
+ version: defaultVersion,
2022
+ sortOrder: nextSortOrder++,
2023
+ metadata
2024
+ },
2025
+ nav: s.nav
2026
+ });
2027
+ existingSections.add(sectionPath);
2028
+ }
2029
+ return merged;
2030
+ }
2031
+ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix, skipSharedSectionMerge) {
2032
+ const versionSlugs = versions.map((v) => detailSlug(v)).filter((s) => s !== "");
1916
2033
  const children = versions.map((version) => {
1917
- const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2034
+ let versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
2035
+ if (detailIsDefault(version) && !skipSharedSectionMerge) {
2036
+ versionSegs = mergeSharedSections(versionSegs, scoped, version, versionSlugs);
2037
+ }
1918
2038
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1919
2039
  const prefix = productPrefix != null ? productPrefix : rootSlug;
1920
2040
  const versionSegment = detailSlug(version);
@@ -1932,7 +2052,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1932
2052
  default: detailIsDefault(version),
1933
2053
  versionId: VersionId(version.id),
1934
2054
  availability: void 0,
1935
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
2055
+ landingPage: buildLandingPage(ctx, versionSegs),
1936
2056
  announcement: void 0,
1937
2057
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1938
2058
  // The version's full slug roots structural sections so the whole
@@ -2013,34 +2133,41 @@ function crossVersionDedupKeys(node, parents) {
2013
2133
  keys.push([...parentTitles, node.title].join("###"));
2014
2134
  return keys;
2015
2135
  }
2016
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
2017
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
2018
- if (tablessSegs.length === 0) {
2136
+ function routeToLandingPage(ctx, route) {
2137
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
2019
2138
  return void 0;
2020
2139
  }
2021
- for (const s of tablessSegs) {
2022
- for (const r of s.nav) {
2023
- if (r.type === "markdown" && r.fullPath != null) {
2024
- const md = r.metadata;
2025
- const pageId = metaStr(md, "pageId") ?? "";
2026
- const slug = ctx.contentSlug(r.fullPath);
2027
- return {
2028
- type: "landingPage",
2029
- ...withMetadataDefaults({
2030
- id: ctx.nodeId(`landing:${slug}`),
2031
- title: metaStr(md, "title") ?? "",
2032
- slug,
2033
- icon: metaStr(md, "icon"),
2034
- hidden: r.hidden,
2035
- viewers: toViewers(metaStrArr(md, "viewers"))
2036
- }),
2037
- pageId: PageId(pageId),
2038
- noindex: metaBool(md, "noindex")
2039
- };
2040
- }
2041
- }
2140
+ const md = route.metadata;
2141
+ const pageId = metaStr(md, "pageId");
2142
+ if (pageId == null) {
2143
+ return void 0;
2042
2144
  }
2043
- return void 0;
2145
+ const slug = ctx.contentSlug(route.fullPath);
2146
+ return {
2147
+ type: "landingPage",
2148
+ ...withMetadataDefaults({
2149
+ id: ctx.nodeId(`landing:${slug}`),
2150
+ title: metaStr(md, "title") ?? "",
2151
+ slug,
2152
+ icon: metaStr(md, "icon"),
2153
+ hidden: route.hidden,
2154
+ authed: metaBool(md, "authed"),
2155
+ viewers: toViewers(metaStrArr(md, "viewers")),
2156
+ orphaned: metaBool(md, "orphaned"),
2157
+ featureFlags: metaFeatureFlags(md)
2158
+ }),
2159
+ pageId: PageId(pageId),
2160
+ noindex: metaBool(md, "noindex")
2161
+ };
2162
+ }
2163
+ function buildLandingPage(ctx, scopeSegs) {
2164
+ const landingSegment = scopeSegs.find(
2165
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2166
+ );
2167
+ return routeToLandingPage(
2168
+ ctx,
2169
+ landingSegment?.nav.find((route) => route.type === "markdown")
2170
+ );
2044
2171
  }
2045
2172
  function markCrossVersionCanonicalSlugs(versionNodes) {
2046
2173
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2075,13 +2202,13 @@ function markCrossVersionCanonicalSlugs(versionNodes) {
2075
2202
  });
2076
2203
  }
2077
2204
  }
2078
- function buildProductGroup(ctx, products, scoped, rootSlug) {
2205
+ function buildProductGroup(ctx, products, scoped, rootSlug, skipSharedSectionMerge) {
2079
2206
  const children = products.map((product) => {
2080
2207
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
2081
2208
  const versions = uniqueDetails(productSegs, "version");
2082
2209
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
2083
2210
  const productPrefix = scopeSlugPrefix(rootSlug, product);
2084
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2211
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix, skipSharedSectionMerge) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
2085
2212
  const node = {
2086
2213
  type: "product",
2087
2214
  ...withMetadataDefaults({
@@ -2111,7 +2238,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2111
2238
  type: "productgroup",
2112
2239
  id: ctx.nodeId("productgroup"),
2113
2240
  collapsed: void 0,
2114
- landingPage: void 0,
2241
+ landingPage: buildLandingPage(
2242
+ ctx,
2243
+ scoped.filter((s) => s.seg.product == null)
2244
+ ),
2115
2245
  children
2116
2246
  };
2117
2247
  }