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 +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +85 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +85 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
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
|
|
863
|
-
const
|
|
864
|
-
const
|
|
865
|
-
if (!
|
|
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
|
-
|
|
873
|
-
|
|
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) {
|