catalyst-relay 0.2.4 → 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.mjs CHANGED
@@ -142,6 +142,11 @@ function debugError(message, cause) {
142
142
  }
143
143
  }
144
144
 
145
+ // src/core/utils/content.ts
146
+ function normalizeContent(content) {
147
+ return content.replace(/\s+/g, " ").trim();
148
+ }
149
+
145
150
  // src/types/config.ts
146
151
  import { z } from "zod";
147
152
  var samlFormSelectorsSchema = z.object({
@@ -166,6 +171,7 @@ var clientConfigSchema = z.object({
166
171
  type: z.literal("saml"),
167
172
  username: z.string().min(1),
168
173
  password: z.string().min(1),
174
+ sapUser: z.string().min(1),
169
175
  providerConfig: samlProviderConfigSchema.optional()
170
176
  }),
171
177
  z.object({
@@ -239,8 +245,9 @@ function getSessionTimeout(authType) {
239
245
  function extractUsername(auth) {
240
246
  switch (auth.type) {
241
247
  case "basic":
242
- case "saml":
243
248
  return auth.username;
249
+ case "saml":
250
+ return auth.sapUser;
244
251
  case "sso":
245
252
  return process.env["USERNAME"] ?? process.env["USER"] ?? "SSO_USER";
246
253
  default: {
@@ -645,6 +652,46 @@ function extractActivationErrors(objects, xml, _extension) {
645
652
  return ok(results);
646
653
  }
647
654
 
655
+ // src/core/adt/discovery/packages.ts
656
+ async function getPackages(client, filter = "*") {
657
+ const params = new URLSearchParams([
658
+ ["operation", "quickSearch"],
659
+ ["query", filter],
660
+ ["maxResults", "10001"],
661
+ ["objectType", "DEVC/K"]
662
+ ]);
663
+ const [response, requestErr] = await client.request({
664
+ method: "GET",
665
+ path: `/sap/bc/adt/repository/informationsystem/search?${params.toString()}`
666
+ });
667
+ if (requestErr) {
668
+ return err(requestErr);
669
+ }
670
+ if (!response.ok) {
671
+ const text2 = await response.text();
672
+ const errorMsg = extractError(text2);
673
+ return err(new Error(`Package search failed: ${errorMsg}`));
674
+ }
675
+ const text = await response.text();
676
+ const [doc, parseErr] = safeParseXml(text);
677
+ if (parseErr) {
678
+ return err(parseErr);
679
+ }
680
+ const packages = [];
681
+ const objectRefs = doc.getElementsByTagNameNS("http://www.sap.com/adt/core", "objectReference");
682
+ for (let i = 0; i < objectRefs.length; i++) {
683
+ const obj = objectRefs[i];
684
+ if (!obj) return err(new Error("Invalid object reference in package search results"));
685
+ const name = obj.getAttributeNS("http://www.sap.com/adt/core", "name") || obj.getAttribute("adtcore:name");
686
+ const description = obj.getAttributeNS("http://www.sap.com/adt/core", "description") || obj.getAttribute("adtcore:description");
687
+ if (!name) return err(new Error("Package name missing in object reference"));
688
+ const pkg = { name };
689
+ if (description) pkg.description = description;
690
+ packages.push(pkg);
691
+ }
692
+ return ok(packages);
693
+ }
694
+
648
695
  // src/core/adt/discovery/tree.ts
649
696
  async function getTree(client, query) {
650
697
  const internalQuery = {};
@@ -762,32 +809,23 @@ function parseTreeResponse(xml) {
762
809
  return ok({ nodes, packages });
763
810
  }
764
811
 
765
- // src/core/adt/discovery/packages.ts
766
- async function getPackages(client) {
767
- const [treeResult, treeErr] = await getTreeInternal(client, {}, "*");
768
- if (treeErr) {
769
- return err(treeErr);
770
- }
771
- return ok(treeResult.packages);
772
- }
773
-
774
812
  // src/core/adt/transports/transports.ts
775
813
  async function getTransports(client, packageName) {
776
814
  const contentType = "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData";
777
815
  const body = `<?xml version="1.0" encoding="UTF-8"?>
778
- <asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml">
779
- <asx:values>
780
- <DATA>
781
- <PGMID></PGMID>
782
- <OBJECT></OBJECT>
783
- <OBJECTNAME></OBJECTNAME>
784
- <DEVCLASS>${packageName}</DEVCLASS>
785
- <SUPER_PACKAGE></SUPER_PACKAGE>
786
- <OPERATION>I</OPERATION>
787
- <URI>/sap/bc/adt/ddic/ddl/sources/transport_check</URI>
788
- </DATA>
789
- </asx:values>
790
- </asx:abap>`;
816
+ <asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml">
817
+ <asx:values>
818
+ <DATA>
819
+ <PGMID></PGMID>
820
+ <OBJECT></OBJECT>
821
+ <OBJECTNAME></OBJECTNAME>
822
+ <DEVCLASS>${packageName}</DEVCLASS>
823
+ <SUPER_PACKAGE></SUPER_PACKAGE>
824
+ <OPERATION>I</OPERATION>
825
+ <URI>/sap/bc/adt/ddic/ddl/sources/zsnap_test4transports</URI>
826
+ </DATA>
827
+ </asx:values>
828
+ </asx:abap>`;
791
829
  const [response, requestErr] = await client.request({
792
830
  method: "POST",
793
831
  path: "/sap/bc/adt/cts/transportchecks",
@@ -797,44 +835,33 @@ async function getTransports(client, packageName) {
797
835
  },
798
836
  body
799
837
  });
800
- if (requestErr) {
801
- return err(requestErr);
802
- }
838
+ if (requestErr) return err(requestErr);
803
839
  if (!response.ok) {
804
840
  const text2 = await response.text();
805
841
  const errorMsg = extractError(text2);
806
- return err(new Error(`Failed to fetch transports for ${packageName}: ${errorMsg}`));
842
+ return err(new Error(`Failed to fetch transports for package ${packageName}: ${errorMsg}`));
807
843
  }
808
844
  const text = await response.text();
809
845
  const [transports, parseErr] = extractTransports(text);
810
- if (parseErr) {
811
- return err(parseErr);
812
- }
846
+ if (parseErr) return err(parseErr);
813
847
  return ok(transports);
814
848
  }
815
849
  function extractTransports(xml) {
816
850
  const [doc, parseErr] = safeParseXml(xml);
817
- if (parseErr) {
818
- return err(parseErr);
819
- }
851
+ if (parseErr) return err(parseErr);
820
852
  const transports = [];
821
853
  const reqHeaders = doc.getElementsByTagName("REQ_HEADER");
822
854
  for (let i = 0; i < reqHeaders.length; i++) {
823
855
  const header = reqHeaders[i];
824
856
  if (!header) continue;
825
- const trkorrElement = header.getElementsByTagName("TRKORR")[0];
826
- const userElement = header.getElementsByTagName("AS4USER")[0];
827
- const textElement = header.getElementsByTagName("AS4TEXT")[0];
828
- if (!trkorrElement || !userElement || !textElement) continue;
829
- const id = trkorrElement.textContent;
830
- const owner = userElement.textContent;
831
- const description = textElement.textContent;
832
- if (!id || !owner || !description) continue;
857
+ const id = header.getElementsByTagName("TRKORR")[0]?.textContent;
858
+ const owner = header.getElementsByTagName("AS4USER")[0]?.textContent;
859
+ const description = header.getElementsByTagName("AS4TEXT")[0]?.textContent;
860
+ if (!id) continue;
833
861
  transports.push({
834
862
  id,
835
- owner,
836
- description,
837
- status: "modifiable"
863
+ description: description || "",
864
+ owner: owner || ""
838
865
  });
839
866
  }
840
867
  return ok(transports);
@@ -1795,11 +1822,22 @@ var SamlAuth = class {
1795
1822
  if (!config.username || !config.password) {
1796
1823
  throw new Error("SamlAuth requires both username and password");
1797
1824
  }
1825
+ if (!config.sapUser) {
1826
+ throw new Error("SamlAuth requires sapUser (SAP system username for object creation)");
1827
+ }
1798
1828
  if (!config.baseUrl) {
1799
1829
  throw new Error("SamlAuth requires baseUrl");
1800
1830
  }
1801
1831
  this.config = config;
1802
1832
  }
1833
+ /**
1834
+ * Get SAP system username
1835
+ *
1836
+ * Used for object creation (adtcore:responsible) instead of the SAML email.
1837
+ */
1838
+ getSapUser() {
1839
+ return this.config.sapUser;
1840
+ }
1803
1841
  /**
1804
1842
  * Get auth headers for SAML
1805
1843
  *
@@ -1863,6 +1901,7 @@ function createAuthStrategy(options) {
1863
1901
  return new SamlAuth({
1864
1902
  username: config.username,
1865
1903
  password: config.password,
1904
+ sapUser: config.sapUser,
1866
1905
  baseUrl,
1867
1906
  ...config.providerConfig && { providerConfig: config.providerConfig }
1868
1907
  });
@@ -1988,6 +2027,9 @@ var ADTClientImpl = class {
1988
2027
  if (this.agent) {
1989
2028
  fetchOptions.dispatcher = this.agent;
1990
2029
  }
2030
+ if (config.insecure) {
2031
+ fetchOptions.tls = { rejectUnauthorized: false };
2032
+ }
1991
2033
  if (body) {
1992
2034
  fetchOptions.body = body;
1993
2035
  }
@@ -2052,6 +2094,13 @@ var ADTClientImpl = class {
2052
2094
  return err(loginErr);
2053
2095
  }
2054
2096
  }
2097
+ if (authStrategy.type === "saml" && authStrategy.getCookies) {
2098
+ const cookies = authStrategy.getCookies();
2099
+ for (const cookie of cookies) {
2100
+ this.state.cookies.set(cookie.name, cookie.value);
2101
+ }
2102
+ debug(`Transferred ${cookies.length} SAML cookies to client`);
2103
+ }
2055
2104
  if (authStrategy.type === "sso" && authStrategy.getCertificates) {
2056
2105
  const certs = authStrategy.getCertificates();
2057
2106
  if (certs) {
@@ -2128,6 +2177,18 @@ var ADTClientImpl = class {
2128
2177
  results.push(result2);
2129
2178
  continue;
2130
2179
  }
2180
+ const serverContent = normalizeContent(existing.content);
2181
+ const localContent = normalizeContent(obj.content);
2182
+ if (serverContent === localContent) {
2183
+ const result2 = {
2184
+ name: obj.name,
2185
+ extension: obj.extension,
2186
+ status: "unchanged"
2187
+ };
2188
+ if (transport) result2.transport = transport;
2189
+ results.push(result2);
2190
+ continue;
2191
+ }
2131
2192
  const [, updateErr] = await this.update(obj, transport);
2132
2193
  if (updateErr) return err(updateErr);
2133
2194
  const result = {
@@ -2158,9 +2219,9 @@ var ADTClientImpl = class {
2158
2219
  return ok(void 0);
2159
2220
  }
2160
2221
  // --- Discovery ---
2161
- async getPackages() {
2222
+ async getPackages(filter) {
2162
2223
  if (!this.state.session) return err(new Error("Not logged in"));
2163
- return getPackages(this.requestor);
2224
+ return getPackages(this.requestor, filter);
2164
2225
  }
2165
2226
  async getTree(query) {
2166
2227
  if (!this.state.session) return err(new Error("Not logged in"));