@fern-api/fdr-sdk 1.2.39-38c6f9a29c → 1.2.39-4a89db5dd2

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 (34) hide show
  1. package/dist/js/client/FdrClient.js +28 -7
  2. package/dist/js/client/FdrClient.js.map +1 -1
  3. package/dist/js/client/FdrClient.mjs +28 -7
  4. package/dist/js/client/FdrClient.mjs.map +1 -1
  5. package/dist/js/index.js +28 -7
  6. package/dist/js/index.js.map +1 -1
  7. package/dist/js/index.mjs +28 -7
  8. package/dist/js/index.mjs.map +1 -1
  9. package/dist/js/navigation/ledger-root-builder.js +188 -75
  10. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  11. package/dist/js/navigation/ledger-root-builder.mjs +188 -75
  12. package/dist/js/navigation/ledger-root-builder.mjs.map +1 -1
  13. package/dist/js/orpc-client.js +30 -7
  14. package/dist/js/orpc-client.js.map +1 -1
  15. package/dist/js/orpc-client.mjs +30 -7
  16. package/dist/js/orpc-client.mjs.map +1 -1
  17. package/dist/tsconfig.tsbuildinfo +1 -1
  18. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts +2 -0
  19. package/dist/types/navigation/__test__/ledger-root-builder.apiReferenceChildren.test.d.ts.map +1 -0
  20. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts +2 -0
  21. package/dist/types/navigation/__test__/ledger-root-builder.landingPage.test.d.ts.map +1 -0
  22. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts +2 -0
  23. package/dist/types/navigation/__test__/ledger-root-builder.rootSlug.test.d.ts.map +1 -0
  24. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts +2 -0
  25. package/dist/types/navigation/__test__/ledger-root-builder.skipSlugTabs.test.d.ts.map +1 -0
  26. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts +2 -0
  27. package/dist/types/navigation/__test__/ledger-root-builder.unversionedPointsTo.test.d.ts.map +1 -0
  28. package/dist/types/navigation/ledger-root-builder.d.ts +2 -0
  29. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  30. package/dist/types/orpc-client/docs-ledger/contract.d.ts +2190 -170
  31. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  32. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +3456 -104
  33. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -1
  34. package/package.json +1 -1
@@ -135,6 +135,9 @@ var AuthSchemeIdSchema = z2.string();
135
135
  var SubpackageIdSchema = z2.string();
136
136
  var WebSocketMessageIdSchema = z2.string();
137
137
  var FileIdSchema = z2.string();
138
+ function FileId(value) {
139
+ return value;
140
+ }
138
141
  var MultipleAuthTypeSchema = z2.object({
139
142
  schemes: z2.array(AuthSchemeIdSchema)
140
143
  });
@@ -906,6 +909,13 @@ function metaStrArr(metadata, key) {
906
909
  }
907
910
  return void 0;
908
911
  }
912
+ function metaFeatureFlags(metadata) {
913
+ if (metadata != null && typeof metadata === "object" && "featureFlags" in metadata) {
914
+ const v = metadata.featureFlags;
915
+ return Array.isArray(v) && v.length > 0 ? v : void 0;
916
+ }
917
+ return void 0;
918
+ }
909
919
  function toViewers(viewers) {
910
920
  if (viewers == null || viewers.length === 0) {
911
921
  return void 0;
@@ -941,17 +951,17 @@ function scopeKey(seg) {
941
951
  return [seg.product?.id ?? "", seg.version?.id ?? "", seg.variant?.id ?? "", seg.tab?.id ?? ""].join("|");
942
952
  }
943
953
  function withMetadataDefaults(base) {
944
- const { viewers, ...rest } = base;
954
+ const { viewers, featureFlags, ...rest } = base;
945
955
  return {
946
956
  ...rest,
947
957
  canonicalSlug: void 0,
948
- authed: void 0,
958
+ authed: base.authed === true ? true : void 0,
949
959
  collapsed: void 0,
950
960
  // Normalise empty arrays to undefined so unrestricted nodes don't add
951
961
  // filter-level noise; a non-empty array engages the RBAC view gate.
952
962
  viewers: viewers != null && viewers.length > 0 ? viewers : void 0,
953
- orphaned: void 0,
954
- featureFlags: void 0
963
+ orphaned: base.orphaned === true ? true : void 0,
964
+ featureFlags: featureFlags != null && featureFlags.length > 0 ? featureFlags : void 0
955
965
  };
956
966
  }
957
967
  function artifactToNode(ctx, route) {
@@ -974,7 +984,10 @@ function artifactToNode(ctx, route) {
974
984
  slug,
975
985
  icon,
976
986
  hidden: route.hidden,
977
- viewers
987
+ authed: metaBool(md, "authed"),
988
+ viewers,
989
+ orphaned: metaBool(md, "orphaned"),
990
+ featureFlags: metaFeatureFlags(md)
978
991
  }),
979
992
  pageId: PageId(pageId),
980
993
  noindex: metaBool(md, "noindex"),
@@ -990,7 +1003,7 @@ function artifactToNode(ctx, route) {
990
1003
  title,
991
1004
  icon,
992
1005
  url: Url(metaStr(md, "url") ?? ""),
993
- target: void 0
1006
+ target: metaStr(md, "target")
994
1007
  };
995
1008
  return node;
996
1009
  }
@@ -1025,7 +1038,10 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1025
1038
  slug,
1026
1039
  icon,
1027
1040
  hidden: route.hidden,
1028
- viewers
1041
+ authed: metaBool(md, "authed"),
1042
+ viewers,
1043
+ orphaned: metaBool(md, "orphaned"),
1044
+ featureFlags: metaFeatureFlags(md)
1029
1045
  });
1030
1046
  if (route.type === "rest") {
1031
1047
  const endpointId = metaStr(md, "endpointId");
@@ -1040,7 +1056,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1040
1056
  endpointId: EndpointId(endpointId),
1041
1057
  apiDefinitionId,
1042
1058
  isResponseStream: metaBool(md, "isResponseStream"),
1043
- availability: void 0,
1059
+ availability: metaStr(md, "availability"),
1044
1060
  playground: void 0
1045
1061
  };
1046
1062
  }
@@ -1056,7 +1072,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1056
1072
  method,
1057
1073
  webhookId: WebhookId(webhookId),
1058
1074
  apiDefinitionId,
1059
- availability: void 0
1075
+ availability: metaStr(md, "availability")
1060
1076
  };
1061
1077
  }
1062
1078
  if (route.type === "asyncapi") {
@@ -1069,7 +1085,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1069
1085
  ...meta,
1070
1086
  webSocketId: WebSocketId(webSocketId),
1071
1087
  apiDefinitionId,
1072
- availability: void 0,
1088
+ availability: metaStr(md, "availability"),
1073
1089
  playground: void 0
1074
1090
  };
1075
1091
  }
@@ -1085,7 +1101,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1085
1101
  method,
1086
1102
  grpcId: GrpcId(grpcId),
1087
1103
  apiDefinitionId,
1088
- availability: void 0
1104
+ availability: metaStr(md, "availability")
1089
1105
  };
1090
1106
  }
1091
1107
  if (route.type === "graphql") {
@@ -1101,12 +1117,69 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
1101
1117
  graphqlOperationId: GraphQlOperationId(graphqlOperationId),
1102
1118
  graphqlOperationIds: void 0,
1103
1119
  apiDefinitionId,
1104
- availability: void 0,
1120
+ availability: metaStr(md, "availability"),
1105
1121
  playground: void 0
1106
1122
  };
1107
1123
  }
1108
1124
  return void 0;
1109
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
+ }
1110
1183
  function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
1111
1184
  const ctx = createBuildContext(basePath);
1112
1185
  return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
@@ -1208,17 +1281,22 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1208
1281
  slug,
1209
1282
  icon: metaStr(seg.metadata, "icon"),
1210
1283
  hidden: seg.hidden,
1211
- viewers: mergeVariantViewers(seg)
1284
+ authed: metaBool(seg.metadata, "authed"),
1285
+ viewers: mergeVariantViewers(seg),
1286
+ orphaned: metaBool(seg.metadata, "orphaned"),
1287
+ featureFlags: metaFeatureFlags(seg.metadata)
1212
1288
  });
1213
1289
  return {
1214
1290
  type: "section",
1215
1291
  ...defaults,
1216
- 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,
1217
1295
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1218
- noindex: void 0,
1296
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1219
1297
  collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1220
1298
  collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
1221
- availability: void 0,
1299
+ availability: metaStr(seg.metadata, "availability"),
1222
1300
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1223
1301
  children: mergeChildrenByPosition(ctx, nav, sectionChildren)
1224
1302
  };
@@ -1241,8 +1319,7 @@ function directChildApiPackages(parentSection, scopeSegs) {
1241
1319
  }
1242
1320
  function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1243
1321
  const { seg, nav } = scoped;
1244
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1245
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1322
+ const leafNodes = positionedApiLeafChildren(ctx, nav, apiDefinitionId);
1246
1323
  const childPackages = directChildApiPackages(seg.section, scopeSegs);
1247
1324
  const packageNodes = childPackages.map((child) => ({
1248
1325
  node: apiPackageChildNode(
@@ -1256,18 +1333,10 @@ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix)
1256
1333
  }));
1257
1334
  const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1258
1335
  if (!hasChildIndex) {
1259
- return [...leafNodes, ...packageNodes.map((p) => p.node)];
1260
- }
1261
- const leafPositions = [];
1262
- for (const route of nav) {
1263
- if (route.displaySortOrder != null) {
1264
- leafPositions.push(route.displaySortOrder);
1265
- }
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);
1266
1337
  }
1267
1338
  const positioned = [];
1268
- for (let i = 0; i < leafNodes.length; i++) {
1269
- positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
1270
- }
1339
+ positioned.push(...leafNodes);
1271
1340
  for (const p of packageNodes) {
1272
1341
  positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1273
1342
  }
@@ -1295,12 +1364,15 @@ function apiPackageChildNode(ctx, scoped, scopeSegs, parentApiDefinitionId, scop
1295
1364
  slug,
1296
1365
  icon: metaStr(seg.metadata, "icon"),
1297
1366
  hidden: seg.hidden,
1298
- viewers: toViewers(metaStrArr(seg.metadata, "viewers"))
1367
+ authed: metaBool(seg.metadata, "authed"),
1368
+ viewers: toViewers(metaStrArr(seg.metadata, "viewers")),
1369
+ orphaned: metaBool(seg.metadata, "orphaned"),
1370
+ featureFlags: metaFeatureFlags(seg.metadata)
1299
1371
  }),
1300
1372
  apiDefinitionId: ApiDefinitionId(apiDefinitionId),
1301
1373
  availability: metaStr(seg.metadata, "availability"),
1302
1374
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1303
- noindex: void 0,
1375
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1304
1376
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1305
1377
  children,
1306
1378
  playground: void 0
@@ -1380,12 +1452,15 @@ function apiReferenceNode(ctx, scoped, scopeSegs, scopePrefix) {
1380
1452
  slug,
1381
1453
  icon: metaStr(seg.metadata, "icon"),
1382
1454
  hidden: seg.hidden,
1383
- viewers: mergeVariantViewers(seg)
1455
+ authed: metaBool(seg.metadata, "authed"),
1456
+ viewers: mergeVariantViewers(seg),
1457
+ orphaned: metaBool(seg.metadata, "orphaned"),
1458
+ featureFlags: metaFeatureFlags(seg.metadata)
1384
1459
  }),
1385
1460
  apiDefinitionId: ApiDefinitionId(apiDefinitionId),
1386
- availability: void 0,
1461
+ availability: metaStr(seg.metadata, "availability"),
1387
1462
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1388
- noindex: void 0,
1463
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1389
1464
  paginated: true,
1390
1465
  showErrors: metaBool(seg.metadata, "showErrors"),
1391
1466
  hideTitle: metaBool(seg.metadata, "hideTitle"),
@@ -1438,10 +1513,13 @@ function changelogNode(ctx, scoped, scopePrefix) {
1438
1513
  slug: ctx.contentSlug(r.fullPath ?? ""),
1439
1514
  icon: metaStr(r.metadata, "icon"),
1440
1515
  hidden: r.hidden,
1441
- viewers: toViewers(metaStrArr(r.metadata, "viewers"))
1516
+ authed: metaBool(r.metadata, "authed"),
1517
+ viewers: toViewers(metaStrArr(r.metadata, "viewers")),
1518
+ orphaned: metaBool(r.metadata, "orphaned"),
1519
+ featureFlags: metaFeatureFlags(r.metadata)
1442
1520
  }),
1443
1521
  pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1444
- noindex: void 0,
1522
+ noindex: metaBool(r.metadata, "noindex"),
1445
1523
  date: dateStr ?? "",
1446
1524
  tags: void 0
1447
1525
  };
@@ -1487,10 +1565,13 @@ function changelogNode(ctx, scoped, scopePrefix) {
1487
1565
  slug: baseSlug,
1488
1566
  icon: metaStr(seg.metadata, "icon"),
1489
1567
  hidden: seg.hidden,
1490
- viewers: mergeVariantViewers(seg)
1568
+ authed: metaBool(seg.metadata, "authed"),
1569
+ viewers: mergeVariantViewers(seg),
1570
+ orphaned: metaBool(seg.metadata, "orphaned"),
1571
+ featureFlags: metaFeatureFlags(seg.metadata)
1491
1572
  }),
1492
1573
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
1493
- noindex: void 0,
1574
+ noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
1494
1575
  children: years
1495
1576
  };
1496
1577
  }
@@ -1558,6 +1639,9 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
1558
1639
  if (hasOwningApiReference(s, scopeSegs)) {
1559
1640
  continue;
1560
1641
  }
1642
+ if (type === "tabRoot" && metaBool(s.seg.metadata, "landingPage") === true) {
1643
+ continue;
1644
+ }
1561
1645
  if (type === "tabRoot" || sec === "" && type !== "section") {
1562
1646
  for (const r of s.nav) {
1563
1647
  const node = artifactToNode(ctx, r);
@@ -1644,13 +1728,13 @@ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1644
1728
  };
1645
1729
  }
1646
1730
  function buildFullRootFromSegments(options) {
1647
- const { basePath, title, segments, navBySegment } = options;
1731
+ const { basePath, rootSlug: sourceRootSlug, title, segments, navBySegment } = options;
1648
1732
  const ctx = createBuildContext(basePath);
1649
1733
  const scoped = segments.filter((seg) => {
1650
1734
  const t = metaStr(seg.metadata, "type");
1651
1735
  return t !== "files" && t !== "redirects";
1652
1736
  }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1653
- const rootSlug = asSlug(basePath);
1737
+ const rootSlug = asSlug(sourceRootSlug ?? basePath);
1654
1738
  const scopesByKey = /* @__PURE__ */ new Map();
1655
1739
  for (const s of scoped) {
1656
1740
  const key = scopeKey(s.seg);
@@ -1676,6 +1760,24 @@ function buildFullRootFromSegments(options) {
1676
1760
  } else if (child.type === "versioned") {
1677
1761
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1678
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
+ }
1679
1781
  }
1680
1782
  const root = {
1681
1783
  type: "root",
@@ -1688,21 +1790,22 @@ function buildFullRootFromSegments(options) {
1688
1790
  return root;
1689
1791
  }
1690
1792
  function uniqueDetails(scoped, dim) {
1691
- const bySlug = /* @__PURE__ */ new Map();
1793
+ const byKey = /* @__PURE__ */ new Map();
1692
1794
  for (const s of scoped) {
1693
1795
  const d = s.seg[dim];
1694
1796
  if (d == null) {
1695
1797
  continue;
1696
1798
  }
1697
1799
  const slug = detailSlug(d);
1698
- const existing = bySlug.get(slug);
1800
+ const key = dim === "tab" ? d.id : slug !== "" ? slug : d.id;
1801
+ const existing = byKey.get(key);
1699
1802
  if (existing == null) {
1700
- bySlug.set(slug, d);
1803
+ byKey.set(key, d);
1701
1804
  } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1702
- bySlug.set(slug, d);
1805
+ byKey.set(key, d);
1703
1806
  }
1704
1807
  }
1705
- return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1808
+ return [...byKey.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1706
1809
  }
1707
1810
  function scopeSlugPrefix(rootSlug, ...details) {
1708
1811
  const parts = [rootSlug];
@@ -1736,7 +1839,7 @@ function buildVariantedNode(ctx, variants, scopeSegs, scopePrefix) {
1736
1839
  default: detailIsDefault(variant),
1737
1840
  variantId: VariantId(String(variant.id)),
1738
1841
  subtitle: metaStr(variant.metadata, "subtitle") ?? void 0,
1739
- image: void 0,
1842
+ image: metaStr(variant.metadata, "image") != null ? FileId(metaStr(variant.metadata, "image")) : void 0,
1740
1843
  pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1741
1844
  children
1742
1845
  };
@@ -1785,7 +1888,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1785
1888
  title: tab.displayName,
1786
1889
  icon: tab.icon ?? void 0,
1787
1890
  url: Url(metaStr(tab.metadata, "url") ?? ""),
1788
- target: void 0
1891
+ target: metaStr(tab.metadata, "target")
1789
1892
  };
1790
1893
  }
1791
1894
  if (tabType === "changelog") {
@@ -1846,7 +1949,7 @@ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1846
1949
  type: "unversioned",
1847
1950
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1848
1951
  collapsed: void 0,
1849
- landingPage: void 0,
1952
+ landingPage: buildLandingPage(ctx, scopeSegs),
1850
1953
  // The enclosing scope prefix (product slug, or rootSlug at the top
1851
1954
  // level) roots structural sections so they share the scope's slug
1852
1955
  // namespace.
@@ -1873,7 +1976,7 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1873
1976
  default: detailIsDefault(version),
1874
1977
  versionId: VersionId(version.id),
1875
1978
  availability: void 0,
1876
- landingPage: buildVersionLandingPage(ctx, versionSegs, asSlug(slug)),
1979
+ landingPage: buildLandingPage(ctx, versionSegs),
1877
1980
  announcement: void 0,
1878
1981
  pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1879
1982
  // The version's full slug roots structural sections so the whole
@@ -1954,34 +2057,41 @@ function crossVersionDedupKeys(node, parents) {
1954
2057
  keys.push([...parentTitles, node.title].join("###"));
1955
2058
  return keys;
1956
2059
  }
1957
- function buildVersionLandingPage(ctx, versionSegs, versionSlug) {
1958
- const tablessSegs = versionSegs.filter((s) => s.seg.tab == null);
1959
- if (tablessSegs.length === 0) {
2060
+ function routeToLandingPage(ctx, route) {
2061
+ if (route == null || route.type !== "markdown" || route.fullPath == null) {
1960
2062
  return void 0;
1961
2063
  }
1962
- for (const s of tablessSegs) {
1963
- for (const r of s.nav) {
1964
- if (r.type === "markdown" && r.fullPath != null) {
1965
- const md = r.metadata;
1966
- const pageId = metaStr(md, "pageId") ?? "";
1967
- const slug = ctx.contentSlug(r.fullPath);
1968
- return {
1969
- type: "landingPage",
1970
- ...withMetadataDefaults({
1971
- id: ctx.nodeId(`landing:${slug}`),
1972
- title: metaStr(md, "title") ?? "",
1973
- slug,
1974
- icon: metaStr(md, "icon"),
1975
- hidden: r.hidden,
1976
- viewers: toViewers(metaStrArr(md, "viewers"))
1977
- }),
1978
- pageId: PageId(pageId),
1979
- noindex: metaBool(md, "noindex")
1980
- };
1981
- }
1982
- }
2064
+ const md = route.metadata;
2065
+ const pageId = metaStr(md, "pageId");
2066
+ if (pageId == null) {
2067
+ return void 0;
1983
2068
  }
1984
- 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
+ );
1985
2095
  }
1986
2096
  function markCrossVersionCanonicalSlugs(versionNodes) {
1987
2097
  const keyToCanonical = /* @__PURE__ */ new Map();
@@ -2041,7 +2151,7 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2041
2151
  // here; sourcing it from the hash makes that filter match nothing.
2042
2152
  productId: ProductId(product.displayName),
2043
2153
  subtitle: metaStr(product.metadata, "subtitle") ?? "",
2044
- image: void 0,
2154
+ image: metaStr(product.metadata, "image") != null ? FileId(metaStr(product.metadata, "image")) : void 0,
2045
2155
  announcement: void 0,
2046
2156
  pointsTo: metaStr(product.metadata, "pointsTo") != null ? pointsToSlug(metaStr(product.metadata, "pointsTo")) : void 0,
2047
2157
  child: productChild
@@ -2052,7 +2162,10 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
2052
2162
  type: "productgroup",
2053
2163
  id: ctx.nodeId("productgroup"),
2054
2164
  collapsed: void 0,
2055
- landingPage: void 0,
2165
+ landingPage: buildLandingPage(
2166
+ ctx,
2167
+ scoped.filter((s) => s.seg.product == null)
2168
+ ),
2056
2169
  children
2057
2170
  };
2058
2171
  }