@fern-api/fdr-sdk 1.2.39-5576c2c80f → 1.2.39-adc66218ce

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.
@@ -1082,6 +1082,63 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1082
1082
  }
1083
1083
  return void 0;
1084
1084
  }
1085
+ function apiLeafPositionKey(node) {
1086
+ switch (node.type) {
1087
+ case "endpoint":
1088
+ return `endpoint:${node.endpointId}`;
1089
+ case "webhook":
1090
+ return `webhook:${node.webhookId}`;
1091
+ case "webSocket":
1092
+ return `webSocket:${node.webSocketId}`;
1093
+ case "grpc":
1094
+ return `grpc:${node.grpcId}`;
1095
+ case "graphql":
1096
+ return `graphql:${node.graphqlOperationId}`;
1097
+ }
1098
+ }
1099
+ function apiChildPositionKey(node) {
1100
+ switch (node.type) {
1101
+ case "endpoint":
1102
+ case "webhook":
1103
+ case "webSocket":
1104
+ case "grpc":
1105
+ case "graphql":
1106
+ return apiLeafPositionKey(node);
1107
+ default:
1108
+ return void 0;
1109
+ }
1110
+ }
1111
+ function positionedApiLeafChildren(ctx, nav, apiDefinitionId) {
1112
+ const rawLeafNodes = [];
1113
+ const leafPositions = /* @__PURE__ */ new Map();
1114
+ const nonApiLeafNodes = [];
1115
+ for (let i = 0; i < nav.length; i++) {
1116
+ const route = nav[i];
1117
+ const pos = route.displaySortOrder ?? i;
1118
+ const apiLeaf = apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId);
1119
+ if (apiLeaf != null) {
1120
+ rawLeafNodes.push(apiLeaf);
1121
+ const key = apiLeafPositionKey(apiLeaf);
1122
+ leafPositions.set(key, Math.min(leafPositions.get(key) ?? pos, pos));
1123
+ continue;
1124
+ }
1125
+ const node = artifactToNode(ctx, route);
1126
+ if (node?.type === "page" || node?.type === "link") {
1127
+ nonApiLeafNodes.push({ node, pos });
1128
+ }
1129
+ }
1130
+ const apiLeafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1131
+ const positionedApiLeafNodes = apiLeafNodes.map((node, index) => {
1132
+ if (node.type === "endpointPair") {
1133
+ const streamPos = leafPositions.get(apiLeafPositionKey(node.stream)) ?? index;
1134
+ const nonStreamPos = leafPositions.get(apiLeafPositionKey(node.nonStream)) ?? index;
1135
+ return { node, pos: Math.min(streamPos, nonStreamPos) };
1136
+ }
1137
+ const key = apiChildPositionKey(node);
1138
+ return { node, pos: key != null ? leafPositions.get(key) ?? index : index };
1139
+ });
1140
+ return [...positionedApiLeafNodes, ...nonApiLeafNodes];
1141
+ }
1085
1142
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1086
1143
  const ctx = createBuildContext(basePath);
1087
1144
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1191,7 +1248,9 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1191
1248
  return {
1192
1249
  type: "section",
1193
1250
  ...defaults,
1194
- collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
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,
1195
1254
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1196
1255
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1197
1256
  collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
@@ -1219,8 +1278,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1219
1278
  }
1220
1279
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1221
1280
  const { seg, nav } = scoped;
1222
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1223
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1281
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1224
1282
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1225
1283
  const packageNodes = childPackages.map((child) => ({
1226
1284
  node: apiPackageChildNode(
@@ -1234,18 +1292,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1234
1292
  }));
1235
1293
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1236
1294
  if (!hasChildIndex) {
1237
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1238
- }
1239
- const leafPositions = [];
1240
- for (const route of nav) {
1241
- if (route.displaySortOrder != null) {
1242
- leafPositions.push(route.displaySortOrder);
1243
- }
1295
+ return [...leafNodes, ...packageNodes.map((p) => ({ node: p.node, pos: Number.MAX_SAFE_INTEGER }))].sort((a, b) => a.pos - b.pos).map((p) => p.node);
1244
1296
  }
1245
1297
  const positioned = [];
1246
- for (let i = 0; i < leafNodes.length; i++) {
1247
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1248
- }
1298
+ positioned.push(...leafNodes);
1249
1299
  for (const p of packageNodes) {
1250
1300
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1251
1301
  }
@@ -1548,6 +1598,9 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1548
1598
  if (hasOwningApiReference(s, scopeSegs)) {
1549
1599
  continue;
1550
1600
  }
1601
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1602
+ continue;
1603
+ }
1551
1604
  if (type === "tabRoot" || sec === "" && type !== "section") {
1552
1605
  for (const r of s.nav) {
1553
1606
  const node = artifactToNode(ctx, r);
@@ -1666,6 +1719,24 @@ function buildFullRootFromSegments(options) {
1666
1719
  } else if (child.type === "versioned") {
1667
1720
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1668
1721
  rootPointsTo = defaultVersion?.pointsTo;
1722
+ } else if (child.type === "unversioned") {
1723
+ if (tabs.length > 0) {
1724
+ const firstTab = tabs[0];
1725
+ const pt = firstTab != null ? metaStr(firstTab.metadata, "pointsTo") : void 0;
1726
+ rootPointsTo = pt != null ? pointsToSlug(pt) : void 0;
1727
+ } else {
1728
+ const sorted = [...scoped].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1729
+ for (const s of sorted) {
1730
+ if (s.seg.hidden) {
1731
+ continue;
1732
+ }
1733
+ const pt = metaStr(s.seg.metadata, "pointsTo");
1734
+ if (pt != null) {
1735
+ rootPointsTo = pointsToSlug(pt);
1736
+ break;
1737
+ }
1738
+ }
1739
+ }
1669
1740
  }
1670
1741
  const root = {
1671
1742
  type: "root",
@@ -1678,21 +1749,22 @@ function buildFullRootFromSegments(options) {
1678
1749
  return root;
1679
1750
  }
1680
1751
  function uniqueDetails(scoped, dim) {
1681
- const bySlug = /* @__PURE__ */ new Map();
1752
+ const byKey = /* @__PURE__ */ new Map();
1682
1753
  for (const s of scoped) {
1683
1754
  const d = s.seg[dim];
1684
1755
  if (d == null) {
1685
1756
  continue;
1686
1757
  }
1687
1758
  const slug = detailSlug(d);
1688
- const existing = bySlug.get(slug);
1759
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1760
+ const existing = byKey.get(key);
1689
1761
  if (existing == null) {
1690
- bySlug.set(slug, d);
1762
+ byKey.set(key, d);
1691
1763
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1692
- bySlug.set(slug, d);
1764
+ byKey.set(key, d);
1693
1765
  }
1694
1766
  }
1695
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1767
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1696
1768
  }
1697
1769
  function scopeSlugPrefix(rootSlug, ...details) {
1698
1770
  const parts = [rootSlug];
@@ -1836,7 +1908,7 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1836
1908
  type: "unversioned",
1837
1909
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1838
1910
  collapsed: void 0,
1839
- landingPage: void 0,
1911
+ landingPage: buildLandingPage(ctx, scopeSegs),
1840
1912
  // The enclosing scope prefix (product slug, or rootSlug at the top
1841
1913
  // level) roots structural sections so they share the scope's slug
1842
1914
  // namespace.
@@ -1863,7 +1935,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1863
1935
  default: detailIsDefault(version),
1864
1936
  versionId: VersionId(version.id),
1865
1937
  availability: void 0,
1866
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
1938
+ landingPage: buildLandingPage(ctx, versionSegs),
1867
1939
  announcement: void 0,
1868
1940
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1869
1941
  // The version's full slug roots structural sections so the whole
@@ -1944,34 +2016,41 @@ function crossVersionDedupKeys(node, parents) {
1944
2016
  keys.push([...parentTitles, node.title].join("###"));
1945
2017
  return keys;
1946
2018
  }
1947
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1948
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1949
- if (tablessSegs.length === 0) {
2019
+ function routeToLandingPage(ctx, route) {
2020
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1950
2021
  return void 0;
1951
2022
  }
1952
- for (const s of tablessSegs) {
1953
- for (const r of s.nav) {
1954
- if (r.type === "markdown" && r.fullPath != null) {
1955
- const md = r.metadata;
1956
- const pageId = metaStr(md, "pageId") ?? "";
1957
- const slug = ctx.contentSlug(r.fullPath);
1958
- return {
1959
- type: "landingPage",
1960
- ...withMetadataDefaults({
1961
- id: ctx.nodeId(`landing:${slug}`),
1962
- title: metaStr(md, "title") ?? "",
1963
- slug,
1964
- icon: metaStr(md, "icon"),
1965
- hidden: r.hidden,
1966
- viewers: toViewers(metaStrArr(md, "viewers"))
1967
- }),
1968
- pageId: PageId(pageId),
1969
- noindex: metaBool(md, "noindex")
1970
- };
1971
- }
1972
- }
2023
+ const md = route.metadata;
2024
+ const pageId = metaStr(md, "pageId");
2025
+ if (pageId == null) {
2026
+ return void 0;
1973
2027
  }
1974
- return void 0;
2028
+ const slug = ctx.contentSlug(route.fullPath);
2029
+ return {
2030
+ type: "landingPage",
2031
+ ...withMetadataDefaults({
2032
+ id: ctx.nodeId(`landing:${slug}`),
2033
+ title: metaStr(md, "title") ?? "",
2034
+ slug,
2035
+ icon: metaStr(md, "icon"),
2036
+ hidden: route.hidden,
2037
+ authed: metaBool(md, "authed"),
2038
+ viewers: toViewers(metaStrArr(md, "viewers")),
2039
+ orphaned: metaBool(md, "orphaned"),
2040
+ featureFlags: metaFeatureFlags(md)
2041
+ }),
2042
+ pageId: PageId(pageId),
2043
+ noindex: metaBool(md, "noindex")
2044
+ };
2045
+ }
2046
+ function buildLandingPage(ctx, scopeSegs) {
2047
+ const landingSegment = scopeSegs.find(
2048
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2049
+ );
2050
+ return routeToLandingPage(
2051
+ ctx,
2052
+ landingSegment?.nav.find((route) => route.type === "markdown")
2053
+ );
1975
2054
  }
1976
2055
  function markCrossVersionCanonicalSlugs(versionNodes) {
1977
2056
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2042,7 +2121,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2042
2121
  type: "productgroup",
2043
2122
  id: ctx.nodeId("productgroup"),
2044
2123
  collapsed: void 0,
2045
- landingPage: void 0,
2124
+ landingPage: buildLandingPage(
2125
+ ctx,
2126
+ scoped.filter((s) => s.seg.product == null)
2127
+ ),
2046
2128
  children
2047
2129
  };
2048
2130
  }