catalyst-relay 0.4.0 → 0.4.2

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.
package/dist/index.d.mts CHANGED
@@ -495,6 +495,7 @@ interface ADTClient {
495
495
  delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;
496
496
  getPackages(filter?: string): AsyncResult<Package[]>;
497
497
  getTree(query: TreeQuery): AsyncResult<TreeResponse>;
498
+ getPackageStats(packageName: string): AsyncResult<PackageNode>;
498
499
  getTransports(packageName: string): AsyncResult<Transport[]>;
499
500
  previewData(query: PreviewSQL): AsyncResult<DataFrame>;
500
501
  getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
@@ -507,4 +508,4 @@ interface ADTClient {
507
508
  }
508
509
  declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
509
510
 
510
- export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectRef, type ObjectWithContent, type Package, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeQuery, type UpsertResult, buildSQLQuery, createClient, err, ok };
511
+ export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type ApiState, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type FolderNode, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeQuery, type TreeResponse, type UpsertResult, buildSQLQuery, createClient, err, ok };
package/dist/index.d.ts CHANGED
@@ -495,6 +495,7 @@ interface ADTClient {
495
495
  delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;
496
496
  getPackages(filter?: string): AsyncResult<Package[]>;
497
497
  getTree(query: TreeQuery): AsyncResult<TreeResponse>;
498
+ getPackageStats(packageName: string): AsyncResult<PackageNode>;
498
499
  getTransports(packageName: string): AsyncResult<Transport[]>;
499
500
  previewData(query: PreviewSQL): AsyncResult<DataFrame>;
500
501
  getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
@@ -507,4 +508,4 @@ interface ADTClient {
507
508
  }
508
509
  declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
509
510
 
510
- export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectRef, type ObjectWithContent, type Package, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeQuery, type UpsertResult, buildSQLQuery, createClient, err, ok };
511
+ export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type ApiState, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type FolderNode, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeQuery, type TreeResponse, type UpsertResult, buildSQLQuery, createClient, err, ok };
package/dist/index.js CHANGED
@@ -753,56 +753,6 @@ var API_FOLDERS = [
753
753
  "USE_IN_KEY_USER_APPS"
754
754
  ];
755
755
 
756
- // src/core/adt/discovery/tree/subpackages.ts
757
- async function getSubpackages(client, packageName) {
758
- const params = new URLSearchParams([
759
- ["parent_type", "DEVC/K"],
760
- ["withShortDescriptions", "true"]
761
- ]);
762
- if (packageName) {
763
- params.append("parent_name", packageName);
764
- }
765
- const [response, requestErr] = await client.request({
766
- method: "POST",
767
- path: `/sap/bc/adt/repository/nodestructure?${params.toString()}`,
768
- headers: {
769
- "Accept": "application/vnd.sap.as+xml"
770
- }
771
- });
772
- if (requestErr) return err(requestErr);
773
- if (!response.ok) {
774
- const text2 = await response.text();
775
- const errorMsg = extractError(text2);
776
- return err(new Error(`Nodestructure failed: ${errorMsg}`));
777
- }
778
- const text = await response.text();
779
- return parseNodestructureForPackages(text, packageName);
780
- }
781
- function parseNodestructureForPackages(xml, parentPackage) {
782
- const [doc, parseErr] = safeParseXml(xml);
783
- if (parseErr) return err(parseErr);
784
- const packages = [];
785
- const nodes = doc.getElementsByTagName("SEU_ADT_REPOSITORY_OBJ_NODE");
786
- for (let i = 0; i < nodes.length; i++) {
787
- const node = nodes[i];
788
- if (!node) continue;
789
- const objectType = node.getElementsByTagName("OBJECT_TYPE")[0]?.textContent?.trim();
790
- if (objectType !== "DEVC/K") continue;
791
- const objectName = node.getElementsByTagName("OBJECT_NAME")[0]?.textContent?.trim();
792
- if (!objectName) continue;
793
- if (parentPackage && objectName.toUpperCase() === parentPackage.toUpperCase()) continue;
794
- const description = node.getElementsByTagName("DESCRIPTION")[0]?.textContent?.trim();
795
- const pkg = {
796
- name: objectName,
797
- numContents: 0
798
- // nodestructure doesn't provide counts
799
- };
800
- if (description) pkg.description = description;
801
- packages.push(pkg);
802
- }
803
- return ok(packages);
804
- }
805
-
806
756
  // src/core/adt/discovery/tree/parsers.ts
807
757
  function buildQueryFromPath(packageName, path) {
808
758
  const query = {
@@ -870,7 +820,7 @@ function parseTreeXml(xml) {
870
820
  if (!validFacets.includes(facet)) continue;
871
821
  const countAttr = vf.getAttribute("counter");
872
822
  const count = countAttr ? parseInt(countAttr, 10) : 0;
873
- const desc = vf.getAttribute("description");
823
+ const desc = vf.getAttribute("text");
874
824
  const displayNameAttr = vf.getAttribute("displayName");
875
825
  const technicalName = name.startsWith("..") ? name.substring(2) : name;
876
826
  const displayName = displayNameAttr || technicalName;
@@ -928,6 +878,45 @@ function transformToTreeResponse(parsed, queryPackage) {
928
878
  return { packages, folders, objects };
929
879
  }
930
880
 
881
+ // src/core/adt/discovery/tree/childPackages.ts
882
+ async function fetchChildPackages(client, parentPackage) {
883
+ const query = {
884
+ PACKAGE: {
885
+ name: parentPackage,
886
+ hasChildrenOfSameFacet: true
887
+ }
888
+ };
889
+ const body = constructTreeBody(query, "*");
890
+ const [response, requestErr] = await client.request({
891
+ method: "POST",
892
+ path: "/sap/bc/adt/repository/informationsystem/virtualfolders/contents",
893
+ headers: {
894
+ "Content-Type": "application/vnd.sap.adt.repository.virtualfolders.request.v1+xml",
895
+ "Accept": "application/vnd.sap.adt.repository.virtualfolders.result.v1+xml"
896
+ },
897
+ body
898
+ });
899
+ if (requestErr) return err(requestErr);
900
+ if (!response.ok) {
901
+ const text2 = await response.text();
902
+ const errorMsg = extractError(text2);
903
+ return err(new Error(`Failed to fetch child packages: ${errorMsg}`));
904
+ }
905
+ const text = await response.text();
906
+ const [parsed, parseErr] = parseTreeXml(text);
907
+ if (parseErr) return err(parseErr);
908
+ const parentUpper = parentPackage.toUpperCase();
909
+ const packages = parsed.folders.filter((f) => f.facet === "PACKAGE" && f.name.toUpperCase() !== parentUpper).map((f) => {
910
+ const pkg = {
911
+ name: f.name,
912
+ numContents: f.count
913
+ };
914
+ if (f.description) pkg.description = f.description;
915
+ return pkg;
916
+ });
917
+ return ok(packages);
918
+ }
919
+
931
920
  // src/core/adt/discovery/tree/virtualFolders.ts
932
921
  async function fetchVirtualFolders(client, query) {
933
922
  const body = constructTreeBody(query, "*");
@@ -1005,8 +994,16 @@ async function fetchObjectsWithApiState(client, packageName, pathSegments, apiFo
1005
994
  // src/core/adt/discovery/tree/index.ts
1006
995
  async function getTree(client, query = {}) {
1007
996
  if (!query.package) {
1008
- const [packages2, pkgErr] = await getSubpackages(client);
1009
- if (pkgErr) return err(pkgErr);
997
+ const [parsed2, parseErr2] = await fetchVirtualFolders(client, {});
998
+ if (parseErr2) return err(parseErr2);
999
+ const packages2 = parsed2.folders.filter((f) => f.facet === "PACKAGE").map((f) => {
1000
+ const pkg = {
1001
+ name: f.name,
1002
+ numContents: f.count
1003
+ };
1004
+ if (f.description) pkg.description = f.description;
1005
+ return pkg;
1006
+ });
1010
1007
  return ok({
1011
1008
  packages: packages2,
1012
1009
  folders: [],
@@ -1015,9 +1012,9 @@ async function getTree(client, query = {}) {
1015
1012
  }
1016
1013
  let packages = [];
1017
1014
  if (!query.path) {
1018
- const [subpkgs, subErr] = await getSubpackages(client, query.package);
1019
- if (subErr) return err(subErr);
1020
- packages = subpkgs;
1015
+ const [childPkgs, childErr] = await fetchChildPackages(client, query.package);
1016
+ if (childErr) return err(childErr);
1017
+ packages = childPkgs;
1021
1018
  }
1022
1019
  const internalQuery = buildQueryFromPath(query.package, query.path);
1023
1020
  const [parsed, parseErr] = await fetchVirtualFolders(client, internalQuery);
@@ -1043,6 +1040,96 @@ async function getTree(client, query = {}) {
1043
1040
  return ok(result);
1044
1041
  }
1045
1042
 
1043
+ // src/core/adt/discovery/tree/packageStats.ts
1044
+ async function fetchPackageMetadata(client, packageName) {
1045
+ const [response, requestErr] = await client.request({
1046
+ method: "GET",
1047
+ path: `/sap/bc/adt/packages/${packageName.toLowerCase()}`,
1048
+ headers: {
1049
+ "Accept": "application/vnd.sap.adt.packages.v1+xml"
1050
+ }
1051
+ });
1052
+ if (requestErr) return err(requestErr);
1053
+ if (!response.ok) {
1054
+ const text = await response.text();
1055
+ const errorMsg = extractError(text);
1056
+ return err(new Error(`Package metadata fetch failed: ${errorMsg}`));
1057
+ }
1058
+ const xml = await response.text();
1059
+ const [doc, parseErr] = safeParseXml(xml);
1060
+ if (parseErr) return err(parseErr);
1061
+ const packageElements = doc.getElementsByTagName("pak:package");
1062
+ if (packageElements.length === 0) {
1063
+ return err(new Error(`Package ${packageName} not found`));
1064
+ }
1065
+ const pkgEl = packageElements[0];
1066
+ const name = pkgEl.getAttribute("adtcore:name") || pkgEl.getAttributeNS("http://www.sap.com/adt/core", "name") || packageName.toUpperCase();
1067
+ const description = pkgEl.getAttribute("adtcore:description") || pkgEl.getAttributeNS("http://www.sap.com/adt/core", "description");
1068
+ const result = { name };
1069
+ if (description) result.description = description;
1070
+ return ok(result);
1071
+ }
1072
+ function constructCountRequestBody(packageName) {
1073
+ return `<?xml version="1.0" encoding="UTF-8"?>
1074
+ <vfs:virtualFoldersRequest xmlns:vfs="http://www.sap.com/adt/ris/virtualFolders" objectSearchPattern="*">
1075
+ <vfs:preselection facet="package">
1076
+ <vfs:value>${packageName}</vfs:value>
1077
+ </vfs:preselection>
1078
+ <vfs:facetorder/>
1079
+ </vfs:virtualFoldersRequest>`;
1080
+ }
1081
+ async function fetchContentCount(client, packageName) {
1082
+ const body = constructCountRequestBody(packageName);
1083
+ const [response, requestErr] = await client.request({
1084
+ method: "POST",
1085
+ path: "/sap/bc/adt/repository/informationsystem/virtualfolders",
1086
+ headers: {
1087
+ "Content-Type": "application/vnd.sap.adt.repository.virtualfolders.request.v1+xml",
1088
+ "Accept": "application/vnd.sap.adt.repository.virtualfolders.result.v1+xml"
1089
+ },
1090
+ body
1091
+ });
1092
+ if (requestErr) return err(requestErr);
1093
+ if (!response.ok) {
1094
+ const text = await response.text();
1095
+ const errorMsg = extractError(text);
1096
+ return err(new Error(`Package count fetch failed: ${errorMsg}`));
1097
+ }
1098
+ const xml = await response.text();
1099
+ const [doc, parseErr] = safeParseXml(xml);
1100
+ if (parseErr) return err(parseErr);
1101
+ const resultElements = doc.getElementsByTagName("vfs:virtualFoldersResult");
1102
+ if (resultElements.length === 0) {
1103
+ return err(new Error("Invalid virtualfolders response: missing result element"));
1104
+ }
1105
+ const resultEl = resultElements[0];
1106
+ const objectCountAttr = resultEl.getAttribute("objectCount");
1107
+ if (!objectCountAttr) {
1108
+ return err(new Error("Invalid virtualfolders response: missing objectCount attribute"));
1109
+ }
1110
+ const count = parseInt(objectCountAttr, 10);
1111
+ if (isNaN(count)) {
1112
+ return err(new Error(`Invalid objectCount value: ${objectCountAttr}`));
1113
+ }
1114
+ return ok(count);
1115
+ }
1116
+ async function getPackageStats(client, packageName) {
1117
+ const [metadataResult, countResult] = await Promise.all([
1118
+ fetchPackageMetadata(client, packageName),
1119
+ fetchContentCount(client, packageName)
1120
+ ]);
1121
+ const [metadata, metaErr] = metadataResult;
1122
+ if (metaErr) return err(metaErr);
1123
+ const [numContents, countErr] = countResult;
1124
+ if (countErr) return err(countErr);
1125
+ const result = {
1126
+ name: metadata.name,
1127
+ numContents
1128
+ };
1129
+ if (metadata.description) result.description = metadata.description;
1130
+ return ok(result);
1131
+ }
1132
+
1046
1133
  // src/core/adt/transports/transports.ts
1047
1134
  async function getTransports(client, packageName) {
1048
1135
  const contentType = "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData";
@@ -2539,6 +2626,10 @@ var ADTClientImpl = class {
2539
2626
  if (!this.state.session) return err(new Error("Not logged in"));
2540
2627
  return getTree(this.requestor, query);
2541
2628
  }
2629
+ async getPackageStats(packageName) {
2630
+ if (!this.state.session) return err(new Error("Not logged in"));
2631
+ return getPackageStats(this.requestor, packageName);
2632
+ }
2542
2633
  async getTransports(packageName) {
2543
2634
  if (!this.state.session) return err(new Error("Not logged in"));
2544
2635
  return getTransports(this.requestor, packageName);