catalyst-relay 0.2.5 → 0.3.0

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
@@ -35,8 +35,12 @@ interface SamlProviderConfig {
35
35
  */
36
36
  interface SamlAuthConfig {
37
37
  type: 'saml';
38
+ /** SAML username (often an email address) - used for browser login */
38
39
  username: string;
40
+ /** SAML password */
39
41
  password: string;
42
+ /** SAP system username - used for object creation (adtcore:responsible) */
43
+ sapUser: string;
40
44
  /** Optional custom provider configuration for non-standard login forms */
41
45
  providerConfig?: SamlProviderConfig;
42
46
  }
@@ -288,7 +292,6 @@ interface Transport {
288
292
  id: string;
289
293
  description: string;
290
294
  owner: string;
291
- status: 'modifiable' | 'released';
292
295
  }
293
296
 
294
297
  /**
package/dist/index.d.ts CHANGED
@@ -35,8 +35,12 @@ interface SamlProviderConfig {
35
35
  */
36
36
  interface SamlAuthConfig {
37
37
  type: 'saml';
38
+ /** SAML username (often an email address) - used for browser login */
38
39
  username: string;
40
+ /** SAML password */
39
41
  password: string;
42
+ /** SAP system username - used for object creation (adtcore:responsible) */
43
+ sapUser: string;
40
44
  /** Optional custom provider configuration for non-standard login forms */
41
45
  providerConfig?: SamlProviderConfig;
42
46
  }
@@ -288,7 +292,6 @@ interface Transport {
288
292
  id: string;
289
293
  description: string;
290
294
  owner: string;
291
- status: 'modifiable' | 'released';
292
295
  }
293
296
 
294
297
  /**
package/dist/index.js CHANGED
@@ -203,6 +203,7 @@ var clientConfigSchema = import_zod.z.object({
203
203
  type: import_zod.z.literal("saml"),
204
204
  username: import_zod.z.string().min(1),
205
205
  password: import_zod.z.string().min(1),
206
+ sapUser: import_zod.z.string().min(1),
206
207
  providerConfig: samlProviderConfigSchema.optional()
207
208
  }),
208
209
  import_zod.z.object({
@@ -276,8 +277,9 @@ function getSessionTimeout(authType) {
276
277
  function extractUsername(auth) {
277
278
  switch (auth.type) {
278
279
  case "basic":
279
- case "saml":
280
280
  return auth.username;
281
+ case "saml":
282
+ return auth.sapUser;
281
283
  case "sso":
282
284
  return process.env["USERNAME"] ?? process.env["USER"] ?? "SSO_USER";
283
285
  default: {
@@ -682,6 +684,46 @@ function extractActivationErrors(objects, xml, _extension) {
682
684
  return ok(results);
683
685
  }
684
686
 
687
+ // src/core/adt/discovery/packages.ts
688
+ async function getPackages(client, filter = "*") {
689
+ const params = new URLSearchParams([
690
+ ["operation", "quickSearch"],
691
+ ["query", filter],
692
+ ["maxResults", "10001"],
693
+ ["objectType", "DEVC/K"]
694
+ ]);
695
+ const [response, requestErr] = await client.request({
696
+ method: "GET",
697
+ path: `/sap/bc/adt/repository/informationsystem/search?${params.toString()}`
698
+ });
699
+ if (requestErr) {
700
+ return err(requestErr);
701
+ }
702
+ if (!response.ok) {
703
+ const text2 = await response.text();
704
+ const errorMsg = extractError(text2);
705
+ return err(new Error(`Package search failed: ${errorMsg}`));
706
+ }
707
+ const text = await response.text();
708
+ const [doc, parseErr] = safeParseXml(text);
709
+ if (parseErr) {
710
+ return err(parseErr);
711
+ }
712
+ const packages = [];
713
+ const objectRefs = doc.getElementsByTagNameNS("http://www.sap.com/adt/core", "objectReference");
714
+ for (let i = 0; i < objectRefs.length; i++) {
715
+ const obj = objectRefs[i];
716
+ if (!obj) return err(new Error("Invalid object reference in package search results"));
717
+ const name = obj.getAttributeNS("http://www.sap.com/adt/core", "name") || obj.getAttribute("adtcore:name");
718
+ const description = obj.getAttributeNS("http://www.sap.com/adt/core", "description") || obj.getAttribute("adtcore:description");
719
+ if (!name) return err(new Error("Package name missing in object reference"));
720
+ const pkg = { name };
721
+ if (description) pkg.description = description;
722
+ packages.push(pkg);
723
+ }
724
+ return ok(packages);
725
+ }
726
+
685
727
  // src/core/adt/discovery/tree.ts
686
728
  async function getTree(client, query) {
687
729
  const internalQuery = {};
@@ -799,32 +841,23 @@ function parseTreeResponse(xml) {
799
841
  return ok({ nodes, packages });
800
842
  }
801
843
 
802
- // src/core/adt/discovery/packages.ts
803
- async function getPackages(client, filter = "*") {
804
- const [treeResult, treeErr] = await getTreeInternal(client, {}, filter);
805
- if (treeErr) {
806
- return err(treeErr);
807
- }
808
- return ok(treeResult.packages);
809
- }
810
-
811
844
  // src/core/adt/transports/transports.ts
812
845
  async function getTransports(client, packageName) {
813
846
  const contentType = "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData";
814
847
  const body = `<?xml version="1.0" encoding="UTF-8"?>
815
- <asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml">
816
- <asx:values>
817
- <DATA>
818
- <PGMID></PGMID>
819
- <OBJECT></OBJECT>
820
- <OBJECTNAME></OBJECTNAME>
821
- <DEVCLASS>${packageName}</DEVCLASS>
822
- <SUPER_PACKAGE></SUPER_PACKAGE>
823
- <OPERATION>I</OPERATION>
824
- <URI>/sap/bc/adt/ddic/ddl/sources/transport_check</URI>
825
- </DATA>
826
- </asx:values>
827
- </asx:abap>`;
848
+ <asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml">
849
+ <asx:values>
850
+ <DATA>
851
+ <PGMID></PGMID>
852
+ <OBJECT></OBJECT>
853
+ <OBJECTNAME></OBJECTNAME>
854
+ <DEVCLASS>${packageName}</DEVCLASS>
855
+ <SUPER_PACKAGE></SUPER_PACKAGE>
856
+ <OPERATION>I</OPERATION>
857
+ <URI>/sap/bc/adt/ddic/ddl/sources/zsnap_test4transports</URI>
858
+ </DATA>
859
+ </asx:values>
860
+ </asx:abap>`;
828
861
  const [response, requestErr] = await client.request({
829
862
  method: "POST",
830
863
  path: "/sap/bc/adt/cts/transportchecks",
@@ -834,44 +867,33 @@ async function getTransports(client, packageName) {
834
867
  },
835
868
  body
836
869
  });
837
- if (requestErr) {
838
- return err(requestErr);
839
- }
870
+ if (requestErr) return err(requestErr);
840
871
  if (!response.ok) {
841
872
  const text2 = await response.text();
842
873
  const errorMsg = extractError(text2);
843
- return err(new Error(`Failed to fetch transports for ${packageName}: ${errorMsg}`));
874
+ return err(new Error(`Failed to fetch transports for package ${packageName}: ${errorMsg}`));
844
875
  }
845
876
  const text = await response.text();
846
877
  const [transports, parseErr] = extractTransports(text);
847
- if (parseErr) {
848
- return err(parseErr);
849
- }
878
+ if (parseErr) return err(parseErr);
850
879
  return ok(transports);
851
880
  }
852
881
  function extractTransports(xml) {
853
882
  const [doc, parseErr] = safeParseXml(xml);
854
- if (parseErr) {
855
- return err(parseErr);
856
- }
883
+ if (parseErr) return err(parseErr);
857
884
  const transports = [];
858
885
  const reqHeaders = doc.getElementsByTagName("REQ_HEADER");
859
886
  for (let i = 0; i < reqHeaders.length; i++) {
860
887
  const header = reqHeaders[i];
861
888
  if (!header) continue;
862
- const trkorrElement = header.getElementsByTagName("TRKORR")[0];
863
- const userElement = header.getElementsByTagName("AS4USER")[0];
864
- const textElement = header.getElementsByTagName("AS4TEXT")[0];
865
- if (!trkorrElement || !userElement || !textElement) continue;
866
- const id = trkorrElement.textContent;
867
- const owner = userElement.textContent;
868
- const description = textElement.textContent;
869
- if (!id || !owner || !description) continue;
889
+ const id = header.getElementsByTagName("TRKORR")[0]?.textContent;
890
+ const owner = header.getElementsByTagName("AS4USER")[0]?.textContent;
891
+ const description = header.getElementsByTagName("AS4TEXT")[0]?.textContent;
892
+ if (!id) continue;
870
893
  transports.push({
871
894
  id,
872
- owner,
873
- description,
874
- status: "modifiable"
895
+ description: description || "",
896
+ owner: owner || ""
875
897
  });
876
898
  }
877
899
  return ok(transports);
@@ -1832,11 +1854,22 @@ var SamlAuth = class {
1832
1854
  if (!config.username || !config.password) {
1833
1855
  throw new Error("SamlAuth requires both username and password");
1834
1856
  }
1857
+ if (!config.sapUser) {
1858
+ throw new Error("SamlAuth requires sapUser (SAP system username for object creation)");
1859
+ }
1835
1860
  if (!config.baseUrl) {
1836
1861
  throw new Error("SamlAuth requires baseUrl");
1837
1862
  }
1838
1863
  this.config = config;
1839
1864
  }
1865
+ /**
1866
+ * Get SAP system username
1867
+ *
1868
+ * Used for object creation (adtcore:responsible) instead of the SAML email.
1869
+ */
1870
+ getSapUser() {
1871
+ return this.config.sapUser;
1872
+ }
1840
1873
  /**
1841
1874
  * Get auth headers for SAML
1842
1875
  *
@@ -1900,6 +1933,7 @@ function createAuthStrategy(options) {
1900
1933
  return new SamlAuth({
1901
1934
  username: config.username,
1902
1935
  password: config.password,
1936
+ sapUser: config.sapUser,
1903
1937
  baseUrl,
1904
1938
  ...config.providerConfig && { providerConfig: config.providerConfig }
1905
1939
  });
@@ -2092,6 +2126,13 @@ var ADTClientImpl = class {
2092
2126
  return err(loginErr);
2093
2127
  }
2094
2128
  }
2129
+ if (authStrategy.type === "saml" && authStrategy.getCookies) {
2130
+ const cookies = authStrategy.getCookies();
2131
+ for (const cookie of cookies) {
2132
+ this.state.cookies.set(cookie.name, cookie.value);
2133
+ }
2134
+ debug(`Transferred ${cookies.length} SAML cookies to client`);
2135
+ }
2095
2136
  if (authStrategy.type === "sso" && authStrategy.getCertificates) {
2096
2137
  const certs = authStrategy.getCertificates();
2097
2138
  if (certs) {