@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.
@@ -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,7 +1289,9 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1232
1289
  return {
1233
1290
  type: "section",
1234
1291
  ...defaults,
1235
- collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
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,
1236
1295
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1237
1296
  noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1238
1297
  collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
@@ -1260,8 +1319,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1260
1319
  }
1261
1320
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1262
1321
  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);
1322
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1265
1323
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1266
1324
  const packageNodes = childPackages.map((child) => ({
1267
1325
  node: apiPackageChildNode(
@@ -1275,18 +1333,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1275
1333
  }));
1276
1334
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1277
1335
  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
- }
1336
+ 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
1337
  }
1286
1338
  const positioned = [];
1287
- for (let i = 0; i < leafNodes.length; i++) {
1288
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1289
- }
1339
+ positioned.push(...leafNodes);
1290
1340
  for (const p of packageNodes) {
1291
1341
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1292
1342
  }
@@ -1589,6 +1639,9 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1589
1639
  if (hasOwningApiReference(s, scopeSegs)) {
1590
1640
  continue;
1591
1641
  }
1642
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1643
+ continue;
1644
+ }
1592
1645
  if (type === "tabRoot" || sec === "" && type !== "section") {
1593
1646
  for (const r of s.nav) {
1594
1647
  const node = artifactToNode(ctx, r);
@@ -1707,6 +1760,24 @@ function buildFullRootFromSegments(options) {
1707
1760
  } else if (child.type === "versioned") {
1708
1761
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1709
1762
  rootPointsTo = defaultVersion?.pointsTo;
1763
+ } else if (child.type === "unversioned") {
1764
+ if (tabs.length > 0) {
1765
+ const firstTab = tabs[0];
1766
+ const pt = firstTab != null ? metaStr(firstTab.metadata, "pointsTo") : void 0;
1767
+ rootPointsTo = pt != null ? pointsToSlug(pt) : void 0;
1768
+ } else {
1769
+ const sorted = [...scoped].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1770
+ for (const s of sorted) {
1771
+ if (s.seg.hidden) {
1772
+ continue;
1773
+ }
1774
+ const pt = metaStr(s.seg.metadata, "pointsTo");
1775
+ if (pt != null) {
1776
+ rootPointsTo = pointsToSlug(pt);
1777
+ break;
1778
+ }
1779
+ }
1780
+ }
1710
1781
  }
1711
1782
  const root = {
1712
1783
  type: "root",
@@ -1719,21 +1790,22 @@ function buildFullRootFromSegments(options) {
1719
1790
  return root;
1720
1791
  }
1721
1792
  function uniqueDetails(scoped, dim) {
1722
- const bySlug = /* @__PURE__ */ new Map();
1793
+ const byKey = /* @__PURE__ */ new Map();
1723
1794
  for (const s of scoped) {
1724
1795
  const d = s.seg[dim];
1725
1796
  if (d == null) {
1726
1797
  continue;
1727
1798
  }
1728
1799
  const slug = detailSlug(d);
1729
- const existing = bySlug.get(slug);
1800
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1801
+ const existing = byKey.get(key);
1730
1802
  if (existing == null) {
1731
- bySlug.set(slug, d);
1803
+ byKey.set(key, d);
1732
1804
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1733
- bySlug.set(slug, d);
1805
+ byKey.set(key, d);
1734
1806
  }
1735
1807
  }
1736
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1808
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1737
1809
  }
1738
1810
  function scopeSlugPrefix(rootSlug, ...details) {
1739
1811
  const parts = [rootSlug];
@@ -1877,7 +1949,7 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1877
1949
  type: "unversioned",
1878
1950
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1879
1951
  collapsed: void 0,
1880
- landingPage: void 0,
1952
+ landingPage: buildLandingPage(ctx, scopeSegs),
1881
1953
  // The enclosing scope prefix (product slug, or rootSlug at the top
1882
1954
  // level) roots structural sections so they share the scope's slug
1883
1955
  // namespace.
@@ -1904,7 +1976,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1904
1976
  default: detailIsDefault(version),
1905
1977
  versionId: VersionId(version.id),
1906
1978
  availability: void 0,
1907
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
1979
+ landingPage: buildLandingPage(ctx, versionSegs),
1908
1980
  announcement: void 0,
1909
1981
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1910
1982
  // The version's full slug roots structural sections so the whole
@@ -1985,34 +2057,41 @@ function crossVersionDedupKeys(node, parents) {
1985
2057
  keys.push([...parentTitles, node.title].join("###"));
1986
2058
  return keys;
1987
2059
  }
1988
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1989
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1990
- if (tablessSegs.length === 0) {
2060
+ function routeToLandingPage(ctx, route) {
2061
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1991
2062
  return void 0;
1992
2063
  }
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
- }
2064
+ const md = route.metadata;
2065
+ const pageId = metaStr(md, "pageId");
2066
+ if (pageId == null) {
2067
+ return void 0;
2014
2068
  }
2015
- return void 0;
2069
+ const slug = ctx.contentSlug(route.fullPath);
2070
+ return {
2071
+ type: "landingPage",
2072
+ ...withMetadataDefaults({
2073
+ id: ctx.nodeId(`landing:${slug}`),
2074
+ title: metaStr(md, "title") ?? "",
2075
+ slug,
2076
+ icon: metaStr(md, "icon"),
2077
+ hidden: route.hidden,
2078
+ authed: metaBool(md, "authed"),
2079
+ viewers: toViewers(metaStrArr(md, "viewers")),
2080
+ orphaned: metaBool(md, "orphaned"),
2081
+ featureFlags: metaFeatureFlags(md)
2082
+ }),
2083
+ pageId: PageId(pageId),
2084
+ noindex: metaBool(md, "noindex")
2085
+ };
2086
+ }
2087
+ function buildLandingPage(ctx, scopeSegs) {
2088
+ const landingSegment = scopeSegs.find(
2089
+ (s) => metaStr(s.seg.metadata, "type") === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true
2090
+ );
2091
+ return routeToLandingPage(
2092
+ ctx,
2093
+ landingSegment?.nav.find((route) => route.type === "markdown")
2094
+ );
2016
2095
  }
2017
2096
  function markCrossVersionCanonicalSlugs(versionNodes) {
2018
2097
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2083,7 +2162,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2083
2162
  type: "productgroup",
2084
2163
  id: ctx.nodeId("productgroup"),
2085
2164
  collapsed: void 0,
2086
- landingPage: void 0,
2165
+ landingPage: buildLandingPage(
2166
+ ctx,
2167
+ scoped.filter((s) => s.seg.product == null)
2168
+ ),
2087
2169
  children
2088
2170
  };
2089
2171
  }