catalyst-relay 0.5.13 → 0.6.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/README.md +58 -16
- package/dist/index.d.mts +71 -1
- package/dist/index.d.ts +71 -1
- package/dist/index.js +631 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +630 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
BehaviorImplementationType: () => BehaviorImplementationType,
|
|
33
34
|
ExternalReferencesError: () => ExternalReferencesError,
|
|
34
35
|
activateLogging: () => activateLogging,
|
|
35
36
|
buildSQLQuery: () => buildSQLQuery,
|
|
@@ -537,6 +538,12 @@ var SsoAuth = class {
|
|
|
537
538
|
}
|
|
538
539
|
};
|
|
539
540
|
|
|
541
|
+
// src/core/auth/saml/browser.ts
|
|
542
|
+
var import_node_child_process = require("child_process");
|
|
543
|
+
var import_node_fs = require("fs");
|
|
544
|
+
var import_node_os = require("os");
|
|
545
|
+
var import_node_path2 = require("path");
|
|
546
|
+
|
|
540
547
|
// src/core/auth/saml/types.ts
|
|
541
548
|
var DEFAULT_FORM_SELECTORS = {
|
|
542
549
|
username: "#j_username",
|
|
@@ -551,9 +558,16 @@ var DEFAULT_PROVIDER_CONFIG = {
|
|
|
551
558
|
// src/core/auth/saml/browser.ts
|
|
552
559
|
var TIMEOUTS = {
|
|
553
560
|
PAGE_LOAD: 6e4,
|
|
554
|
-
FORM_SELECTOR:
|
|
561
|
+
FORM_SELECTOR: 15e3,
|
|
562
|
+
NETWORK_IDLE: 3e4,
|
|
563
|
+
/** Quiet period with no in-flight requests that counts as "idle". */
|
|
564
|
+
IDLE_QUIET: 600
|
|
555
565
|
};
|
|
566
|
+
var isBun = typeof globalThis.Bun !== "undefined";
|
|
556
567
|
async function performBrowserLogin(options) {
|
|
568
|
+
return isBun ? performBrowserLoginViaCdp(options) : performBrowserLoginViaPlaywright(options);
|
|
569
|
+
}
|
|
570
|
+
async function performBrowserLoginViaPlaywright(options) {
|
|
557
571
|
const { baseUrl, credentials, headless = true } = options;
|
|
558
572
|
const config = options.providerConfig ?? DEFAULT_PROVIDER_CONFIG;
|
|
559
573
|
let playwright;
|
|
@@ -611,6 +625,222 @@ async function performBrowserLogin(options) {
|
|
|
611
625
|
await browser.close();
|
|
612
626
|
}
|
|
613
627
|
}
|
|
628
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
629
|
+
async function resolveChromiumPath() {
|
|
630
|
+
const override = process.env["CATALYST_CHROMIUM_PATH"];
|
|
631
|
+
if (override) return [override, null];
|
|
632
|
+
try {
|
|
633
|
+
const playwright = await import("playwright");
|
|
634
|
+
const path = playwright.chromium.executablePath();
|
|
635
|
+
if (!path) {
|
|
636
|
+
return [null, new Error("Could not resolve the Chromium executable path from Playwright.")];
|
|
637
|
+
}
|
|
638
|
+
return [path, null];
|
|
639
|
+
} catch {
|
|
640
|
+
return [
|
|
641
|
+
null,
|
|
642
|
+
new Error(
|
|
643
|
+
"Playwright is required for SAML authentication but is not installed. Install it with: npm install playwright"
|
|
644
|
+
)
|
|
645
|
+
];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
async function connectCdp(wsUrl) {
|
|
649
|
+
const WebSocketCtor = globalThis.WebSocket;
|
|
650
|
+
if (!WebSocketCtor) {
|
|
651
|
+
throw new Error("Native WebSocket is not available in this runtime.");
|
|
652
|
+
}
|
|
653
|
+
const ws = new WebSocketCtor(wsUrl);
|
|
654
|
+
let nextId = 0;
|
|
655
|
+
const pending = /* @__PURE__ */ new Map();
|
|
656
|
+
const eventHandlers = [];
|
|
657
|
+
ws.onmessage = (event) => {
|
|
658
|
+
const msg = JSON.parse(String(event.data));
|
|
659
|
+
if (typeof msg.id === "number" && pending.has(msg.id)) {
|
|
660
|
+
const { resolve, reject } = pending.get(msg.id);
|
|
661
|
+
pending.delete(msg.id);
|
|
662
|
+
if (msg.error) reject(new Error(msg.error.message));
|
|
663
|
+
else resolve(msg.result ?? {});
|
|
664
|
+
} else if (msg.method) {
|
|
665
|
+
for (const handler of eventHandlers) {
|
|
666
|
+
handler({
|
|
667
|
+
method: msg.method,
|
|
668
|
+
params: msg.params ?? {},
|
|
669
|
+
...msg.sessionId !== void 0 ? { sessionId: msg.sessionId } : {}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
await new Promise((resolve, reject) => {
|
|
675
|
+
ws.onopen = () => resolve();
|
|
676
|
+
ws.onerror = () => reject(new Error("Failed to connect to the browser CDP endpoint."));
|
|
677
|
+
});
|
|
678
|
+
return {
|
|
679
|
+
send(method, params = {}, sessionId) {
|
|
680
|
+
return new Promise((resolve, reject) => {
|
|
681
|
+
const id = ++nextId;
|
|
682
|
+
pending.set(id, { resolve, reject });
|
|
683
|
+
ws.send(JSON.stringify({ id, method, params, ...sessionId ? { sessionId } : {} }));
|
|
684
|
+
});
|
|
685
|
+
},
|
|
686
|
+
on(handler) {
|
|
687
|
+
eventHandlers.push(handler);
|
|
688
|
+
},
|
|
689
|
+
close() {
|
|
690
|
+
ws.close();
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
async function performBrowserLoginViaCdp(options) {
|
|
695
|
+
const { baseUrl, credentials, headless = true } = options;
|
|
696
|
+
const config = options.providerConfig ?? DEFAULT_PROVIDER_CONFIG;
|
|
697
|
+
const [exePath, pathError] = await resolveChromiumPath();
|
|
698
|
+
if (pathError) return err(pathError);
|
|
699
|
+
const userDataDir = (0, import_node_fs.mkdtempSync)((0, import_node_path2.join)((0, import_node_os.tmpdir)(), "catalyst-saml-"));
|
|
700
|
+
const args = [
|
|
701
|
+
...headless ? ["--headless=new"] : [],
|
|
702
|
+
"--remote-debugging-port=0",
|
|
703
|
+
"--no-first-run",
|
|
704
|
+
"--no-default-browser-check",
|
|
705
|
+
`--user-data-dir=${userDataDir}`,
|
|
706
|
+
...config.ignoreHttpsErrors ? ["--ignore-certificate-errors"] : []
|
|
707
|
+
];
|
|
708
|
+
const proc = (0, import_node_child_process.spawn)(exePath, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
709
|
+
let client = null;
|
|
710
|
+
const cleanup = () => {
|
|
711
|
+
try {
|
|
712
|
+
client?.close();
|
|
713
|
+
} catch {
|
|
714
|
+
}
|
|
715
|
+
try {
|
|
716
|
+
proc.kill();
|
|
717
|
+
} catch {
|
|
718
|
+
}
|
|
719
|
+
try {
|
|
720
|
+
(0, import_node_fs.rmSync)(userDataDir, { recursive: true, force: true });
|
|
721
|
+
} catch {
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
try {
|
|
725
|
+
const browserWsUrl = await new Promise((resolve, reject) => {
|
|
726
|
+
let buffer = "";
|
|
727
|
+
const timer = setTimeout(
|
|
728
|
+
() => reject(new Error("Failed to launch browser: timed out waiting for the CDP endpoint.")),
|
|
729
|
+
TIMEOUTS.PAGE_LOAD
|
|
730
|
+
);
|
|
731
|
+
proc.stderr?.on("data", (chunk) => {
|
|
732
|
+
buffer += String(chunk);
|
|
733
|
+
const match = buffer.match(/DevTools listening on (ws:\/\/\S+)/);
|
|
734
|
+
if (match) {
|
|
735
|
+
clearTimeout(timer);
|
|
736
|
+
resolve(match[1]);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
proc.on("error", (e) => {
|
|
740
|
+
clearTimeout(timer);
|
|
741
|
+
reject(new Error(`Failed to launch browser: ${e instanceof Error ? e.message : String(e)}`));
|
|
742
|
+
});
|
|
743
|
+
proc.on("exit", (code) => {
|
|
744
|
+
clearTimeout(timer);
|
|
745
|
+
reject(new Error(`Failed to launch browser: process exited early (code ${code}).`));
|
|
746
|
+
});
|
|
747
|
+
});
|
|
748
|
+
client = await connectCdp(browserWsUrl);
|
|
749
|
+
const { targetId } = await client.send("Target.createTarget", { url: "about:blank" });
|
|
750
|
+
const { sessionId } = await client.send("Target.attachToTarget", {
|
|
751
|
+
targetId,
|
|
752
|
+
flatten: true
|
|
753
|
+
});
|
|
754
|
+
let inflight = 0;
|
|
755
|
+
let lastNetworkChange = Date.now();
|
|
756
|
+
client.on((msg) => {
|
|
757
|
+
if (msg.sessionId !== sessionId) return;
|
|
758
|
+
if (msg.method === "Network.requestWillBeSent") {
|
|
759
|
+
inflight += 1;
|
|
760
|
+
lastNetworkChange = Date.now();
|
|
761
|
+
} else if (msg.method === "Network.loadingFinished" || msg.method === "Network.loadingFailed") {
|
|
762
|
+
inflight = Math.max(0, inflight - 1);
|
|
763
|
+
lastNetworkChange = Date.now();
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
await client.send("Page.enable", {}, sessionId);
|
|
767
|
+
await client.send("Network.enable", {}, sessionId);
|
|
768
|
+
await client.send("Runtime.enable", {}, sessionId);
|
|
769
|
+
const loginUrl = `${baseUrl}/sap/bc/adt/compatibility/graph`;
|
|
770
|
+
const navResult = await client.send("Page.navigate", { url: loginUrl }, sessionId);
|
|
771
|
+
if (navResult.errorText) {
|
|
772
|
+
return err(new Error("Failed to load login page. Please check if the server is online."));
|
|
773
|
+
}
|
|
774
|
+
const usernameSel = config.formSelectors.username;
|
|
775
|
+
const formFound = await waitForSelector(client, sessionId, usernameSel, TIMEOUTS.FORM_SELECTOR);
|
|
776
|
+
if (!formFound) {
|
|
777
|
+
return err(new Error("Login form not found. The page may have changed or loaded incorrectly."));
|
|
778
|
+
}
|
|
779
|
+
const fillExpr = `(() => {
|
|
780
|
+
const u = document.querySelector(${JSON.stringify(config.formSelectors.username)});
|
|
781
|
+
const p = document.querySelector(${JSON.stringify(config.formSelectors.password)});
|
|
782
|
+
const s = document.querySelector(${JSON.stringify(config.formSelectors.submit)});
|
|
783
|
+
if (!u || !p || !s) return false;
|
|
784
|
+
const set = (el, val) => {
|
|
785
|
+
el.value = val;
|
|
786
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
787
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
788
|
+
};
|
|
789
|
+
set(u, ${JSON.stringify(credentials.username)});
|
|
790
|
+
set(p, ${JSON.stringify(credentials.password)});
|
|
791
|
+
s.click();
|
|
792
|
+
return true;
|
|
793
|
+
})()`;
|
|
794
|
+
const fillResult = await client.send(
|
|
795
|
+
"Runtime.evaluate",
|
|
796
|
+
{ expression: fillExpr, returnByValue: true },
|
|
797
|
+
sessionId
|
|
798
|
+
);
|
|
799
|
+
if (fillResult.result?.value !== true) {
|
|
800
|
+
return err(new Error("Login form not found. The page may have changed or loaded incorrectly."));
|
|
801
|
+
}
|
|
802
|
+
const idleStart = Date.now();
|
|
803
|
+
while (Date.now() - idleStart < TIMEOUTS.NETWORK_IDLE) {
|
|
804
|
+
if (inflight === 0 && Date.now() - lastNetworkChange > TIMEOUTS.IDLE_QUIET) break;
|
|
805
|
+
await sleep(100);
|
|
806
|
+
}
|
|
807
|
+
const { cookies } = await client.send("Network.getAllCookies", {}, sessionId);
|
|
808
|
+
return ok(cookies.map(toPlaywrightCookie));
|
|
809
|
+
} catch (e) {
|
|
810
|
+
return err(
|
|
811
|
+
new Error(`SAML browser login failed: ${e instanceof Error ? e.message : String(e)}`)
|
|
812
|
+
);
|
|
813
|
+
} finally {
|
|
814
|
+
cleanup();
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
async function waitForSelector(client, sessionId, selector, timeoutMs) {
|
|
818
|
+
const start = Date.now();
|
|
819
|
+
const expression = `!!document.querySelector(${JSON.stringify(selector)})`;
|
|
820
|
+
while (Date.now() - start < timeoutMs) {
|
|
821
|
+
const res = await client.send(
|
|
822
|
+
"Runtime.evaluate",
|
|
823
|
+
{ expression, returnByValue: true },
|
|
824
|
+
sessionId
|
|
825
|
+
);
|
|
826
|
+
if (res.result?.value === true) return true;
|
|
827
|
+
await sleep(200);
|
|
828
|
+
}
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
function toPlaywrightCookie(c) {
|
|
832
|
+
const sameSite = c.sameSite === "Strict" || c.sameSite === "Lax" || c.sameSite === "None" ? c.sameSite : "Lax";
|
|
833
|
+
return {
|
|
834
|
+
name: c.name,
|
|
835
|
+
value: c.value,
|
|
836
|
+
domain: c.domain,
|
|
837
|
+
path: c.path,
|
|
838
|
+
expires: typeof c.expires === "number" ? c.expires : -1,
|
|
839
|
+
httpOnly: Boolean(c.httpOnly),
|
|
840
|
+
secure: Boolean(c.secure),
|
|
841
|
+
sameSite
|
|
842
|
+
};
|
|
843
|
+
}
|
|
614
844
|
|
|
615
845
|
// src/core/auth/saml/cookies.ts
|
|
616
846
|
function toAuthCookies(playwrightCookies) {
|
|
@@ -815,6 +1045,16 @@ function extractError(xml) {
|
|
|
815
1045
|
const message = messageElement?.textContent;
|
|
816
1046
|
return message || "No message found";
|
|
817
1047
|
}
|
|
1048
|
+
function extractTagText(xml, tagName) {
|
|
1049
|
+
if (!xml) return null;
|
|
1050
|
+
const [doc, parseErr] = safeParseXml(xml);
|
|
1051
|
+
if (parseErr) return null;
|
|
1052
|
+
const elements = doc.getElementsByTagName(tagName);
|
|
1053
|
+
if (elements.length === 0) return null;
|
|
1054
|
+
const text = elements[0]?.textContent;
|
|
1055
|
+
if (!text || text.trim().length === 0) return null;
|
|
1056
|
+
return text.trim();
|
|
1057
|
+
}
|
|
818
1058
|
function escapeXml(str) {
|
|
819
1059
|
if (!str) {
|
|
820
1060
|
return "";
|
|
@@ -1235,6 +1475,24 @@ var OBJECT_CONFIG_MAP = {
|
|
|
1235
1475
|
type: "PROG/I",
|
|
1236
1476
|
label: "ABAP Include" /* INCLUDE */,
|
|
1237
1477
|
extension: "asinc"
|
|
1478
|
+
},
|
|
1479
|
+
"srvd": {
|
|
1480
|
+
endpoint: "ddic/srvd/sources",
|
|
1481
|
+
nameSpace: 'xmlns:srvd="http://www.sap.com/adt/ddic/srvdsources"',
|
|
1482
|
+
rootName: "srvd:srvdSource",
|
|
1483
|
+
type: "SRVD/SRV",
|
|
1484
|
+
label: "Service Definition" /* SERVICE_DEFINITION */,
|
|
1485
|
+
extension: "srvd",
|
|
1486
|
+
rootAttributes: { "srvd:srvdSourceType": "S" }
|
|
1487
|
+
},
|
|
1488
|
+
"asbdef": {
|
|
1489
|
+
endpoint: "bo/behaviordefinitions",
|
|
1490
|
+
nameSpace: 'xmlns:blue="http://www.sap.com/wbobj/blue"',
|
|
1491
|
+
rootName: "blue:blueSource",
|
|
1492
|
+
type: "BDEF/BDO",
|
|
1493
|
+
label: "Behavior Definition" /* BEHAVIOR_DEFINITION */,
|
|
1494
|
+
extension: "asbdef",
|
|
1495
|
+
requiresImplementationType: true
|
|
1238
1496
|
}
|
|
1239
1497
|
};
|
|
1240
1498
|
function getConfigByExtension(extension) {
|
|
@@ -1547,11 +1805,44 @@ async function multiDeleteObjects(client, objects, transport) {
|
|
|
1547
1805
|
return ok(results);
|
|
1548
1806
|
}
|
|
1549
1807
|
|
|
1808
|
+
// src/types/requests.ts
|
|
1809
|
+
var import_zod2 = require("zod");
|
|
1810
|
+
var BehaviorImplementationType = /* @__PURE__ */ ((BehaviorImplementationType2) => {
|
|
1811
|
+
BehaviorImplementationType2["Managed"] = "Managed";
|
|
1812
|
+
return BehaviorImplementationType2;
|
|
1813
|
+
})(BehaviorImplementationType || {});
|
|
1814
|
+
var objectRefSchema = import_zod2.z.object({
|
|
1815
|
+
name: import_zod2.z.string().min(1),
|
|
1816
|
+
extension: import_zod2.z.string().min(1)
|
|
1817
|
+
});
|
|
1818
|
+
var objectContentSchema = objectRefSchema.extend({
|
|
1819
|
+
content: import_zod2.z.string(),
|
|
1820
|
+
description: import_zod2.z.string().optional(),
|
|
1821
|
+
implementationType: import_zod2.z.nativeEnum(BehaviorImplementationType).optional()
|
|
1822
|
+
});
|
|
1823
|
+
var treeQuerySchema = import_zod2.z.object({
|
|
1824
|
+
package: import_zod2.z.string().min(1).optional(),
|
|
1825
|
+
path: import_zod2.z.string().optional(),
|
|
1826
|
+
owner: import_zod2.z.string().min(1).optional()
|
|
1827
|
+
});
|
|
1828
|
+
var previewQuerySchema = import_zod2.z.object({
|
|
1829
|
+
objectName: import_zod2.z.string().min(1),
|
|
1830
|
+
objectType: import_zod2.z.enum(["table", "view"]),
|
|
1831
|
+
sqlQuery: import_zod2.z.string().min(1),
|
|
1832
|
+
limit: import_zod2.z.number().positive().max(5e4).optional()
|
|
1833
|
+
});
|
|
1834
|
+
|
|
1550
1835
|
// src/core/adt/craud/create.ts
|
|
1551
1836
|
async function createObject(client, object, packageName, transport, username) {
|
|
1552
1837
|
const [config, configErr] = requireConfig(object.extension);
|
|
1553
1838
|
if (configErr) return err(configErr);
|
|
1554
1839
|
const description = object.description ?? "";
|
|
1840
|
+
const extraAttrs = config.rootAttributes ? Object.entries(config.rootAttributes).map(([key, value]) => `
|
|
1841
|
+
${key}="${escapeXml(value)}"`).join("") : "";
|
|
1842
|
+
const implementationType = object.implementationType ?? "Managed" /* Managed */;
|
|
1843
|
+
const adtTemplate = config.requiresImplementationType ? ` <adtcore:adtTemplate>
|
|
1844
|
+
<adtcore:adtProperty adtcore:key="implementation_type">${implementationType}</adtcore:adtProperty>
|
|
1845
|
+
</adtcore:adtTemplate>` : "";
|
|
1555
1846
|
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1556
1847
|
<${config.rootName} ${config.nameSpace}
|
|
1557
1848
|
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
@@ -1559,8 +1850,8 @@ async function createObject(client, object, packageName, transport, username) {
|
|
|
1559
1850
|
adtcore:language="EN"
|
|
1560
1851
|
adtcore:name="${object.name.toUpperCase()}"
|
|
1561
1852
|
adtcore:type="${config.type}"
|
|
1562
|
-
adtcore:responsible="${username.toUpperCase()}">
|
|
1563
|
-
|
|
1853
|
+
adtcore:responsible="${username.toUpperCase()}"${extraAttrs}>
|
|
1854
|
+
${adtTemplate}
|
|
1564
1855
|
<adtcore:packageRef adtcore:name="${packageName}"/>
|
|
1565
1856
|
|
|
1566
1857
|
</${config.rootName}>`;
|
|
@@ -1621,14 +1912,26 @@ async function activateObjects(client, objects) {
|
|
|
1621
1912
|
if (objects.length === 0) {
|
|
1622
1913
|
return ok([]);
|
|
1623
1914
|
}
|
|
1915
|
+
const references = [];
|
|
1624
1916
|
for (const obj of objects) {
|
|
1625
1917
|
const config = getConfigByExtension(obj.extension);
|
|
1626
1918
|
if (!config) return err(new Error(`Unsupported extension: ${obj.extension}`));
|
|
1919
|
+
references.push({
|
|
1920
|
+
uri: `/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}`,
|
|
1921
|
+
type: config.type,
|
|
1922
|
+
name: obj.name,
|
|
1923
|
+
extension: obj.extension
|
|
1924
|
+
});
|
|
1627
1925
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1926
|
+
return activateByReferences(client, references);
|
|
1927
|
+
}
|
|
1928
|
+
async function activateByReferences(client, references) {
|
|
1929
|
+
if (references.length === 0) {
|
|
1930
|
+
return ok([]);
|
|
1931
|
+
}
|
|
1932
|
+
const objectRefs = references.map(
|
|
1933
|
+
(ref) => `<adtcore:objectReference adtcore:uri="${ref.uri}" adtcore:type="${ref.type}" adtcore:name="${ref.name}"/>`
|
|
1934
|
+
).join("\n ");
|
|
1632
1935
|
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1633
1936
|
<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
|
|
1634
1937
|
${objectRefs}
|
|
@@ -1692,7 +1995,7 @@ async function activateObjects(client, objects) {
|
|
|
1692
1995
|
if (!resultsRes.ok) {
|
|
1693
1996
|
return err(new Error(`Failed to fetch activation results: ${extractError(resultsText)}`));
|
|
1694
1997
|
}
|
|
1695
|
-
const [results, parseErr] = extractActivationErrors(
|
|
1998
|
+
const [results, parseErr] = extractActivationErrors(references, resultsText);
|
|
1696
1999
|
if (parseErr) return err(parseErr);
|
|
1697
2000
|
return ok(results);
|
|
1698
2001
|
}
|
|
@@ -2381,16 +2684,64 @@ function parseDataPreview(xml, maxRows, isTable) {
|
|
|
2381
2684
|
const namespace = "http://www.sap.com/adt/dataPreview";
|
|
2382
2685
|
const metadataElements = doc.getElementsByTagNameNS(namespace, "metadata");
|
|
2383
2686
|
const columns = [];
|
|
2687
|
+
const SAP_TYPE_MAP = {
|
|
2688
|
+
"8": "integer",
|
|
2689
|
+
// Int8
|
|
2690
|
+
"I": "integer",
|
|
2691
|
+
// Integer
|
|
2692
|
+
"P": "decimal",
|
|
2693
|
+
// Packed decimal
|
|
2694
|
+
"F": "float",
|
|
2695
|
+
// Floating point
|
|
2696
|
+
"D": "date",
|
|
2697
|
+
// Date (YYYYMMDD)
|
|
2698
|
+
"T": "time",
|
|
2699
|
+
// Time (HHMMSS)
|
|
2700
|
+
"S": "timestamp",
|
|
2701
|
+
// Timestamp
|
|
2702
|
+
"C": "string",
|
|
2703
|
+
// Character
|
|
2704
|
+
"N": "string",
|
|
2705
|
+
// Numeric character string
|
|
2706
|
+
"V": "string",
|
|
2707
|
+
// Variable-length character
|
|
2708
|
+
"X": "binary"
|
|
2709
|
+
// Raw binary/hex
|
|
2710
|
+
};
|
|
2384
2711
|
for (let i = 0; i < metadataElements.length; i++) {
|
|
2385
2712
|
const meta = metadataElements[i];
|
|
2386
2713
|
if (!meta) continue;
|
|
2387
2714
|
const nameAttr = isTable ? "name" : "camelCaseName";
|
|
2388
2715
|
const name = meta.getAttributeNS(namespace, nameAttr) || meta.getAttribute("name");
|
|
2389
|
-
const
|
|
2716
|
+
const colType = meta.getAttributeNS(namespace, "colType") || meta.getAttribute("colType");
|
|
2717
|
+
const rawType = meta.getAttributeNS(namespace, "type") || meta.getAttribute("type");
|
|
2718
|
+
const isKeyFigure = meta.getAttributeNS(namespace, "isKeyFigure") === "true";
|
|
2719
|
+
let dataType;
|
|
2720
|
+
if (colType && colType.trim() !== "") {
|
|
2721
|
+
dataType = colType;
|
|
2722
|
+
} else if (isKeyFigure) {
|
|
2723
|
+
dataType = "decimal";
|
|
2724
|
+
} else if (rawType && SAP_TYPE_MAP[rawType]) {
|
|
2725
|
+
dataType = SAP_TYPE_MAP[rawType];
|
|
2726
|
+
} else {
|
|
2727
|
+
dataType = "string";
|
|
2728
|
+
}
|
|
2729
|
+
const allAttrs = {};
|
|
2730
|
+
for (let j = 0; j < meta.attributes.length; j++) {
|
|
2731
|
+
const attr = meta.attributes[j];
|
|
2732
|
+
if (!attr) {
|
|
2733
|
+
continue;
|
|
2734
|
+
}
|
|
2735
|
+
allAttrs[attr.name] = attr.value;
|
|
2736
|
+
}
|
|
2390
2737
|
if (!name || !dataType) continue;
|
|
2391
2738
|
columns.push({ name, dataType });
|
|
2392
2739
|
}
|
|
2393
2740
|
const dataSetElements = doc.getElementsByTagNameNS(namespace, "dataSet");
|
|
2741
|
+
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2742
|
+
const dataSet = dataSetElements[i];
|
|
2743
|
+
if (!dataSet) continue;
|
|
2744
|
+
}
|
|
2394
2745
|
if (columns.length === 0 && dataSetElements.length > 0) {
|
|
2395
2746
|
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2396
2747
|
const dataSet = dataSetElements[i];
|
|
@@ -2473,7 +2824,7 @@ async function previewData(client, query) {
|
|
|
2473
2824
|
|
|
2474
2825
|
// src/core/adt/data_extraction/freestyle.ts
|
|
2475
2826
|
var DEFAULT_ROW_LIMIT = 100;
|
|
2476
|
-
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
2827
|
+
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT, timeout) {
|
|
2477
2828
|
debug(`Freestyle query: ${sqlQuery}`);
|
|
2478
2829
|
const [response, requestErr] = await client.request({
|
|
2479
2830
|
method: "POST",
|
|
@@ -2483,16 +2834,21 @@ async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
|
2483
2834
|
},
|
|
2484
2835
|
headers: {
|
|
2485
2836
|
"Accept": "application/xml, application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
2486
|
-
"Content-Type": "text/plain"
|
|
2837
|
+
"Content-Type": "text/plain",
|
|
2838
|
+
// Override stateful base header: each preview request is independent; stateless
|
|
2839
|
+
// lets SAP route to any work process and recycle it after the request, preventing
|
|
2840
|
+
// GENERATE_SUBPOOL_DIR_FULL (36-pool limit per work process).
|
|
2841
|
+
"X-sap-adt-sessiontype": "stateless"
|
|
2487
2842
|
},
|
|
2488
|
-
body: sqlQuery
|
|
2843
|
+
body: sqlQuery,
|
|
2844
|
+
...timeout !== void 0 && { timeout }
|
|
2489
2845
|
});
|
|
2490
2846
|
if (requestErr) return err(requestErr);
|
|
2491
2847
|
if (!response.ok) {
|
|
2492
2848
|
const text2 = await response.text();
|
|
2493
2849
|
debug(`Freestyle query error response: ${text2.substring(0, 500)}`);
|
|
2494
2850
|
const errorMsg = extractError(text2);
|
|
2495
|
-
return err(new Error(`Freestyle query failed: ${errorMsg}
|
|
2851
|
+
return err(new Error(`Freestyle query failed: ${errorMsg}`, { cause: text2 }));
|
|
2496
2852
|
}
|
|
2497
2853
|
const text = await response.text();
|
|
2498
2854
|
const [dataFrame, parseErr] = parseDataPreview(text, limit, true);
|
|
@@ -2753,7 +3109,16 @@ function parseTransportTasks(doc) {
|
|
|
2753
3109
|
position: el.getAttribute("tm:position") || ""
|
|
2754
3110
|
});
|
|
2755
3111
|
}
|
|
2756
|
-
|
|
3112
|
+
const owner = taskEl.getAttribute("tm:owner");
|
|
3113
|
+
const description = taskEl.getAttribute("tm:desc");
|
|
3114
|
+
const status = taskEl.getAttribute("tm:status");
|
|
3115
|
+
tasks.push({
|
|
3116
|
+
taskId,
|
|
3117
|
+
...owner ? { owner } : {},
|
|
3118
|
+
...description ? { description } : {},
|
|
3119
|
+
...status ? { status } : {},
|
|
3120
|
+
objects
|
|
3121
|
+
});
|
|
2757
3122
|
}
|
|
2758
3123
|
return tasks;
|
|
2759
3124
|
}
|
|
@@ -2991,6 +3356,203 @@ async function gitDiff(client, object) {
|
|
|
2991
3356
|
});
|
|
2992
3357
|
}
|
|
2993
3358
|
|
|
3359
|
+
// src/core/adt/businessservices/validate.ts
|
|
3360
|
+
var SEVERITY_OK = "OK";
|
|
3361
|
+
async function validateServiceBinding(client, options) {
|
|
3362
|
+
const bindingType = options.bindingType ?? "ODATA";
|
|
3363
|
+
const bindingVersion = options.bindingVersion ?? "V4";
|
|
3364
|
+
const [response, requestErr] = await client.request({
|
|
3365
|
+
method: "POST",
|
|
3366
|
+
path: "/sap/bc/adt/businessservices/bindings/validation",
|
|
3367
|
+
params: {
|
|
3368
|
+
objname: options.bindingName.toUpperCase(),
|
|
3369
|
+
description: options.description ?? "",
|
|
3370
|
+
serviceBindingVersion: `${bindingType}\\${bindingVersion}`,
|
|
3371
|
+
serviceDefinition: options.serviceDefinition.toUpperCase(),
|
|
3372
|
+
package: options.packageName.toUpperCase()
|
|
3373
|
+
}
|
|
3374
|
+
});
|
|
3375
|
+
const [text, checkErr] = await checkResponse(
|
|
3376
|
+
response,
|
|
3377
|
+
requestErr,
|
|
3378
|
+
`Failed to validate service binding ${options.bindingName}`
|
|
3379
|
+
);
|
|
3380
|
+
if (checkErr) return err(checkErr);
|
|
3381
|
+
const severity = extractTagText(text, "SEVERITY");
|
|
3382
|
+
if (severity && severity !== SEVERITY_OK) {
|
|
3383
|
+
const shortText = extractTagText(text, "SHORT_TEXT") ?? "";
|
|
3384
|
+
return err(new Error(`Service binding validation failed (${severity}): ${shortText}`));
|
|
3385
|
+
}
|
|
3386
|
+
return ok(void 0);
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
// src/core/adt/businessservices/create.ts
|
|
3390
|
+
var SERVICE_BINDING_TYPE_CODE = "SRVB/SVB";
|
|
3391
|
+
var BINDING_CATEGORY = "1";
|
|
3392
|
+
var CONTENT_VERSION = "0001";
|
|
3393
|
+
async function createServiceBindingObject(client, options, username) {
|
|
3394
|
+
const bindingType = options.bindingType ?? "ODATA";
|
|
3395
|
+
const bindingVersion = options.bindingVersion ?? "V4";
|
|
3396
|
+
const description = options.description ?? "";
|
|
3397
|
+
const bindingName = options.bindingName.toUpperCase();
|
|
3398
|
+
const serviceDefinition = options.serviceDefinition.toUpperCase();
|
|
3399
|
+
const packageName = options.packageName.toUpperCase();
|
|
3400
|
+
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
3401
|
+
<srvb:serviceBinding xmlns:srvb="http://www.sap.com/adt/ddic/ServiceBindings" xmlns:adtcore="http://www.sap.com/adt/core" adtcore:description="${escapeXml(description)}" adtcore:language="EN" adtcore:name="${bindingName}" adtcore:type="${SERVICE_BINDING_TYPE_CODE}" adtcore:masterLanguage="EN" adtcore:responsible="${username.toUpperCase()}">
|
|
3402
|
+
<adtcore:packageRef adtcore:name="${packageName}"/>
|
|
3403
|
+
<srvb:services srvb:name="${serviceDefinition}">
|
|
3404
|
+
<srvb:content srvb:version="${CONTENT_VERSION}">
|
|
3405
|
+
<srvb:serviceDefinition adtcore:name="${serviceDefinition}"/>
|
|
3406
|
+
</srvb:content>
|
|
3407
|
+
</srvb:services>
|
|
3408
|
+
<srvb:binding srvb:category="${BINDING_CATEGORY}" srvb:type="${bindingType}" srvb:version="${bindingVersion}">
|
|
3409
|
+
<srvb:implementation adtcore:name=""/>
|
|
3410
|
+
</srvb:binding>
|
|
3411
|
+
</srvb:serviceBinding>`;
|
|
3412
|
+
const params = {};
|
|
3413
|
+
if (options.transport) {
|
|
3414
|
+
params["corrNr"] = options.transport;
|
|
3415
|
+
}
|
|
3416
|
+
const [response, requestErr] = await client.request({
|
|
3417
|
+
method: "POST",
|
|
3418
|
+
path: "/sap/bc/adt/businessservices/bindings",
|
|
3419
|
+
params,
|
|
3420
|
+
headers: { "Content-Type": "application/*" },
|
|
3421
|
+
body
|
|
3422
|
+
});
|
|
3423
|
+
const [, checkErr] = await checkResponse(
|
|
3424
|
+
response,
|
|
3425
|
+
requestErr,
|
|
3426
|
+
`Failed to create service binding ${options.bindingName}`
|
|
3427
|
+
);
|
|
3428
|
+
if (checkErr) return err(checkErr);
|
|
3429
|
+
return ok(void 0);
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
// src/core/adt/businessservices/activate.ts
|
|
3433
|
+
var SERVICE_BINDING_TYPE_CODE2 = "SRVB/SVB";
|
|
3434
|
+
async function activateServiceBinding(client, bindingName) {
|
|
3435
|
+
return activateByReferences(client, [{
|
|
3436
|
+
uri: `/sap/bc/adt/businessservices/bindings/${bindingName.toLowerCase()}`,
|
|
3437
|
+
type: SERVICE_BINDING_TYPE_CODE2,
|
|
3438
|
+
name: bindingName.toUpperCase(),
|
|
3439
|
+
extension: ""
|
|
3440
|
+
}]);
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
// src/core/adt/businessservices/helpers.ts
|
|
3444
|
+
var BINDINGS_BASE_PATH = "/sap/bc/adt/businessservices/bindings";
|
|
3445
|
+
var LOCK_ACCEPT_HEADER = "application/*,application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.lock.result";
|
|
3446
|
+
var PUBLISH_JOBS_PATH = "/sap/bc/adt/businessservices/odatav4/publishjobs";
|
|
3447
|
+
var UNPUBLISH_JOBS_PATH = "/sap/bc/adt/businessservices/odatav4/unpublishjobs";
|
|
3448
|
+
var SEVERITY_OK2 = "OK";
|
|
3449
|
+
function bindingPath(bindingName) {
|
|
3450
|
+
return `${BINDINGS_BASE_PATH}/${bindingName.toLowerCase()}`;
|
|
3451
|
+
}
|
|
3452
|
+
async function lockServiceBinding(client, bindingName) {
|
|
3453
|
+
const [response, requestErr] = await client.request({
|
|
3454
|
+
method: "POST",
|
|
3455
|
+
path: bindingPath(bindingName),
|
|
3456
|
+
params: {
|
|
3457
|
+
"_action": "LOCK",
|
|
3458
|
+
"accessMode": "MODIFY"
|
|
3459
|
+
},
|
|
3460
|
+
headers: { "Accept": LOCK_ACCEPT_HEADER }
|
|
3461
|
+
});
|
|
3462
|
+
const [text, checkErr] = await checkResponse(
|
|
3463
|
+
response,
|
|
3464
|
+
requestErr,
|
|
3465
|
+
`Failed to lock service binding ${bindingName}`
|
|
3466
|
+
);
|
|
3467
|
+
if (checkErr) return err(checkErr);
|
|
3468
|
+
const [lockHandle, extractErr] = extractLockHandle(text);
|
|
3469
|
+
if (extractErr) return err(new Error(`Failed to extract lock handle: ${extractErr.message}`));
|
|
3470
|
+
return ok(lockHandle);
|
|
3471
|
+
}
|
|
3472
|
+
async function unlockServiceBinding(client, bindingName, lockHandle) {
|
|
3473
|
+
const [response, requestErr] = await client.request({
|
|
3474
|
+
method: "POST",
|
|
3475
|
+
path: bindingPath(bindingName),
|
|
3476
|
+
params: {
|
|
3477
|
+
"_action": "UNLOCK",
|
|
3478
|
+
"lockHandle": lockHandle
|
|
3479
|
+
}
|
|
3480
|
+
});
|
|
3481
|
+
const [, checkErr] = await checkResponse(
|
|
3482
|
+
response,
|
|
3483
|
+
requestErr,
|
|
3484
|
+
`Failed to unlock service binding ${bindingName}`
|
|
3485
|
+
);
|
|
3486
|
+
if (checkErr) return err(checkErr);
|
|
3487
|
+
return ok(void 0);
|
|
3488
|
+
}
|
|
3489
|
+
async function submitServiceBindingJob(client, bindingName, action) {
|
|
3490
|
+
const path = action === "publish" ? PUBLISH_JOBS_PATH : UNPUBLISH_JOBS_PATH;
|
|
3491
|
+
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
3492
|
+
<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
|
|
3493
|
+
<adtcore:objectReference adtcore:type="SCGR" adtcore:name="${bindingName.toUpperCase()}"/>
|
|
3494
|
+
</adtcore:objectReferences>`;
|
|
3495
|
+
const [response, requestErr] = await client.request({
|
|
3496
|
+
method: "POST",
|
|
3497
|
+
path,
|
|
3498
|
+
headers: { "Content-Type": "application/xml" },
|
|
3499
|
+
body
|
|
3500
|
+
});
|
|
3501
|
+
const [text, checkErr] = await checkResponse(
|
|
3502
|
+
response,
|
|
3503
|
+
requestErr,
|
|
3504
|
+
`Failed to ${action} service binding ${bindingName}`
|
|
3505
|
+
);
|
|
3506
|
+
if (checkErr) return err(checkErr);
|
|
3507
|
+
const severity = extractTagText(text, "SEVERITY");
|
|
3508
|
+
if (severity && severity !== SEVERITY_OK2) {
|
|
3509
|
+
const shortText = extractTagText(text, "SHORT_TEXT") ?? "";
|
|
3510
|
+
return err(new Error(`Service binding ${action} failed (${severity}): ${shortText}`));
|
|
3511
|
+
}
|
|
3512
|
+
return ok(extractTagText(text, "SHORT_TEXT") ?? "");
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
// src/core/adt/businessservices/publish.ts
|
|
3516
|
+
async function publishServiceBinding(client, bindingName) {
|
|
3517
|
+
return runBindingJob(client, bindingName, "publish");
|
|
3518
|
+
}
|
|
3519
|
+
async function runBindingJob(client, bindingName, action) {
|
|
3520
|
+
const [lockHandle, lockErr] = await lockServiceBinding(client, bindingName);
|
|
3521
|
+
if (lockErr) return err(lockErr);
|
|
3522
|
+
debug(`Service binding lock acquired for ${action}: handle=${lockHandle}`);
|
|
3523
|
+
const [message, jobErr] = await submitServiceBindingJob(client, bindingName, action);
|
|
3524
|
+
const [, unlockErr] = await unlockServiceBinding(client, bindingName, lockHandle);
|
|
3525
|
+
if (jobErr) return err(jobErr);
|
|
3526
|
+
if (unlockErr) return err(unlockErr);
|
|
3527
|
+
return ok(message);
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
// src/core/adt/businessservices/delete.ts
|
|
3531
|
+
async function deleteServiceBinding(client, bindingName, transport) {
|
|
3532
|
+
const [lockHandle, lockErr] = await lockServiceBinding(client, bindingName);
|
|
3533
|
+
if (lockErr) return err(lockErr);
|
|
3534
|
+
const [, unpublishErr] = await submitServiceBindingJob(client, bindingName, "unpublish");
|
|
3535
|
+
if (unpublishErr) debug(`Unpublish before delete skipped: ${unpublishErr.message}`);
|
|
3536
|
+
const params = { lockHandle };
|
|
3537
|
+
if (transport) params["corrNr"] = transport;
|
|
3538
|
+
const [response, requestErr] = await client.request({
|
|
3539
|
+
method: "DELETE",
|
|
3540
|
+
path: bindingPath(bindingName),
|
|
3541
|
+
params,
|
|
3542
|
+
headers: { "Accept": "text/plain" }
|
|
3543
|
+
});
|
|
3544
|
+
const [, checkErr] = await checkResponse(
|
|
3545
|
+
response,
|
|
3546
|
+
requestErr,
|
|
3547
|
+
`Failed to delete service binding ${bindingName}`
|
|
3548
|
+
);
|
|
3549
|
+
if (checkErr) {
|
|
3550
|
+
await unlockServiceBinding(client, bindingName, lockHandle);
|
|
3551
|
+
return err(checkErr);
|
|
3552
|
+
}
|
|
3553
|
+
return ok(void 0);
|
|
3554
|
+
}
|
|
3555
|
+
|
|
2994
3556
|
// src/client/methods/craud/read.ts
|
|
2995
3557
|
async function read(state, requestor, objects) {
|
|
2996
3558
|
if (!state.session) return err(new Error("Not logged in"));
|
|
@@ -3147,6 +3709,12 @@ async function countRows2(state, requestor, objectName, objectType, parameters =
|
|
|
3147
3709
|
return countRows(requestor, objectName, objectType, parameters);
|
|
3148
3710
|
}
|
|
3149
3711
|
|
|
3712
|
+
// src/client/methods/preview/freestyleQuery.ts
|
|
3713
|
+
async function freestyleQuery2(state, requestor, sqlQuery, limit, timeout) {
|
|
3714
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3715
|
+
return freestyleQuery(requestor, sqlQuery, limit, timeout);
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3150
3718
|
// src/client/methods/search/search.ts
|
|
3151
3719
|
async function search(state, requestor, query, options) {
|
|
3152
3720
|
if (!state.session) return err(new Error("Not logged in"));
|
|
@@ -3201,6 +3769,41 @@ function getObjectConfig() {
|
|
|
3201
3769
|
return Object.values(OBJECT_CONFIG_MAP);
|
|
3202
3770
|
}
|
|
3203
3771
|
|
|
3772
|
+
// src/client/methods/businessservices/createServiceBinding.ts
|
|
3773
|
+
async function createServiceBinding(state, requestor, options) {
|
|
3774
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3775
|
+
const [, validateErr] = await validateServiceBinding(requestor, options);
|
|
3776
|
+
if (validateErr) return err(validateErr);
|
|
3777
|
+
const [, createErr] = await createServiceBindingObject(requestor, options, state.session.username);
|
|
3778
|
+
if (createErr) return err(createErr);
|
|
3779
|
+
const [activation, activateErr] = await activateServiceBinding(requestor, options.bindingName);
|
|
3780
|
+
if (activateErr) return err(activateErr);
|
|
3781
|
+
if (activation.some((result2) => result2.status === "error")) {
|
|
3782
|
+
return err(new Error(`Service binding ${options.bindingName} failed activation`));
|
|
3783
|
+
}
|
|
3784
|
+
const result = {
|
|
3785
|
+
name: options.bindingName.toUpperCase(),
|
|
3786
|
+
serviceDefinition: options.serviceDefinition.toUpperCase(),
|
|
3787
|
+
created: true,
|
|
3788
|
+
activation,
|
|
3789
|
+
published: false
|
|
3790
|
+
};
|
|
3791
|
+
if (options.publish === false) {
|
|
3792
|
+
return ok(result);
|
|
3793
|
+
}
|
|
3794
|
+
const [publishMessage, publishErr] = await publishServiceBinding(requestor, options.bindingName);
|
|
3795
|
+
if (publishErr) return err(publishErr);
|
|
3796
|
+
result.published = true;
|
|
3797
|
+
if (publishMessage) result.publishMessage = publishMessage;
|
|
3798
|
+
return ok(result);
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3801
|
+
// src/client/methods/businessservices/deleteServiceBinding.ts
|
|
3802
|
+
async function deleteServiceBinding2(state, requestor, bindingName, transport) {
|
|
3803
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3804
|
+
return deleteServiceBinding(requestor, bindingName, transport);
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3204
3807
|
// src/client/methods/internal/cookies.ts
|
|
3205
3808
|
function storeCookies(cookies, response) {
|
|
3206
3809
|
const setCookieHeader = response.headers.get("set-cookie");
|
|
@@ -3330,7 +3933,7 @@ function buildUrl2(baseUrl, path, params) {
|
|
|
3330
3933
|
// src/client/methods/internal/request.ts
|
|
3331
3934
|
async function executeRequest(deps, options, selfRequest) {
|
|
3332
3935
|
const { state, ssoCerts, getCookieHeader, storeCookies: storeCookies2 } = deps;
|
|
3333
|
-
const { method, path, params, headers: customHeaders, body } = options;
|
|
3936
|
+
const { method, path, params, headers: customHeaders, body, timeout: requestTimeout } = options;
|
|
3334
3937
|
const { config } = state;
|
|
3335
3938
|
debug(`Request ${method} ${path} - CSRF token in state: ${state.csrfToken?.substring(0, 20) || "null"}...`);
|
|
3336
3939
|
const headers = buildRequestHeaders(
|
|
@@ -3357,7 +3960,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3357
3960
|
cert: ssoCerts?.cert,
|
|
3358
3961
|
key: ssoCerts?.key,
|
|
3359
3962
|
rejectUnauthorized: !config.insecure,
|
|
3360
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3963
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3361
3964
|
});
|
|
3362
3965
|
storeCookies2(response);
|
|
3363
3966
|
if (response.status === 403) {
|
|
@@ -3380,7 +3983,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3380
3983
|
cert: ssoCerts?.cert,
|
|
3381
3984
|
key: ssoCerts?.key,
|
|
3382
3985
|
rejectUnauthorized: !config.insecure,
|
|
3383
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3986
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3384
3987
|
});
|
|
3385
3988
|
storeCookies2(retryResponse);
|
|
3386
3989
|
return ok(retryResponse);
|
|
@@ -3551,6 +4154,9 @@ var ADTClientImpl = class {
|
|
|
3551
4154
|
async countRows(objectName, objectType, parameters = []) {
|
|
3552
4155
|
return countRows2(this.state, this.requestor, objectName, objectType, parameters);
|
|
3553
4156
|
}
|
|
4157
|
+
async freestyleQuery(sqlQuery, limit, timeout) {
|
|
4158
|
+
return freestyleQuery2(this.state, this.requestor, sqlQuery, limit, timeout);
|
|
4159
|
+
}
|
|
3554
4160
|
// --- Search ---
|
|
3555
4161
|
async search(query, options) {
|
|
3556
4162
|
return search(this.state, this.requestor, query, options);
|
|
@@ -3575,6 +4181,13 @@ var ADTClientImpl = class {
|
|
|
3575
4181
|
async gitDiff(objects) {
|
|
3576
4182
|
return gitDiff2(this.state, this.requestor, objects);
|
|
3577
4183
|
}
|
|
4184
|
+
// --- Business Services ---
|
|
4185
|
+
async createServiceBinding(options) {
|
|
4186
|
+
return createServiceBinding(this.state, this.requestor, options);
|
|
4187
|
+
}
|
|
4188
|
+
async deleteServiceBinding(bindingName, transport) {
|
|
4189
|
+
return deleteServiceBinding2(this.state, this.requestor, bindingName, transport);
|
|
4190
|
+
}
|
|
3578
4191
|
// --- Configuration ---
|
|
3579
4192
|
getObjectConfig() {
|
|
3580
4193
|
return getObjectConfig();
|
|
@@ -3592,6 +4205,7 @@ function createClient(config) {
|
|
|
3592
4205
|
}
|
|
3593
4206
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3594
4207
|
0 && (module.exports = {
|
|
4208
|
+
BehaviorImplementationType,
|
|
3595
4209
|
ExternalReferencesError,
|
|
3596
4210
|
activateLogging,
|
|
3597
4211
|
buildSQLQuery,
|