@fern-api/fdr-sdk 1.2.36-eaea1f74f7 → 1.2.37-94cc3f83f5

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 (52) hide show
  1. package/dist/js/client/FdrClient.js +315 -55
  2. package/dist/js/client/FdrClient.js.map +1 -1
  3. package/dist/js/client/FdrClient.mjs +315 -55
  4. package/dist/js/client/FdrClient.mjs.map +1 -1
  5. package/dist/js/index.js +320 -60
  6. package/dist/js/index.js.map +1 -1
  7. package/dist/js/index.mjs +320 -60
  8. package/dist/js/index.mjs.map +1 -1
  9. package/dist/js/navigation/ledger-root-builder.js +732 -249
  10. package/dist/js/navigation/ledger-root-builder.js.map +1 -1
  11. package/dist/js/navigation/ledger-root-builder.mjs +730 -249
  12. package/dist/js/navigation/ledger-root-builder.mjs.map +1 -1
  13. package/dist/js/orpc-client.js +759 -91
  14. package/dist/js/orpc-client.js.map +1 -1
  15. package/dist/js/orpc-client.mjs +715 -86
  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.changelogSlug.test.d.ts +2 -0
  19. package/dist/types/navigation/__test__/ledger-root-builder.changelogSlug.test.d.ts.map +1 -0
  20. package/dist/types/navigation/__test__/ledger-root-builder.defaultVersionElision.test.d.ts +2 -0
  21. package/dist/types/navigation/__test__/ledger-root-builder.defaultVersionElision.test.d.ts.map +1 -0
  22. package/dist/types/navigation/__test__/ledger-root-builder.linkRepro.test.d.ts +2 -0
  23. package/dist/types/navigation/__test__/ledger-root-builder.linkRepro.test.d.ts.map +1 -0
  24. package/dist/types/navigation/__test__/ledger-root-builder.mergeEndpointPairs.test.d.ts +2 -0
  25. package/dist/types/navigation/__test__/ledger-root-builder.mergeEndpointPairs.test.d.ts.map +1 -0
  26. package/dist/types/navigation/__test__/ledger-root-builder.pointsTo.test.d.ts +2 -0
  27. package/dist/types/navigation/__test__/ledger-root-builder.pointsTo.test.d.ts.map +1 -0
  28. package/dist/types/navigation/__test__/ledger-root-builder.productId.test.d.ts +2 -0
  29. package/dist/types/navigation/__test__/ledger-root-builder.productId.test.d.ts.map +1 -0
  30. package/dist/types/navigation/__test__/ledger-root-builder.rootChildOrder.test.d.ts +2 -0
  31. package/dist/types/navigation/__test__/ledger-root-builder.rootChildOrder.test.d.ts.map +1 -0
  32. package/dist/types/navigation/__test__/ledger-root-builder.rootSectionSlug.test.d.ts +2 -0
  33. package/dist/types/navigation/__test__/ledger-root-builder.rootSectionSlug.test.d.ts.map +1 -0
  34. package/dist/types/navigation/__test__/ledger-root-builder.tabSlug.test.d.ts +2 -0
  35. package/dist/types/navigation/__test__/ledger-root-builder.tabSlug.test.d.ts.map +1 -0
  36. package/dist/types/navigation/ledger-root-builder.d.ts +26 -3
  37. package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
  38. package/dist/types/orpc-client/client.d.ts +1 -2
  39. package/dist/types/orpc-client/client.d.ts.map +1 -1
  40. package/dist/types/orpc-client/docs-ledger/client.d.ts +1 -3
  41. package/dist/types/orpc-client/docs-ledger/client.d.ts.map +1 -1
  42. package/dist/types/orpc-client/docs-ledger/config-files.d.ts +16 -0
  43. package/dist/types/orpc-client/docs-ledger/config-files.d.ts.map +1 -0
  44. package/dist/types/orpc-client/docs-ledger/contract.d.ts +60922 -47158
  45. package/dist/types/orpc-client/docs-ledger/contract.d.ts.map +1 -1
  46. package/dist/types/orpc-client/docs-ledger/index.d.ts +3 -0
  47. package/dist/types/orpc-client/docs-ledger/index.d.ts.map +1 -1
  48. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts +37008 -0
  49. package/dist/types/orpc-client/docs-ledger/ledger-manifest.d.ts.map +1 -0
  50. package/dist/types/orpc-client/docs-ledger/stable-stringify.d.ts +18 -0
  51. package/dist/types/orpc-client/docs-ledger/stable-stringify.d.ts.map +1 -0
  52. package/package.json +1 -1
@@ -596,6 +596,82 @@ function NodeId(value) {
596
596
  function ProductId(value) {
597
597
  return value;
598
598
  }
599
+ function VariantId(value) {
600
+ return value;
601
+ }
602
+
603
+ // src/navigation/versions/latest/getChildren.ts
604
+ import { UnreachableCaseError } from "ts-essentials";
605
+
606
+ // src/navigation/versions/latest/NavigationNodeApiLeaf.ts
607
+ function isApiLeaf(node) {
608
+ return node.type === "endpoint" || node.type === "webSocket" || node.type === "webhook" || node.type === "grpc" || node.type === "graphql" || node.type === "graphqlType";
609
+ }
610
+
611
+ // src/navigation/versions/latest/NavigationNodePageLeaf.ts
612
+ function isMarkdownLeaf(node) {
613
+ return node.type === "page" || node.type === "landingPage" || node.type === "changelogEntry";
614
+ }
615
+
616
+ // src/navigation/versions/latest/NavigationNodeLeaf.ts
617
+ function isLeaf(node) {
618
+ return isApiLeaf(node) || isMarkdownLeaf(node) || node.type === "link";
619
+ }
620
+
621
+ // src/navigation/versions/latest/getChildren.ts
622
+ function getChildren(node) {
623
+ if (isLeaf(node)) {
624
+ return [];
625
+ }
626
+ switch (node.type) {
627
+ case "apiPackage":
628
+ case "changelog":
629
+ case "changelogMonth":
630
+ case "changelogYear":
631
+ case "section":
632
+ case "sidebarGroup":
633
+ case "sidebarRoot":
634
+ case "tabbed":
635
+ case "versioned":
636
+ case "varianted":
637
+ return node.children;
638
+ case "product":
639
+ case "root":
640
+ case "tab":
641
+ return [node.child];
642
+ case "productLink":
643
+ return [];
644
+ case "variant":
645
+ return node.children;
646
+ case "apiReference":
647
+ return [...node.children, ...node.changelog ? [node.changelog] : []];
648
+ case "endpointPair":
649
+ return [node.nonStream, node.stream];
650
+ case "productgroup":
651
+ return [...node.landingPage ? [node.landingPage] : [], ...node.children];
652
+ case "unversioned":
653
+ case "version":
654
+ return [...node.landingPage ? [node.landingPage] : [], node.child];
655
+ default:
656
+ throw new UnreachableCaseError(node);
657
+ }
658
+ }
659
+
660
+ // src/navigation/versions/latest/NavigationNodeWithMetadata.ts
661
+ function hasMetadata(node) {
662
+ return typeof node.title === "string" && typeof node.slug === "string";
663
+ }
664
+
665
+ // src/navigation/versions/latest/NavigationNodeWithRedirect.ts
666
+ function hasPointsTo(node) {
667
+ return node.type === "root" || node.type === "product" || node.type === "version" || node.type === "tab" || node.type === "section" || node.type === "apiReference" || node.type === "apiPackage";
668
+ }
669
+ function hasRedirect(node) {
670
+ if (!hasPointsTo(node)) {
671
+ return false;
672
+ }
673
+ return node.pointsTo != null;
674
+ }
599
675
 
600
676
  // ../commons/core-utils/dist/isNonNullish.js
601
677
  function isNonNullish(x) {
@@ -611,10 +687,50 @@ function slugjoin(...parts) {
611
687
  return Slug(normalized);
612
688
  }
613
689
 
690
+ // src/navigation/versions/latest/toDefaultSlug.ts
691
+ import { escapeRegExp } from "es-toolkit/string";
692
+ function toDefaultSlug(slug, rootSlug, versionSlug) {
693
+ if (slug == null) {
694
+ return void 0;
695
+ }
696
+ if (slug.startsWith(versionSlug)) {
697
+ return Slug(slug.replace(new RegExp(`^${escapeRegExp(versionSlug)}`), rootSlug).replace(/^\//, ""));
698
+ }
699
+ return slug;
700
+ }
701
+
702
+ // src/utils/traversers/types.ts
703
+ var SKIP = "skip";
704
+ var STOP = false;
705
+
706
+ // src/utils/traversers/dfs.ts
707
+ function dfs(root, visit, getChildren2, isParent = (node) => true) {
708
+ const stack = [[root, []]];
709
+ while (stack.length > 0) {
710
+ const [node, parents] = stack.pop() ?? [];
711
+ if (!node) {
712
+ continue;
713
+ }
714
+ const next = visit(node, parents ?? []);
715
+ if (next === SKIP) {
716
+ continue;
717
+ } else if (next === STOP) {
718
+ return;
719
+ }
720
+ if (isParent(node)) {
721
+ for (const child of [...getChildren2(node)].reverse()) {
722
+ stack.push([child, [...parents ?? [], node]]);
723
+ }
724
+ }
725
+ }
726
+ }
727
+
728
+ // src/navigation/versions/latest/traverseDF.ts
729
+ function traverseDF(node, visit) {
730
+ return dfs(node, visit, getChildren);
731
+ }
732
+
614
733
  // src/navigation/ledger-root-builder.ts
615
- var segMeta = (seg) => seg.metadata ?? {};
616
- var routeMeta = (route) => route.metadata ?? {};
617
- var detailMeta = (detail) => detail.metadata ?? {};
618
734
  function createBuildContext(basePath) {
619
735
  const seen = /* @__PURE__ */ new Map();
620
736
  const basePrefix = basePath.replace(/^\/+|\/+$/g, "");
@@ -633,6 +749,51 @@ function createBuildContext(basePath) {
633
749
  function asSlug(path) {
634
750
  return Slug(path.replace(/^\/+|\/+$/g, ""));
635
751
  }
752
+ function pointsToSlug(metaPointsTo) {
753
+ return asSlug(metaPointsTo);
754
+ }
755
+ function metaStr(metadata, key) {
756
+ if (metadata != null && typeof metadata === "object" && key in metadata) {
757
+ const v = metadata[key];
758
+ return typeof v === "string" ? v : void 0;
759
+ }
760
+ return void 0;
761
+ }
762
+ function metaBool(metadata, key) {
763
+ if (metadata != null && typeof metadata === "object" && key in metadata) {
764
+ const v = metadata[key];
765
+ return typeof v === "boolean" ? v : void 0;
766
+ }
767
+ return void 0;
768
+ }
769
+ function metaNum(metadata, key) {
770
+ if (metadata != null && typeof metadata === "object" && key in metadata) {
771
+ const v = metadata[key];
772
+ return typeof v === "number" ? v : void 0;
773
+ }
774
+ return void 0;
775
+ }
776
+ function metaCollapsed(metadata) {
777
+ if (metadata != null && typeof metadata === "object" && "collapsed" in metadata) {
778
+ const v = metadata.collapsed;
779
+ if (typeof v === "boolean") {
780
+ return v;
781
+ }
782
+ if (v === "open-by-default") {
783
+ return "open-by-default";
784
+ }
785
+ }
786
+ return void 0;
787
+ }
788
+ function metaStrArr(metadata, key) {
789
+ if (metadata != null && typeof metadata === "object" && key in metadata) {
790
+ const v = metadata[key];
791
+ if (Array.isArray(v)) {
792
+ return v.filter((x) => typeof x === "string");
793
+ }
794
+ }
795
+ return void 0;
796
+ }
636
797
  function toViewers(viewers) {
637
798
  if (viewers == null || viewers.length === 0) {
638
799
  return void 0;
@@ -640,17 +801,29 @@ function toViewers(viewers) {
640
801
  return viewers.map((v) => RoleId(v));
641
802
  }
642
803
  function mergeVariantViewers(seg) {
643
- const all = [...segMeta(seg).viewers ?? [], ...seg.variant?.viewers ?? []];
644
- return all.length > 0 ? [...new Set(all)].map((v) => RoleId(v)) : void 0;
804
+ const segViewers = seg.metadata.type === "section" || seg.metadata.type === "apiReference" || seg.metadata.type === "apiPackage" || seg.metadata.type === "changelog" ? seg.metadata.viewers : void 0;
805
+ const variantViewers = seg.variant?.viewers;
806
+ if ((segViewers == null || segViewers.length === 0) && (variantViewers == null || variantViewers.length === 0)) {
807
+ return void 0;
808
+ }
809
+ const merged = /* @__PURE__ */ new Set();
810
+ if (segViewers != null) {
811
+ for (const v of segViewers) {
812
+ merged.add(v);
813
+ }
814
+ }
815
+ if (variantViewers != null) {
816
+ for (const v of variantViewers) {
817
+ merged.add(v);
818
+ }
819
+ }
820
+ return merged.size > 0 ? [...merged].map((v) => RoleId(v)) : void 0;
645
821
  }
646
822
  function detailSlug(detail) {
647
- return detailMeta(detail).slug ?? "";
823
+ return detail.metadata?.slug ?? "";
648
824
  }
649
825
  function detailIsDefault(detail) {
650
- return detailMeta(detail).default ?? false;
651
- }
652
- function pointsToSlug(ctx, meta) {
653
- return meta.pointsTo != null ? ctx.contentSlug(meta.pointsTo) : void 0;
826
+ return detail.metadata?.default ?? false;
654
827
  }
655
828
  function scopeKey(seg) {
656
829
  return [seg.product?.id ?? "", seg.version?.id ?? "", seg.variant?.id ?? "", seg.tab?.id ?? ""].join("|");
@@ -670,226 +843,347 @@ function withMetadataDefaults(base) {
670
843
  };
671
844
  }
672
845
  function artifactToNode(ctx, route) {
673
- const md = routeMeta(route);
846
+ const md = route.metadata;
847
+ const title = metaStr(md, "title") ?? "";
848
+ const icon = metaStr(md, "icon");
849
+ const viewers = toViewers(metaStrArr(md, "viewers"));
674
850
  const slug = ctx.contentSlug(route.fullPath ?? "");
675
851
  switch (route.type) {
676
852
  case "markdown": {
677
- if (md.isOverview) {
853
+ if (metaBool(md, "isOverview")) {
678
854
  return void 0;
679
855
  }
680
- return {
856
+ const pageId = metaStr(md, "pageId") ?? "";
857
+ const node = {
681
858
  type: "page",
682
859
  ...withMetadataDefaults({
683
860
  id: ctx.nodeId(`page:${slug}`),
684
- title: md.title ?? "",
861
+ title,
685
862
  slug,
686
- icon: md.icon,
863
+ icon,
687
864
  hidden: route.hidden,
688
- viewers: toViewers(md.viewers)
865
+ viewers
689
866
  }),
690
- pageId: PageId(md.pageId ?? ""),
691
- noindex: md.noindex,
867
+ pageId: PageId(pageId),
868
+ noindex: metaBool(md, "noindex"),
692
869
  availability: void 0
693
870
  };
871
+ return node;
694
872
  }
695
873
  case "link": {
696
- return {
874
+ const node = {
697
875
  type: "link",
698
- id: ctx.nodeId(`link:${md.url ?? route.fullPath ?? ""}`),
876
+ id: ctx.nodeId(`link:${metaStr(md, "url") ?? route.fullPath ?? ""}`),
699
877
  collapsed: void 0,
700
- title: md.title ?? "",
701
- icon: md.icon,
702
- url: Url(md.url ?? ""),
878
+ title,
879
+ icon,
880
+ url: Url(metaStr(md, "url") ?? ""),
703
881
  target: void 0
704
882
  };
883
+ return node;
705
884
  }
706
885
  // API leaf types are handled by apiReferenceNode (which calls
707
886
  // apiLeafNodeFromNavRouteInternal), not by section-level artifact
708
887
  // conversion. Returning undefined here prevents them from appearing
709
888
  // as duplicate siblings alongside the apiReference node.
889
+ case "rest":
890
+ case "asyncapi":
891
+ case "webhook":
892
+ case "grpc":
893
+ case "graphql":
894
+ return void 0;
710
895
  default:
711
896
  return void 0;
712
897
  }
713
898
  }
714
- function apiLeafNodeFromNavRoute(route, basePath, segmentApiDefId) {
899
+ function apiLeafNodeFromNavRoute(route, basePath, segmentApiDefinitionId2) {
715
900
  const ctx = createBuildContext(basePath);
716
- return apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefId);
901
+ return apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2);
717
902
  }
718
- function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefId) {
719
- const md = routeMeta(route);
903
+ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2) {
904
+ const md = route.metadata;
905
+ const apiDefinitionId = ApiDefinitionId(metaStr(md, "apiDefinitionId") ?? segmentApiDefinitionId2);
720
906
  const slug = ctx.contentSlug(route.fullPath ?? "");
721
- const base = {
722
- ...withMetadataDefaults({
723
- id: ctx.nodeId(`api-leaf:${slug}`),
724
- title: md.title ?? "",
725
- slug,
726
- icon: md.icon,
727
- hidden: route.hidden,
728
- viewers: toViewers(md.viewers)
729
- }),
730
- apiDefinitionId: ApiDefinitionId(md.apiDefinitionId ?? segmentApiDefId),
731
- availability: void 0
732
- };
733
- switch (route.type) {
734
- case "rest":
735
- if (md.endpointId == null || md.method == null) {
736
- return void 0;
737
- }
738
- return {
739
- type: "endpoint",
740
- ...base,
741
- method: md.method,
742
- endpointId: EndpointId(md.endpointId),
743
- isResponseStream: md.isResponseStream,
744
- playground: void 0
745
- };
746
- case "webhook":
747
- if (md.webhookId == null || md.method == null) {
748
- return void 0;
749
- }
750
- return {
751
- type: "webhook",
752
- ...base,
753
- method: md.method,
754
- webhookId: WebhookId(md.webhookId)
755
- };
756
- case "asyncapi":
757
- if (md.webSocketId == null) {
758
- return void 0;
759
- }
760
- return {
761
- type: "webSocket",
762
- ...base,
763
- webSocketId: WebSocketId(md.webSocketId),
764
- playground: void 0
765
- };
766
- case "grpc":
767
- if (md.grpcId == null || md.method == null) {
768
- return void 0;
769
- }
770
- return {
771
- type: "grpc",
772
- ...base,
773
- method: md.method,
774
- grpcId: GrpcId(md.grpcId)
775
- };
776
- case "graphql":
777
- if (md.graphqlOperationId == null || md.operationType == null) {
778
- return void 0;
779
- }
780
- return {
781
- type: "graphql",
782
- ...base,
783
- operationType: md.operationType,
784
- graphqlOperationId: GraphQlOperationId(md.graphqlOperationId),
785
- graphqlOperationIds: void 0,
786
- playground: void 0
787
- };
788
- default:
907
+ const title = metaStr(md, "title") ?? "";
908
+ const icon = metaStr(md, "icon");
909
+ const viewers = toViewers(metaStrArr(md, "viewers"));
910
+ const meta = withMetadataDefaults({
911
+ id: ctx.nodeId(`api-leaf:${slug}`),
912
+ title,
913
+ slug,
914
+ icon,
915
+ hidden: route.hidden,
916
+ viewers
917
+ });
918
+ if (route.type === "rest") {
919
+ const endpointId = metaStr(md, "endpointId");
920
+ const method = metaStr(md, "method");
921
+ if (endpointId == null || method == null) {
922
+ return void 0;
923
+ }
924
+ return {
925
+ type: "endpoint",
926
+ ...meta,
927
+ method,
928
+ endpointId: EndpointId(endpointId),
929
+ apiDefinitionId,
930
+ isResponseStream: metaBool(md, "isResponseStream"),
931
+ availability: void 0,
932
+ playground: void 0
933
+ };
934
+ }
935
+ if (route.type === "webhook") {
936
+ const webhookId = metaStr(md, "webhookId");
937
+ const method = metaStr(md, "method");
938
+ if (webhookId == null || method == null) {
939
+ return void 0;
940
+ }
941
+ return {
942
+ type: "webhook",
943
+ ...meta,
944
+ method,
945
+ webhookId: WebhookId(webhookId),
946
+ apiDefinitionId,
947
+ availability: void 0
948
+ };
949
+ }
950
+ if (route.type === "asyncapi") {
951
+ const webSocketId = metaStr(md, "webSocketId");
952
+ if (webSocketId == null) {
953
+ return void 0;
954
+ }
955
+ return {
956
+ type: "webSocket",
957
+ ...meta,
958
+ webSocketId: WebSocketId(webSocketId),
959
+ apiDefinitionId,
960
+ availability: void 0,
961
+ playground: void 0
962
+ };
963
+ }
964
+ if (route.type === "grpc") {
965
+ const grpcId = metaStr(md, "grpcId");
966
+ const method = metaStr(md, "method");
967
+ if (grpcId == null || method == null) {
968
+ return void 0;
969
+ }
970
+ return {
971
+ type: "grpc",
972
+ ...meta,
973
+ method,
974
+ grpcId: GrpcId(grpcId),
975
+ apiDefinitionId,
976
+ availability: void 0
977
+ };
978
+ }
979
+ if (route.type === "graphql") {
980
+ const graphqlOperationId = metaStr(md, "graphqlOperationId");
981
+ const operationType = metaStr(md, "operationType");
982
+ if (graphqlOperationId == null || operationType == null) {
789
983
  return void 0;
984
+ }
985
+ return {
986
+ type: "graphql",
987
+ ...meta,
988
+ operationType,
989
+ graphqlOperationId: GraphQlOperationId(graphqlOperationId),
990
+ graphqlOperationIds: void 0,
991
+ apiDefinitionId,
992
+ availability: void 0,
993
+ playground: void 0
994
+ };
790
995
  }
996
+ return void 0;
791
997
  }
792
- function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefId) {
998
+ function collectApiLeafNodesFromNav(routes, basePath, segmentApiDefinitionId2) {
793
999
  const ctx = createBuildContext(basePath);
794
- return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefId)).filter((node) => node != null);
1000
+ return routes.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId2)).filter((node) => node != null);
795
1001
  }
796
1002
  function segmentApiDefinitionId(metadata) {
797
- return metadata?.apiDefinitionId;
1003
+ switch (metadata.type) {
1004
+ case "apiReference":
1005
+ case "apiPackage":
1006
+ case "changelog":
1007
+ return metadata.apiDefinitionId;
1008
+ default:
1009
+ return void 0;
1010
+ }
798
1011
  }
799
1012
  function overviewRoute(nav) {
1013
+ return nav.find((r) => r.type === "markdown" && metaBool(r.metadata, "isOverview"));
1014
+ }
1015
+ function overviewRouteFromSegmentMeta(seg, nav) {
1016
+ const overviewPageId = metaStr(seg.metadata, "overviewPageId");
1017
+ if (overviewPageId == null) {
1018
+ return void 0;
1019
+ }
1020
+ return nav.find((r) => metaStr(r.metadata, "pageId") === overviewPageId);
1021
+ }
1022
+ function inferSectionSlugFromNav(ctx, nav, scopePrefix) {
1023
+ const scopeStr = String(scopePrefix);
1024
+ const prefix = scopeStr !== "" ? scopeStr + "/" : "";
800
1025
  for (const r of nav) {
801
- if (r.type === "markdown") {
802
- const meta = routeMeta(r);
803
- if (meta.isOverview) {
804
- return { route: r, meta };
805
- }
1026
+ if (r.fullPath == null) {
1027
+ continue;
1028
+ }
1029
+ if (r.type !== "markdown" && r.type !== "page") {
1030
+ continue;
1031
+ }
1032
+ const contentSlug = String(ctx.contentSlug(r.fullPath));
1033
+ const rel = prefix !== "" ? contentSlug.startsWith(prefix) ? contentSlug.slice(prefix.length) : null : contentSlug;
1034
+ if (rel == null) {
1035
+ continue;
1036
+ }
1037
+ const parts = rel.split("/");
1038
+ if (parts.length >= 2 && parts[0] !== "") {
1039
+ return slugjoin(scopePrefix, parts[0]);
806
1040
  }
807
1041
  }
808
1042
  return void 0;
809
1043
  }
810
- function sectionNode(ctx, scoped, sectionChildren) {
811
- const { seg, meta: sm, nav } = scoped;
812
- const overview = overviewRoute(nav);
813
- const overviewPageId = overview?.meta.pageId;
814
- const slug = ctx.contentSlug(overview?.route.fullPath ?? seg.section);
815
- const leafChildren = nav.map((r) => artifactToNode(ctx, r)).filter((n) => n != null);
1044
+ function structuralNodeSlug(ctx, overviewFullPath, section, scopePrefix) {
1045
+ if (overviewFullPath != null) {
1046
+ return ctx.contentSlug(overviewFullPath);
1047
+ }
1048
+ return section !== "" ? slugjoin(scopePrefix, section) : scopePrefix;
1049
+ }
1050
+ function stripLeadingScopePrefix(section, scopePrefix) {
1051
+ const prefix = scopePrefix;
1052
+ if (prefix === "") {
1053
+ return section;
1054
+ }
1055
+ if (section === prefix) {
1056
+ return "";
1057
+ }
1058
+ if (section.startsWith(prefix + "/")) {
1059
+ return section.slice(prefix.length + 1);
1060
+ }
1061
+ return section;
1062
+ }
1063
+ function mergeChildrenByPosition(ctx, nav, sectionChildren) {
1064
+ const leafNodes = [];
1065
+ for (let i = 0; i < nav.length; i++) {
1066
+ const route = nav[i];
1067
+ const node = artifactToNode(ctx, route);
1068
+ if (node != null) {
1069
+ leafNodes.push({ node, pos: route.displaySortOrder ?? i });
1070
+ }
1071
+ }
1072
+ const hasChildIndex = sectionChildren.some((s) => s.childIndex != null);
1073
+ if (!hasChildIndex) {
1074
+ return [...leafNodes.map((l) => l.node), ...sectionChildren.map((s) => s.node)];
1075
+ }
1076
+ const positioned = [...leafNodes];
1077
+ for (const s of sectionChildren) {
1078
+ positioned.push({ node: s.node, pos: s.childIndex ?? Number.MAX_SAFE_INTEGER });
1079
+ }
1080
+ positioned.sort((a, b) => a.pos - b.pos);
1081
+ return positioned.map((p) => p.node);
1082
+ }
1083
+ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
1084
+ const { seg, nav } = scoped;
1085
+ const overview = overviewRoute(nav) ?? overviewRouteFromSegmentMeta(seg, nav);
1086
+ const overviewPageId = overview != null ? metaStr(overview.metadata, "pageId") : void 0;
1087
+ let slug = structuralNodeSlug(ctx, overview?.fullPath, seg.section, scopePrefix);
1088
+ if (seg.section === "" && overview?.fullPath == null) {
1089
+ slug = inferSectionSlugFromNav(ctx, nav, scopePrefix) ?? slug;
1090
+ }
1091
+ const metaPointsTo = metaStr(seg.metadata, "pointsTo");
816
1092
  const defaults = withMetadataDefaults({
817
1093
  id: ctx.nodeId(`section:${slug}`),
818
- title: sm.title ?? "",
1094
+ title: metaStr(seg.metadata, "title") ?? "",
819
1095
  slug,
820
- icon: sm.icon,
1096
+ icon: metaStr(seg.metadata, "icon"),
821
1097
  hidden: seg.hidden,
822
1098
  viewers: mergeVariantViewers(seg)
823
1099
  });
824
1100
  return {
825
1101
  type: "section",
826
1102
  ...defaults,
827
- collapsed: sm.collapsed ?? defaults.collapsed,
1103
+ collapsed: metaCollapsed(seg.metadata) ?? defaults.collapsed,
828
1104
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
829
1105
  noindex: void 0,
830
- collapsible: sm.collapsible,
831
- collapsedByDefault: sm.collapsedByDefault,
1106
+ collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) != null ? true : void 0),
1107
+ collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : void 0),
832
1108
  availability: void 0,
833
- pointsTo: void 0,
834
- children: [...leafChildren, ...sectionChildren]
1109
+ pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1110
+ children: mergeChildrenByPosition(ctx, nav, sectionChildren)
835
1111
  };
836
1112
  }
837
- function parentSectionPath(sectionPath) {
838
- const idx = sectionPath.lastIndexOf("/");
839
- return idx === -1 ? "" : sectionPath.slice(0, idx);
1113
+ function directChildApiPackages(parentSection, scopeSegs) {
1114
+ const sectionPaths = new Set(scopeSegs.map((s) => s.seg.section));
1115
+ return scopeSegs.filter((s) => {
1116
+ if (metaStr(s.seg.metadata, "type") !== "apiPackage") {
1117
+ return false;
1118
+ }
1119
+ const parent = parentSectionPath(s.seg.section);
1120
+ if (parent === parentSection) {
1121
+ return true;
1122
+ }
1123
+ if (!sectionPaths.has(parent)) {
1124
+ return nearestExistingAncestor(s.seg.section, sectionPaths) === parentSection;
1125
+ }
1126
+ return false;
1127
+ }).sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
840
1128
  }
841
- function nearestExistingAncestor(sectionPath, existing) {
842
- let current = parentSectionPath(sectionPath);
843
- while (current !== "") {
844
- if (existing.has(current)) {
845
- return current;
1129
+ function buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1130
+ const { seg, nav } = scoped;
1131
+ const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefinitionId)).filter((node) => node != null);
1132
+ const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
1133
+ const childPackages = directChildApiPackages(seg.section, scopeSegs);
1134
+ const packageNodes = childPackages.map((child) => ({
1135
+ node: apiPackageChildNode(
1136
+ ctx,
1137
+ child,
1138
+ scopeSegs,
1139
+ apiDefinitionId,
1140
+ scopePrefix
1141
+ ),
1142
+ childIndex: metaNum(child.seg.metadata, "childIndex")
1143
+ }));
1144
+ const hasChildIndex = packageNodes.some((p) => p.childIndex != null);
1145
+ if (!hasChildIndex) {
1146
+ return [...leafNodes, ...packageNodes.map((p) => p.node)];
1147
+ }
1148
+ const leafPositions = [];
1149
+ for (const route of nav) {
1150
+ if (route.displaySortOrder != null) {
1151
+ leafPositions.push(route.displaySortOrder);
846
1152
  }
847
- current = parentSectionPath(current);
848
1153
  }
849
- return "";
850
- }
851
- function isDirectChildOf(sec, parentPath, sectionPaths) {
852
- const parent = parentSectionPath(sec);
853
- if (parent === parentPath) {
854
- return true;
1154
+ const positioned = [];
1155
+ for (let i = 0; i < leafNodes.length; i++) {
1156
+ positioned.push({ node: leafNodes[i], pos: leafPositions[i] ?? i });
855
1157
  }
856
- return !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === parentPath;
857
- }
858
- function directChildApiPackages(parentSection, scopeSegs, sectionPaths) {
859
- return scopeSegs.filter((s) => s.meta.type === "apiPackage" && isDirectChildOf(s.seg.section, parentSection, sectionPaths)).sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1158
+ for (const p of packageNodes) {
1159
+ positioned.push({ node: p.node, pos: p.childIndex ?? Number.MAX_SAFE_INTEGER });
1160
+ }
1161
+ positioned.sort((a, b) => a.pos - b.pos);
1162
+ return positioned.map((p) => p.node);
860
1163
  }
861
- function buildApiChildren(ctx, scoped, scopeSegs, apiDefId, sectionPaths) {
862
- const { nav } = scoped;
863
- const rawLeafNodes = nav.map((route) => apiLeafNodeFromNavRouteInternal(ctx, route, apiDefId)).filter((node) => node != null);
864
- const leafNodes = mergeEndpointPairs(ctx, rawLeafNodes, nav);
865
- const childPackages = directChildApiPackages(scoped.seg.section, scopeSegs, sectionPaths);
866
- const packageNodes = childPackages.map(
867
- (child) => apiPackageChildNode(ctx, child, scopeSegs, apiDefId, sectionPaths)
868
- );
869
- return [...leafNodes, ...packageNodes];
870
- }
871
- function apiPackageChildNode(ctx, scoped, scopeSegs, parentApiDefId, sectionPaths) {
872
- const { seg, meta: sm, nav } = scoped;
1164
+ function apiPackageChildNode(ctx, scoped, scopeSegs, parentApiDefinitionId, scopePrefix) {
1165
+ const { seg, nav } = scoped;
873
1166
  const overview = overviewRoute(nav);
874
- const overviewPageId = overview?.meta.pageId;
875
- const apiDefId = sm.apiDefinitionId ?? parentApiDefId;
876
- const slug = ctx.contentSlug(overview?.route.fullPath ?? nav[0]?.fullPath ?? seg.section);
877
- const children = buildApiChildren(ctx, scoped, scopeSegs, apiDefId, sectionPaths);
1167
+ const overviewPageId = overview != null ? metaStr(overview.metadata, "pageId") : void 0;
1168
+ const apiDefinitionId = metaStr(seg.metadata, "apiDefinitionId") ?? parentApiDefinitionId;
1169
+ const slug = structuralNodeSlug(ctx, overview?.fullPath, seg.section, scopePrefix);
1170
+ const metaPointsTo = metaStr(seg.metadata, "pointsTo");
1171
+ const children = buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix);
878
1172
  return {
879
1173
  type: "apiPackage",
880
1174
  ...withMetadataDefaults({
881
1175
  id: ctx.nodeId(`api-pkg:${slug}`),
882
- title: sm.title ?? "",
1176
+ title: metaStr(seg.metadata, "title") ?? "",
883
1177
  slug,
884
- icon: sm.icon,
1178
+ icon: metaStr(seg.metadata, "icon"),
885
1179
  hidden: seg.hidden,
886
- viewers: toViewers(sm.viewers)
1180
+ viewers: toViewers(metaStrArr(seg.metadata, "viewers"))
887
1181
  }),
888
- apiDefinitionId: ApiDefinitionId(apiDefId),
889
- availability: sm.availability,
1182
+ apiDefinitionId: ApiDefinitionId(apiDefinitionId),
1183
+ availability: metaStr(seg.metadata, "availability"),
890
1184
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
891
1185
  noindex: void 0,
892
- pointsTo: void 0,
1186
+ pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
893
1187
  children,
894
1188
  playground: void 0
895
1189
  };
@@ -900,9 +1194,10 @@ function mergeEndpointPairs(ctx, leafNodes, allNav) {
900
1194
  if (route.type !== "rest") {
901
1195
  continue;
902
1196
  }
903
- const md = routeMeta(route);
904
- if (md.endpointPairKey != null && md.endpointId != null) {
905
- endpointIdToPairKey.set(md.endpointId, md.endpointPairKey);
1197
+ const pairKey = metaStr(route.metadata, "endpointPairKey");
1198
+ const endpointId = metaStr(route.metadata, "endpointId");
1199
+ if (pairKey != null && endpointId != null) {
1200
+ endpointIdToPairKey.set(endpointId, pairKey);
906
1201
  }
907
1202
  }
908
1203
  if (endpointIdToPairKey.size === 0) {
@@ -932,6 +1227,7 @@ function mergeEndpointPairs(ctx, leafNodes, allNav) {
932
1227
  }
933
1228
  const stream = node.isResponseStream ? node : first;
934
1229
  const nonStream = node.isResponseStream ? first : node;
1230
+ stream.canonicalSlug = nonStream.slug;
935
1231
  const pairNode = {
936
1232
  id: ctx.nodeId(`endpoint-pair:${pairKey}`),
937
1233
  type: "endpointPair",
@@ -944,61 +1240,86 @@ function mergeEndpointPairs(ctx, leafNodes, allNav) {
944
1240
  }
945
1241
  return result;
946
1242
  }
947
- function apiReferenceNode(ctx, scoped, scopeSegs, sectionPaths) {
948
- const { seg, meta: sm, nav } = scoped;
1243
+ function apiReferenceNode(ctx, scoped, scopeSegs, scopePrefix) {
1244
+ const { seg, nav } = scoped;
949
1245
  const overview = overviewRoute(nav);
950
- const overviewPageId = overview?.meta.pageId;
951
- const apiDefId = sm.apiDefinitionId ?? "";
952
- const slug = ctx.contentSlug(overview?.route.fullPath ?? nav[0]?.fullPath ?? seg.section);
953
- const children = buildApiChildren(ctx, scoped, scopeSegs, apiDefId, sectionPaths);
1246
+ const overviewPageId = overview != null ? metaStr(overview.metadata, "pageId") : void 0;
1247
+ const apiDefinitionId = metaStr(seg.metadata, "apiDefinitionId") ?? "";
1248
+ const slug = structuralNodeSlug(ctx, overview?.fullPath, seg.section, scopePrefix);
1249
+ const metaPointsTo = metaStr(seg.metadata, "pointsTo");
1250
+ const children = buildApiChildren(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix);
1251
+ const changelog = attachedApiChangelogNode(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix);
954
1252
  return {
955
1253
  type: "apiReference",
956
1254
  ...withMetadataDefaults({
957
1255
  id: ctx.nodeId(`api:${slug}`),
958
- title: sm.title ?? "",
1256
+ title: metaStr(seg.metadata, "title") ?? "",
959
1257
  slug,
960
- icon: sm.icon,
1258
+ icon: metaStr(seg.metadata, "icon"),
961
1259
  hidden: seg.hidden,
962
1260
  viewers: mergeVariantViewers(seg)
963
1261
  }),
964
- apiDefinitionId: ApiDefinitionId(apiDefId),
1262
+ apiDefinitionId: ApiDefinitionId(apiDefinitionId),
965
1263
  availability: void 0,
966
1264
  overviewPageId: overviewPageId != null ? PageId(overviewPageId) : void 0,
967
1265
  noindex: void 0,
968
1266
  paginated: true,
969
- showErrors: sm.showErrors,
970
- hideTitle: sm.hideTitle,
971
- pointsTo: void 0,
1267
+ showErrors: metaBool(seg.metadata, "showErrors"),
1268
+ hideTitle: metaBool(seg.metadata, "hideTitle"),
1269
+ pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
972
1270
  children,
973
- changelog: void 0,
1271
+ changelog,
974
1272
  playground: void 0,
975
1273
  postmanCollectionUrl: void 0
976
1274
  };
977
1275
  }
978
- function changelogNode(ctx, scoped) {
979
- const { seg, meta: sm, nav } = scoped;
1276
+ function attachedApiChangelogNode(ctx, scoped, scopeSegs, apiDefinitionId, scopePrefix) {
1277
+ const { seg } = scoped;
1278
+ const candidates = scopeSegs.filter((candidate) => {
1279
+ if (metaStr(candidate.seg.metadata, "type") !== "changelog") {
1280
+ return false;
1281
+ }
1282
+ return metaStr(candidate.seg.metadata, "apiDefinitionId") === apiDefinitionId;
1283
+ });
1284
+ const changelogSeg = candidates.find((candidate) => parentSectionPath(candidate.seg.section) === seg.section) ?? candidates[0];
1285
+ return changelogSeg != null ? changelogNode(ctx, changelogSeg, scopePrefix) : void 0;
1286
+ }
1287
+ function hasOwningApiReference(scoped, scopeSegs) {
1288
+ const apiDefinitionId = metaStr(scoped.seg.metadata, "apiDefinitionId");
1289
+ if (apiDefinitionId == null || metaStr(scoped.seg.metadata, "type") !== "changelog") {
1290
+ return false;
1291
+ }
1292
+ return scopeSegs.some((candidate) => {
1293
+ if (metaStr(candidate.seg.metadata, "type") !== "apiReference") {
1294
+ return false;
1295
+ }
1296
+ return metaStr(candidate.seg.metadata, "apiDefinitionId") === apiDefinitionId;
1297
+ });
1298
+ }
1299
+ function changelogNode(ctx, scoped, scopePrefix) {
1300
+ const { seg, nav } = scoped;
980
1301
  const overview = overviewRoute(nav);
981
- const overviewPageId = overview?.meta.pageId;
1302
+ const overviewPageId = overview != null ? metaStr(overview.metadata, "pageId") : void 0;
982
1303
  const entries = nav.filter((r) => r.type === "changelog");
983
1304
  const byYear = /* @__PURE__ */ new Map();
984
1305
  for (const r of entries) {
985
- const md = routeMeta(r);
986
- const date = md.date != null ? new Date(md.date) : /* @__PURE__ */ new Date(0);
1306
+ const dateStr = metaStr(r.metadata, "date");
1307
+ const date = dateStr != null ? new Date(dateStr) : /* @__PURE__ */ new Date(0);
987
1308
  const year = date.getUTCFullYear();
988
1309
  const month = date.getUTCMonth() + 1;
989
1310
  const entry = {
990
1311
  type: "changelogEntry",
991
1312
  ...withMetadataDefaults({
992
- id: ctx.nodeId(`cl-entry:${r.fullPath ?? md.pageId ?? ""}`),
993
- title: md.title ?? "",
1313
+ id: ctx.nodeId(`cl-entry:${r.fullPath ?? metaStr(r.metadata, "pageId") ?? ""}`),
1314
+ title: metaStr(r.metadata, "title") ?? "",
994
1315
  slug: ctx.contentSlug(r.fullPath ?? ""),
995
- icon: md.icon,
1316
+ icon: metaStr(r.metadata, "icon"),
996
1317
  hidden: r.hidden,
997
- viewers: toViewers(md.viewers)
1318
+ viewers: toViewers(metaStrArr(r.metadata, "viewers"))
998
1319
  }),
999
- pageId: PageId(md.pageId ?? ""),
1320
+ pageId: PageId(metaStr(r.metadata, "pageId") ?? ""),
1000
1321
  noindex: void 0,
1001
- date: md.date ?? "",
1322
+ date: dateStr ?? "",
1002
1323
  tags: void 0
1003
1324
  };
1004
1325
  let months = byYear.get(year);
@@ -1010,7 +1331,8 @@ function changelogNode(ctx, scoped) {
1010
1331
  arr.push(entry);
1011
1332
  months.set(month, arr);
1012
1333
  }
1013
- const baseSlug = ctx.contentSlug(overview?.route.fullPath ?? seg.section);
1334
+ const relativeSection = stripLeadingScopePrefix(seg.section, scopePrefix);
1335
+ const baseSlug = structuralNodeSlug(ctx, overview?.fullPath, relativeSection, scopePrefix);
1014
1336
  const years = [...byYear.entries()].sort((a, b) => b[0] - a[0]).map(([year, months]) => ({
1015
1337
  type: "changelogYear",
1016
1338
  ...withMetadataDefaults({
@@ -1038,9 +1360,9 @@ function changelogNode(ctx, scoped) {
1038
1360
  type: "changelog",
1039
1361
  ...withMetadataDefaults({
1040
1362
  id: ctx.nodeId(`changelog:${baseSlug}`),
1041
- title: sm.title ?? "",
1363
+ title: metaStr(seg.metadata, "title") ?? "",
1042
1364
  slug: baseSlug,
1043
- icon: sm.icon,
1365
+ icon: metaStr(seg.metadata, "icon"),
1044
1366
  hidden: seg.hidden,
1045
1367
  viewers: mergeVariantViewers(seg)
1046
1368
  }),
@@ -1049,48 +1371,112 @@ function changelogNode(ctx, scoped) {
1049
1371
  children: years
1050
1372
  };
1051
1373
  }
1052
- function buildSectionTree(ctx, scopeSegs, parentPath, sectionPaths) {
1374
+ function parentSectionPath(sectionPath) {
1375
+ const idx = sectionPath.lastIndexOf("/");
1376
+ return idx === -1 ? "" : sectionPath.slice(0, idx);
1377
+ }
1378
+ function nearestExistingAncestor(sectionPath, existing) {
1379
+ let current = parentSectionPath(sectionPath);
1380
+ while (current !== "") {
1381
+ if (existing.has(current)) {
1382
+ return current;
1383
+ }
1384
+ current = parentSectionPath(current);
1385
+ }
1386
+ return "";
1387
+ }
1388
+ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScopePrefix) {
1389
+ const sectionPaths = new Set(scopeSegs.map((s) => s.seg.section));
1053
1390
  const direct = scopeSegs.filter((s) => {
1054
1391
  const sec = s.seg.section;
1055
- return sec !== "" && s.meta.type !== "tabRoot" && isDirectChildOf(sec, parentPath, sectionPaths);
1392
+ const type = metaStr(s.seg.metadata, "type");
1393
+ if (sec === "" || type === "tabRoot") {
1394
+ return false;
1395
+ }
1396
+ if (hasOwningApiReference(s, scopeSegs)) {
1397
+ return false;
1398
+ }
1399
+ const parent = parentSectionPath(sec);
1400
+ if (parent === parentPath) {
1401
+ return true;
1402
+ }
1403
+ if (!sectionPaths.has(parent)) {
1404
+ return nearestExistingAncestor(sec, sectionPaths) === parentPath;
1405
+ }
1406
+ return false;
1056
1407
  }).sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1057
1408
  return direct.map((s) => {
1058
- const { type } = s.meta;
1409
+ const type = metaStr(s.seg.metadata, "type");
1410
+ const childIndex = metaNum(s.seg.metadata, "childIndex");
1411
+ let node;
1059
1412
  if (type === "apiReference" || type === "apiPackage") {
1060
- return apiReferenceNode(ctx, s, scopeSegs, sectionPaths);
1061
- }
1062
- if (type === "changelog") {
1063
- return changelogNode(ctx, s);
1413
+ node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1414
+ } else if (type === "changelog") {
1415
+ node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1416
+ } else {
1417
+ node = sectionNode(
1418
+ ctx,
1419
+ s,
1420
+ buildSectionTree(ctx, scopeSegs, s.seg.section, scopePrefix, changelogScopePrefix),
1421
+ scopePrefix
1422
+ );
1064
1423
  }
1065
- return sectionNode(ctx, s, buildSectionTree(ctx, scopeSegs, s.seg.section, sectionPaths));
1424
+ return { node, childIndex };
1066
1425
  });
1067
1426
  }
1068
- function buildSidebarRootChildren(ctx, scopeSegs) {
1427
+ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1069
1428
  const ordered = [...scopeSegs].sort((a, b) => a.seg.sortOrder - b.seg.sortOrder);
1070
1429
  const sectionPaths = new Set(ordered.map((s) => s.seg.section));
1071
- const flat = [];
1430
+ const annotated = [];
1431
+ const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
1072
1432
  for (const s of ordered) {
1073
- const { type } = s.meta;
1433
+ const type = metaStr(s.seg.metadata, "type");
1074
1434
  const sec = s.seg.section;
1075
- if (type === "tabRoot" || sec === "") {
1435
+ if (hasOwningApiReference(s, scopeSegs)) {
1436
+ continue;
1437
+ }
1438
+ if (type === "tabRoot" || sec === "" && type !== "section") {
1076
1439
  for (const r of s.nav) {
1077
1440
  const node = artifactToNode(ctx, r);
1078
1441
  if (node != null) {
1079
- flat.push(node);
1442
+ annotated.push({ node, pos: r.displaySortOrder ?? void 0, isLeaf: true });
1080
1443
  }
1081
1444
  }
1082
1445
  continue;
1083
1446
  }
1084
- if (isDirectChildOf(sec, "", sectionPaths)) {
1447
+ if (type === "section" && sec === "") {
1448
+ const sectionChildren = buildSectionTree(ctx, scopeSegs, "", scopePrefix);
1449
+ const node = sectionNode(ctx, s, sectionChildren, scopePrefix);
1450
+ annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1451
+ continue;
1452
+ }
1453
+ const parent = parentSectionPath(sec);
1454
+ const isRootLevel = parent === "" || !sectionPaths.has(parent) && nearestExistingAncestor(sec, sectionPaths) === "";
1455
+ if (isRootLevel && hasRootSection) {
1456
+ continue;
1457
+ }
1458
+ if (isRootLevel) {
1459
+ let node;
1085
1460
  if (type === "apiReference" || type === "apiPackage") {
1086
- flat.push(apiReferenceNode(ctx, s, scopeSegs, sectionPaths));
1461
+ node = apiReferenceNode(ctx, s, scopeSegs, scopePrefix);
1087
1462
  } else if (type === "changelog") {
1088
- flat.push(changelogNode(ctx, s));
1463
+ node = changelogNode(ctx, s, changelogScopePrefix ?? scopePrefix);
1089
1464
  } else {
1090
- flat.push(sectionNode(ctx, s, buildSectionTree(ctx, scopeSegs, sec, sectionPaths)));
1465
+ node = sectionNode(
1466
+ ctx,
1467
+ s,
1468
+ buildSectionTree(ctx, scopeSegs, sec, scopePrefix, changelogScopePrefix),
1469
+ scopePrefix
1470
+ );
1091
1471
  }
1472
+ annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
1092
1473
  }
1093
1474
  }
1475
+ const hasLeafPos = annotated.some((a) => a.isLeaf && a.pos != null);
1476
+ const hasSegmentPos = annotated.some((a) => !a.isLeaf && a.pos != null);
1477
+ const flat = hasLeafPos && hasSegmentPos ? annotated.map((a, seq) => ({ ...a, seq })).sort(
1478
+ (x, y) => (x.pos ?? Number.MAX_SAFE_INTEGER) - (y.pos ?? Number.MAX_SAFE_INTEGER) || x.seq - y.seq
1479
+ ).map((a) => a.node) : annotated.map((a) => a.node);
1094
1480
  return groupSidebarRootChildren(ctx, flat);
1095
1481
  }
1096
1482
  function groupSidebarRootChildren(ctx, children) {
@@ -1111,9 +1497,13 @@ function groupSidebarRootChildren(ctx, children) {
1111
1497
  if (child.type === "apiReference" || child.type === "varianted") {
1112
1498
  flushRun();
1113
1499
  out.push(child);
1114
- } else if (child.type === "section" && (child.collapsible === false || child.collapsible == null && child.collapsed === false)) {
1500
+ } else if (child.type === "section" && !child.collapsible) {
1115
1501
  flushRun();
1116
1502
  out.push(child);
1503
+ } else if (child.type === "changelog") {
1504
+ flushRun();
1505
+ run.push(child);
1506
+ flushRun();
1117
1507
  } else {
1118
1508
  run.push(child);
1119
1509
  }
@@ -1121,19 +1511,22 @@ function groupSidebarRootChildren(ctx, children) {
1121
1511
  flushRun();
1122
1512
  return out;
1123
1513
  }
1124
- function buildSidebarRoot(ctx, scopeSegs) {
1514
+ function buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1125
1515
  const first = scopeSegs[0];
1126
1516
  return {
1127
1517
  type: "sidebarRoot",
1128
1518
  id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1129
1519
  collapsed: void 0,
1130
- children: buildSidebarRootChildren(ctx, scopeSegs)
1520
+ children: buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePrefix)
1131
1521
  };
1132
1522
  }
1133
1523
  function buildFullRootFromSegments(options) {
1134
1524
  const { basePath, title, segments, navBySegment } = options;
1135
1525
  const ctx = createBuildContext(basePath);
1136
- const scoped = segments.map((seg) => ({ seg, meta: segMeta(seg), nav: navBySegment.get(seg.segmentHash) ?? [] })).filter((s) => s.meta.type !== "files" && s.meta.type !== "redirects");
1526
+ const scoped = segments.filter((seg) => {
1527
+ const t = metaStr(seg.metadata, "type");
1528
+ return t !== "files" && t !== "redirects";
1529
+ }).map((seg) => ({ seg, nav: navBySegment.get(seg.segmentHash) ?? [] }));
1137
1530
  const rootSlug = asSlug(basePath);
1138
1531
  const scopesByKey = /* @__PURE__ */ new Map();
1139
1532
  for (const s of scoped) {
@@ -1151,7 +1544,7 @@ function buildFullRootFromSegments(options) {
1151
1544
  } else if (versions.length > 0) {
1152
1545
  child = buildVersioned(ctx, versions, scoped, rootSlug, void 0);
1153
1546
  } else {
1154
- child = buildUnversioned(ctx, scoped, tabs.length > 0);
1547
+ child = buildUnversioned(ctx, scoped, rootSlug, tabs.length > 0);
1155
1548
  }
1156
1549
  let rootPointsTo;
1157
1550
  if (child.type === "productgroup") {
@@ -1161,20 +1554,15 @@ function buildFullRootFromSegments(options) {
1161
1554
  const defaultVersion = child.children.find((v) => v.default) ?? child.children[0];
1162
1555
  rootPointsTo = defaultVersion?.pointsTo;
1163
1556
  }
1164
- return {
1557
+ const root = {
1165
1558
  type: "root",
1166
1559
  version: "v2",
1167
- ...withMetadataDefaults({
1168
- id: ctx.nodeId("root"),
1169
- title,
1170
- slug: rootSlug,
1171
- icon: void 0,
1172
- hidden: void 0
1173
- }),
1560
+ ...withMetadataDefaults({ id: ctx.nodeId("root"), title, slug: rootSlug, icon: void 0, hidden: void 0 }),
1174
1561
  roles: void 0,
1175
1562
  pointsTo: rootPointsTo,
1176
1563
  child
1177
1564
  };
1565
+ return root;
1178
1566
  }
1179
1567
  function uniqueDetails(scoped, dim) {
1180
1568
  const bySlug = /* @__PURE__ */ new Map();
@@ -1183,14 +1571,15 @@ function uniqueDetails(scoped, dim) {
1183
1571
  if (d == null) {
1184
1572
  continue;
1185
1573
  }
1186
- const dm = detailMeta(d);
1187
- const slug = dm.slug ?? "";
1574
+ const slug = detailSlug(d);
1188
1575
  const existing = bySlug.get(slug);
1189
- if (existing == null || dm.pointsTo != null && existing.meta.pointsTo == null) {
1190
- bySlug.set(slug, { detail: d, meta: dm });
1576
+ if (existing == null) {
1577
+ bySlug.set(slug, d);
1578
+ } else if (metaStr(d.metadata, "pointsTo") != null && metaStr(existing.metadata, "pointsTo") == null) {
1579
+ bySlug.set(slug, d);
1191
1580
  }
1192
1581
  }
1193
- return [...bySlug.values()].map((e) => e.detail).sort((a, b) => a.sortOrder - b.sortOrder);
1582
+ return [...bySlug.values()].sort((a, b) => a.sortOrder - b.sortOrder);
1194
1583
  }
1195
1584
  function scopeSlugPrefix(rootSlug, ...details) {
1196
1585
  const parts = [rootSlug];
@@ -1204,30 +1593,80 @@ function scopeSlugPrefix(rootSlug, ...details) {
1204
1593
  }
1205
1594
  return slugjoin(...parts);
1206
1595
  }
1207
- function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent) {
1596
+ function buildVariantedNode(ctx, variants, scopeSegs, scopePrefix) {
1597
+ const variantChildren = variants.map((variant) => {
1598
+ const variantSegs = scopeSegs.filter((s) => s.seg.variant?.id === variant.id);
1599
+ const variantIndividualSlug = detailSlug(variant);
1600
+ const variantSlug = variantIndividualSlug !== "" ? asSlug(slugjoin(scopePrefix, variantIndividualSlug)) : scopePrefix;
1601
+ const metaPointsTo = metaStr(variant.metadata, "pointsTo");
1602
+ const children = buildSidebarRootChildren(ctx, variantSegs, scopePrefix);
1603
+ return {
1604
+ type: "variant",
1605
+ ...withMetadataDefaults({
1606
+ id: ctx.nodeId(`variant:${variantSlug}`),
1607
+ title: variant.displayName,
1608
+ slug: variantSlug,
1609
+ icon: variant.icon ?? void 0,
1610
+ hidden: variant.hidden,
1611
+ viewers: toViewers(variant.viewers)
1612
+ }),
1613
+ default: detailIsDefault(variant),
1614
+ variantId: VariantId(String(variant.id)),
1615
+ subtitle: metaStr(variant.metadata, "subtitle") ?? void 0,
1616
+ image: void 0,
1617
+ pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1618
+ children
1619
+ };
1620
+ });
1621
+ return {
1622
+ type: "varianted",
1623
+ id: ctx.nodeId(`varianted:${scopeSegs[0] != null ? scopeKey(scopeSegs[0].seg) : "root"}`),
1624
+ collapsed: void 0,
1625
+ children: variantChildren
1626
+ };
1627
+ }
1628
+ function buildSidebarRootWithVariants(ctx, scopeSegs, scopePrefix, changelogScopePrefix) {
1629
+ const variants = uniqueDetails(scopeSegs, "variant");
1630
+ if (variants.length <= 1) {
1631
+ return buildSidebarRoot(ctx, scopeSegs, scopePrefix, changelogScopePrefix);
1632
+ }
1633
+ const variantedNode = buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1634
+ const first = scopeSegs[0];
1635
+ return {
1636
+ type: "sidebarRoot",
1637
+ id: ctx.nodeId(`sidebar:${first != null ? scopeKey(first.seg) : "root"}`),
1638
+ collapsed: void 0,
1639
+ children: [variantedNode]
1640
+ };
1641
+ }
1642
+ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix) {
1208
1643
  if (!tabsPresent) {
1209
- return buildSidebarRoot(ctx, scopeSegs);
1644
+ const variants = uniqueDetails(scopeSegs, "variant");
1645
+ if (variants.length > 1) {
1646
+ return buildVariantedNode(ctx, variants, scopeSegs, scopePrefix);
1647
+ }
1648
+ return buildSidebarRoot(ctx, scopeSegs, scopePrefix);
1210
1649
  }
1211
1650
  const tabDetails = uniqueDetails(scopeSegs, "tab");
1212
1651
  const children = tabDetails.map((tab) => {
1213
- const tm = detailMeta(tab);
1214
- const tabSlug = asSlug(scopeSlugPrefix(Slug(""), tab));
1215
- if (tm.tab_type === "link") {
1652
+ const tabType = metaStr(tab.metadata, "tab_type");
1653
+ const tabSlug = asSlug(scopeSlugPrefix(scopePrefix, tab));
1654
+ if (tabType === "link") {
1216
1655
  return {
1217
1656
  type: "link",
1218
- id: ctx.nodeId(`link:${tm.url ?? tabSlug}`),
1657
+ id: ctx.nodeId(`link:${metaStr(tab.metadata, "url") ?? tabSlug}`),
1219
1658
  collapsed: void 0,
1220
1659
  title: tab.displayName,
1221
1660
  icon: tab.icon ?? void 0,
1222
- url: Url(tm.url ?? ""),
1661
+ url: Url(metaStr(tab.metadata, "url") ?? ""),
1223
1662
  target: void 0
1224
1663
  };
1225
1664
  }
1226
- if (tm.tab_type === "changelog") {
1665
+ if (tabType === "changelog") {
1227
1666
  const tabSegs2 = scopeSegs.filter((s) => s.seg.tab?.id === tab.id);
1228
- const changelogSeg = tabSegs2.find((s) => s.meta.type === "changelog");
1667
+ const changelogSeg = tabSegs2.find((s) => metaStr(s.seg.metadata, "type") === "changelog");
1229
1668
  if (changelogSeg != null) {
1230
- return changelogNode(ctx, changelogSeg);
1669
+ return changelogNode(ctx, changelogSeg, scopePrefix);
1231
1670
  }
1232
1671
  return {
1233
1672
  type: "changelog",
@@ -1245,6 +1684,7 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent) {
1245
1684
  };
1246
1685
  }
1247
1686
  const tabSegs = scopeSegs.filter((s) => s.seg.tab?.id === tab.id);
1687
+ const metaPointsTo = metaStr(tab.metadata, "pointsTo");
1248
1688
  return {
1249
1689
  type: "tab",
1250
1690
  ...withMetadataDefaults({
@@ -1255,8 +1695,15 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent) {
1255
1695
  hidden: tab.hidden,
1256
1696
  viewers: toViewers(tab.viewers)
1257
1697
  }),
1258
- pointsTo: pointsToSlug(ctx, tm),
1259
- child: buildSidebarRoot(ctx, tabSegs)
1698
+ pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : void 0,
1699
+ // Structural sections under this tab are rooted at the TAB slug
1700
+ // (`{...}/{version}/{tab}`) so their slugs nest under the tab
1701
+ // (matching v2) while still starting with the version slug, keeping
1702
+ // the subtree inside the default-version prune window (see
1703
+ // {@link structuralNodeSlug}).
1704
+ // Changelog sidebar children use the product/version prefix — v2
1705
+ // roots changelogs at the scope level, not under the tab.
1706
+ child: buildSidebarRootWithVariants(ctx, tabSegs, tabSlug, scopePrefix)
1260
1707
  };
1261
1708
  });
1262
1709
  const first = scopeSegs[0];
@@ -1267,24 +1714,27 @@ function buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent) {
1267
1714
  children
1268
1715
  };
1269
1716
  }
1270
- function buildUnversioned(ctx, scopeSegs, tabsPresent) {
1717
+ function buildUnversioned(ctx, scopeSegs, scopePrefix, tabsPresent) {
1271
1718
  const first = scopeSegs[0];
1272
1719
  return {
1273
1720
  type: "unversioned",
1274
1721
  id: ctx.nodeId(`unversioned:${first?.seg.product?.id ?? "root"}`),
1275
1722
  collapsed: void 0,
1276
1723
  landingPage: void 0,
1277
- child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent)
1724
+ // The enclosing scope prefix (product slug, or rootSlug at the top
1725
+ // level) roots structural sections so they share the scope's slug
1726
+ // namespace.
1727
+ child: buildTabbedOrSidebar(ctx, scopeSegs, tabsPresent, scopePrefix)
1278
1728
  };
1279
1729
  }
1280
1730
  function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1281
1731
  const children = versions.map((version) => {
1282
- const vm = detailMeta(version);
1283
1732
  const versionSegs = scoped.filter((s) => s.seg.version?.id === version.id);
1284
1733
  const tabsPresent = uniqueDetails(versionSegs, "tab").length > 0;
1285
- const prefix = productPrefix ?? rootSlug;
1286
- const slug = vm.default ? prefix : scopeSlugPrefix(rootSlug, version);
1287
- return {
1734
+ const prefix = productPrefix != null ? productPrefix : rootSlug;
1735
+ const versionSegment = detailSlug(version);
1736
+ const slug = versionSegment !== "" ? slugjoin(asSlug(prefix), versionSegment) : asSlug(prefix);
1737
+ const node = {
1288
1738
  type: "version",
1289
1739
  ...withMetadataDefaults({
1290
1740
  id: ctx.nodeId(`version:${slug}`),
@@ -1294,14 +1744,20 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1294
1744
  hidden: version.hidden,
1295
1745
  viewers: toViewers(version.viewers)
1296
1746
  }),
1297
- default: vm.default ?? false,
1747
+ default: detailIsDefault(version),
1298
1748
  versionId: VersionId(version.id),
1299
1749
  availability: void 0,
1300
1750
  landingPage: void 0,
1301
1751
  announcement: void 0,
1302
- pointsTo: pointsToSlug(ctx, vm),
1303
- child: buildTabbedOrSidebar(ctx, versionSegs, tabsPresent)
1752
+ pointsTo: metaStr(version.metadata, "pointsTo") != null ? pointsToSlug(metaStr(version.metadata, "pointsTo")) : void 0,
1753
+ // The version's full slug roots structural sections so the whole
1754
+ // version subtree stays inside the default-version prune window.
1755
+ child: buildTabbedOrSidebar(ctx, versionSegs, tabsPresent, asSlug(slug))
1304
1756
  };
1757
+ if (node.default) {
1758
+ markDefaultVersionCanonicalSlugs(node, productPrefix != null ? asSlug(productPrefix) : rootSlug, node.slug);
1759
+ }
1760
+ return node;
1305
1761
  });
1306
1762
  return {
1307
1763
  type: "versioned",
@@ -1310,15 +1766,32 @@ function buildVersioned(ctx, versions, scoped, rootSlug, productPrefix) {
1310
1766
  children
1311
1767
  };
1312
1768
  }
1769
+ function markDefaultVersionCanonicalSlugs(node, pruneSlug, versionSlug) {
1770
+ traverseDF(node, (child) => {
1771
+ if (hasMetadata(child)) {
1772
+ const canonicalSlug = toDefaultSlug(
1773
+ child.canonicalSlug ?? child.slug,
1774
+ pruneSlug,
1775
+ versionSlug
1776
+ );
1777
+ if (canonicalSlug !== child.slug) {
1778
+ child.canonicalSlug = canonicalSlug;
1779
+ }
1780
+ }
1781
+ if (hasRedirect(child)) {
1782
+ child.pointsTo = toDefaultSlug(child.pointsTo, pruneSlug, versionSlug);
1783
+ }
1784
+ return;
1785
+ });
1786
+ }
1313
1787
  function buildProductGroup(ctx, products, scoped, rootSlug) {
1314
1788
  const children = products.map((product) => {
1315
- const pm = detailMeta(product);
1316
1789
  const productSegs = scoped.filter((s) => s.seg.product?.id === product.id);
1317
1790
  const versions = uniqueDetails(productSegs, "version");
1318
1791
  const tabsPresent = uniqueDetails(productSegs, "tab").length > 0;
1319
1792
  const productPrefix = scopeSlugPrefix(rootSlug, product);
1320
- const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, tabsPresent);
1321
- return {
1793
+ const productChild = versions.length > 0 ? buildVersioned(ctx, versions, productSegs, rootSlug, productPrefix) : buildUnversioned(ctx, productSegs, asSlug(productPrefix), tabsPresent);
1794
+ const node = {
1322
1795
  type: "product",
1323
1796
  ...withMetadataDefaults({
1324
1797
  id: ctx.nodeId(`product:${productPrefix}`),
@@ -1329,13 +1802,19 @@ function buildProductGroup(ctx, products, scoped, rootSlug) {
1329
1802
  viewers: toViewers(product.viewers)
1330
1803
  }),
1331
1804
  default: detailIsDefault(product),
1332
- productId: ProductId(product.id),
1333
- subtitle: pm.subtitle ?? "",
1805
+ // `product.id` is the content-addressed STORAGE hash (the segment
1806
+ // key). `productId` is the SEMANTIC identifier search/UI key off
1807
+ // (the product-scoped search filter does `product.title:${productId}`,
1808
+ // so it must equal the product title). v2 carries the display name
1809
+ // here; sourcing it from the hash makes that filter match nothing.
1810
+ productId: ProductId(product.displayName),
1811
+ subtitle: metaStr(product.metadata, "subtitle") ?? "",
1334
1812
  image: void 0,
1335
1813
  announcement: void 0,
1336
- pointsTo: pointsToSlug(ctx, pm),
1814
+ pointsTo: metaStr(product.metadata, "pointsTo") != null ? pointsToSlug(metaStr(product.metadata, "pointsTo")) : void 0,
1337
1815
  child: productChild
1338
1816
  };
1817
+ return node;
1339
1818
  });
1340
1819
  return {
1341
1820
  type: "productgroup",
@@ -1349,6 +1828,8 @@ export {
1349
1828
  apiLeafNodeFromNavRoute,
1350
1829
  buildFullRootFromSegments,
1351
1830
  collectApiLeafNodesFromNav,
1831
+ createBuildContext,
1832
+ mergeEndpointPairs,
1352
1833
  segmentApiDefinitionId
1353
1834
  };
1354
1835
  //# sourceMappingURL=ledger-root-builder.mjs.map