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.mjs
CHANGED
|
@@ -502,6 +502,12 @@ var SsoAuth = class {
|
|
|
502
502
|
}
|
|
503
503
|
};
|
|
504
504
|
|
|
505
|
+
// src/core/auth/saml/browser.ts
|
|
506
|
+
import { spawn } from "child_process";
|
|
507
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
508
|
+
import { tmpdir } from "os";
|
|
509
|
+
import { join as join2 } from "path";
|
|
510
|
+
|
|
505
511
|
// src/core/auth/saml/types.ts
|
|
506
512
|
var DEFAULT_FORM_SELECTORS = {
|
|
507
513
|
username: "#j_username",
|
|
@@ -516,9 +522,16 @@ var DEFAULT_PROVIDER_CONFIG = {
|
|
|
516
522
|
// src/core/auth/saml/browser.ts
|
|
517
523
|
var TIMEOUTS = {
|
|
518
524
|
PAGE_LOAD: 6e4,
|
|
519
|
-
FORM_SELECTOR:
|
|
525
|
+
FORM_SELECTOR: 15e3,
|
|
526
|
+
NETWORK_IDLE: 3e4,
|
|
527
|
+
/** Quiet period with no in-flight requests that counts as "idle". */
|
|
528
|
+
IDLE_QUIET: 600
|
|
520
529
|
};
|
|
530
|
+
var isBun = typeof globalThis.Bun !== "undefined";
|
|
521
531
|
async function performBrowserLogin(options) {
|
|
532
|
+
return isBun ? performBrowserLoginViaCdp(options) : performBrowserLoginViaPlaywright(options);
|
|
533
|
+
}
|
|
534
|
+
async function performBrowserLoginViaPlaywright(options) {
|
|
522
535
|
const { baseUrl, credentials, headless = true } = options;
|
|
523
536
|
const config = options.providerConfig ?? DEFAULT_PROVIDER_CONFIG;
|
|
524
537
|
let playwright;
|
|
@@ -576,6 +589,222 @@ async function performBrowserLogin(options) {
|
|
|
576
589
|
await browser.close();
|
|
577
590
|
}
|
|
578
591
|
}
|
|
592
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
593
|
+
async function resolveChromiumPath() {
|
|
594
|
+
const override = process.env["CATALYST_CHROMIUM_PATH"];
|
|
595
|
+
if (override) return [override, null];
|
|
596
|
+
try {
|
|
597
|
+
const playwright = await import("playwright");
|
|
598
|
+
const path = playwright.chromium.executablePath();
|
|
599
|
+
if (!path) {
|
|
600
|
+
return [null, new Error("Could not resolve the Chromium executable path from Playwright.")];
|
|
601
|
+
}
|
|
602
|
+
return [path, null];
|
|
603
|
+
} catch {
|
|
604
|
+
return [
|
|
605
|
+
null,
|
|
606
|
+
new Error(
|
|
607
|
+
"Playwright is required for SAML authentication but is not installed. Install it with: npm install playwright"
|
|
608
|
+
)
|
|
609
|
+
];
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
async function connectCdp(wsUrl) {
|
|
613
|
+
const WebSocketCtor = globalThis.WebSocket;
|
|
614
|
+
if (!WebSocketCtor) {
|
|
615
|
+
throw new Error("Native WebSocket is not available in this runtime.");
|
|
616
|
+
}
|
|
617
|
+
const ws = new WebSocketCtor(wsUrl);
|
|
618
|
+
let nextId = 0;
|
|
619
|
+
const pending = /* @__PURE__ */ new Map();
|
|
620
|
+
const eventHandlers = [];
|
|
621
|
+
ws.onmessage = (event) => {
|
|
622
|
+
const msg = JSON.parse(String(event.data));
|
|
623
|
+
if (typeof msg.id === "number" && pending.has(msg.id)) {
|
|
624
|
+
const { resolve, reject } = pending.get(msg.id);
|
|
625
|
+
pending.delete(msg.id);
|
|
626
|
+
if (msg.error) reject(new Error(msg.error.message));
|
|
627
|
+
else resolve(msg.result ?? {});
|
|
628
|
+
} else if (msg.method) {
|
|
629
|
+
for (const handler of eventHandlers) {
|
|
630
|
+
handler({
|
|
631
|
+
method: msg.method,
|
|
632
|
+
params: msg.params ?? {},
|
|
633
|
+
...msg.sessionId !== void 0 ? { sessionId: msg.sessionId } : {}
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
await new Promise((resolve, reject) => {
|
|
639
|
+
ws.onopen = () => resolve();
|
|
640
|
+
ws.onerror = () => reject(new Error("Failed to connect to the browser CDP endpoint."));
|
|
641
|
+
});
|
|
642
|
+
return {
|
|
643
|
+
send(method, params = {}, sessionId) {
|
|
644
|
+
return new Promise((resolve, reject) => {
|
|
645
|
+
const id = ++nextId;
|
|
646
|
+
pending.set(id, { resolve, reject });
|
|
647
|
+
ws.send(JSON.stringify({ id, method, params, ...sessionId ? { sessionId } : {} }));
|
|
648
|
+
});
|
|
649
|
+
},
|
|
650
|
+
on(handler) {
|
|
651
|
+
eventHandlers.push(handler);
|
|
652
|
+
},
|
|
653
|
+
close() {
|
|
654
|
+
ws.close();
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
async function performBrowserLoginViaCdp(options) {
|
|
659
|
+
const { baseUrl, credentials, headless = true } = options;
|
|
660
|
+
const config = options.providerConfig ?? DEFAULT_PROVIDER_CONFIG;
|
|
661
|
+
const [exePath, pathError] = await resolveChromiumPath();
|
|
662
|
+
if (pathError) return err(pathError);
|
|
663
|
+
const userDataDir = mkdtempSync(join2(tmpdir(), "catalyst-saml-"));
|
|
664
|
+
const args = [
|
|
665
|
+
...headless ? ["--headless=new"] : [],
|
|
666
|
+
"--remote-debugging-port=0",
|
|
667
|
+
"--no-first-run",
|
|
668
|
+
"--no-default-browser-check",
|
|
669
|
+
`--user-data-dir=${userDataDir}`,
|
|
670
|
+
...config.ignoreHttpsErrors ? ["--ignore-certificate-errors"] : []
|
|
671
|
+
];
|
|
672
|
+
const proc = spawn(exePath, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
673
|
+
let client = null;
|
|
674
|
+
const cleanup = () => {
|
|
675
|
+
try {
|
|
676
|
+
client?.close();
|
|
677
|
+
} catch {
|
|
678
|
+
}
|
|
679
|
+
try {
|
|
680
|
+
proc.kill();
|
|
681
|
+
} catch {
|
|
682
|
+
}
|
|
683
|
+
try {
|
|
684
|
+
rmSync(userDataDir, { recursive: true, force: true });
|
|
685
|
+
} catch {
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
try {
|
|
689
|
+
const browserWsUrl = await new Promise((resolve, reject) => {
|
|
690
|
+
let buffer = "";
|
|
691
|
+
const timer = setTimeout(
|
|
692
|
+
() => reject(new Error("Failed to launch browser: timed out waiting for the CDP endpoint.")),
|
|
693
|
+
TIMEOUTS.PAGE_LOAD
|
|
694
|
+
);
|
|
695
|
+
proc.stderr?.on("data", (chunk) => {
|
|
696
|
+
buffer += String(chunk);
|
|
697
|
+
const match = buffer.match(/DevTools listening on (ws:\/\/\S+)/);
|
|
698
|
+
if (match) {
|
|
699
|
+
clearTimeout(timer);
|
|
700
|
+
resolve(match[1]);
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
proc.on("error", (e) => {
|
|
704
|
+
clearTimeout(timer);
|
|
705
|
+
reject(new Error(`Failed to launch browser: ${e instanceof Error ? e.message : String(e)}`));
|
|
706
|
+
});
|
|
707
|
+
proc.on("exit", (code) => {
|
|
708
|
+
clearTimeout(timer);
|
|
709
|
+
reject(new Error(`Failed to launch browser: process exited early (code ${code}).`));
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
client = await connectCdp(browserWsUrl);
|
|
713
|
+
const { targetId } = await client.send("Target.createTarget", { url: "about:blank" });
|
|
714
|
+
const { sessionId } = await client.send("Target.attachToTarget", {
|
|
715
|
+
targetId,
|
|
716
|
+
flatten: true
|
|
717
|
+
});
|
|
718
|
+
let inflight = 0;
|
|
719
|
+
let lastNetworkChange = Date.now();
|
|
720
|
+
client.on((msg) => {
|
|
721
|
+
if (msg.sessionId !== sessionId) return;
|
|
722
|
+
if (msg.method === "Network.requestWillBeSent") {
|
|
723
|
+
inflight += 1;
|
|
724
|
+
lastNetworkChange = Date.now();
|
|
725
|
+
} else if (msg.method === "Network.loadingFinished" || msg.method === "Network.loadingFailed") {
|
|
726
|
+
inflight = Math.max(0, inflight - 1);
|
|
727
|
+
lastNetworkChange = Date.now();
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
await client.send("Page.enable", {}, sessionId);
|
|
731
|
+
await client.send("Network.enable", {}, sessionId);
|
|
732
|
+
await client.send("Runtime.enable", {}, sessionId);
|
|
733
|
+
const loginUrl = `${baseUrl}/sap/bc/adt/compatibility/graph`;
|
|
734
|
+
const navResult = await client.send("Page.navigate", { url: loginUrl }, sessionId);
|
|
735
|
+
if (navResult.errorText) {
|
|
736
|
+
return err(new Error("Failed to load login page. Please check if the server is online."));
|
|
737
|
+
}
|
|
738
|
+
const usernameSel = config.formSelectors.username;
|
|
739
|
+
const formFound = await waitForSelector(client, sessionId, usernameSel, TIMEOUTS.FORM_SELECTOR);
|
|
740
|
+
if (!formFound) {
|
|
741
|
+
return err(new Error("Login form not found. The page may have changed or loaded incorrectly."));
|
|
742
|
+
}
|
|
743
|
+
const fillExpr = `(() => {
|
|
744
|
+
const u = document.querySelector(${JSON.stringify(config.formSelectors.username)});
|
|
745
|
+
const p = document.querySelector(${JSON.stringify(config.formSelectors.password)});
|
|
746
|
+
const s = document.querySelector(${JSON.stringify(config.formSelectors.submit)});
|
|
747
|
+
if (!u || !p || !s) return false;
|
|
748
|
+
const set = (el, val) => {
|
|
749
|
+
el.value = val;
|
|
750
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
751
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
752
|
+
};
|
|
753
|
+
set(u, ${JSON.stringify(credentials.username)});
|
|
754
|
+
set(p, ${JSON.stringify(credentials.password)});
|
|
755
|
+
s.click();
|
|
756
|
+
return true;
|
|
757
|
+
})()`;
|
|
758
|
+
const fillResult = await client.send(
|
|
759
|
+
"Runtime.evaluate",
|
|
760
|
+
{ expression: fillExpr, returnByValue: true },
|
|
761
|
+
sessionId
|
|
762
|
+
);
|
|
763
|
+
if (fillResult.result?.value !== true) {
|
|
764
|
+
return err(new Error("Login form not found. The page may have changed or loaded incorrectly."));
|
|
765
|
+
}
|
|
766
|
+
const idleStart = Date.now();
|
|
767
|
+
while (Date.now() - idleStart < TIMEOUTS.NETWORK_IDLE) {
|
|
768
|
+
if (inflight === 0 && Date.now() - lastNetworkChange > TIMEOUTS.IDLE_QUIET) break;
|
|
769
|
+
await sleep(100);
|
|
770
|
+
}
|
|
771
|
+
const { cookies } = await client.send("Network.getAllCookies", {}, sessionId);
|
|
772
|
+
return ok(cookies.map(toPlaywrightCookie));
|
|
773
|
+
} catch (e) {
|
|
774
|
+
return err(
|
|
775
|
+
new Error(`SAML browser login failed: ${e instanceof Error ? e.message : String(e)}`)
|
|
776
|
+
);
|
|
777
|
+
} finally {
|
|
778
|
+
cleanup();
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
async function waitForSelector(client, sessionId, selector, timeoutMs) {
|
|
782
|
+
const start = Date.now();
|
|
783
|
+
const expression = `!!document.querySelector(${JSON.stringify(selector)})`;
|
|
784
|
+
while (Date.now() - start < timeoutMs) {
|
|
785
|
+
const res = await client.send(
|
|
786
|
+
"Runtime.evaluate",
|
|
787
|
+
{ expression, returnByValue: true },
|
|
788
|
+
sessionId
|
|
789
|
+
);
|
|
790
|
+
if (res.result?.value === true) return true;
|
|
791
|
+
await sleep(200);
|
|
792
|
+
}
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
function toPlaywrightCookie(c) {
|
|
796
|
+
const sameSite = c.sameSite === "Strict" || c.sameSite === "Lax" || c.sameSite === "None" ? c.sameSite : "Lax";
|
|
797
|
+
return {
|
|
798
|
+
name: c.name,
|
|
799
|
+
value: c.value,
|
|
800
|
+
domain: c.domain,
|
|
801
|
+
path: c.path,
|
|
802
|
+
expires: typeof c.expires === "number" ? c.expires : -1,
|
|
803
|
+
httpOnly: Boolean(c.httpOnly),
|
|
804
|
+
secure: Boolean(c.secure),
|
|
805
|
+
sameSite
|
|
806
|
+
};
|
|
807
|
+
}
|
|
579
808
|
|
|
580
809
|
// src/core/auth/saml/cookies.ts
|
|
581
810
|
function toAuthCookies(playwrightCookies) {
|
|
@@ -780,6 +1009,16 @@ function extractError(xml) {
|
|
|
780
1009
|
const message = messageElement?.textContent;
|
|
781
1010
|
return message || "No message found";
|
|
782
1011
|
}
|
|
1012
|
+
function extractTagText(xml, tagName) {
|
|
1013
|
+
if (!xml) return null;
|
|
1014
|
+
const [doc, parseErr] = safeParseXml(xml);
|
|
1015
|
+
if (parseErr) return null;
|
|
1016
|
+
const elements = doc.getElementsByTagName(tagName);
|
|
1017
|
+
if (elements.length === 0) return null;
|
|
1018
|
+
const text = elements[0]?.textContent;
|
|
1019
|
+
if (!text || text.trim().length === 0) return null;
|
|
1020
|
+
return text.trim();
|
|
1021
|
+
}
|
|
783
1022
|
function escapeXml(str) {
|
|
784
1023
|
if (!str) {
|
|
785
1024
|
return "";
|
|
@@ -1200,6 +1439,24 @@ var OBJECT_CONFIG_MAP = {
|
|
|
1200
1439
|
type: "PROG/I",
|
|
1201
1440
|
label: "ABAP Include" /* INCLUDE */,
|
|
1202
1441
|
extension: "asinc"
|
|
1442
|
+
},
|
|
1443
|
+
"srvd": {
|
|
1444
|
+
endpoint: "ddic/srvd/sources",
|
|
1445
|
+
nameSpace: 'xmlns:srvd="http://www.sap.com/adt/ddic/srvdsources"',
|
|
1446
|
+
rootName: "srvd:srvdSource",
|
|
1447
|
+
type: "SRVD/SRV",
|
|
1448
|
+
label: "Service Definition" /* SERVICE_DEFINITION */,
|
|
1449
|
+
extension: "srvd",
|
|
1450
|
+
rootAttributes: { "srvd:srvdSourceType": "S" }
|
|
1451
|
+
},
|
|
1452
|
+
"asbdef": {
|
|
1453
|
+
endpoint: "bo/behaviordefinitions",
|
|
1454
|
+
nameSpace: 'xmlns:blue="http://www.sap.com/wbobj/blue"',
|
|
1455
|
+
rootName: "blue:blueSource",
|
|
1456
|
+
type: "BDEF/BDO",
|
|
1457
|
+
label: "Behavior Definition" /* BEHAVIOR_DEFINITION */,
|
|
1458
|
+
extension: "asbdef",
|
|
1459
|
+
requiresImplementationType: true
|
|
1203
1460
|
}
|
|
1204
1461
|
};
|
|
1205
1462
|
function getConfigByExtension(extension) {
|
|
@@ -1512,11 +1769,44 @@ async function multiDeleteObjects(client, objects, transport) {
|
|
|
1512
1769
|
return ok(results);
|
|
1513
1770
|
}
|
|
1514
1771
|
|
|
1772
|
+
// src/types/requests.ts
|
|
1773
|
+
import { z as z2 } from "zod";
|
|
1774
|
+
var BehaviorImplementationType = /* @__PURE__ */ ((BehaviorImplementationType2) => {
|
|
1775
|
+
BehaviorImplementationType2["Managed"] = "Managed";
|
|
1776
|
+
return BehaviorImplementationType2;
|
|
1777
|
+
})(BehaviorImplementationType || {});
|
|
1778
|
+
var objectRefSchema = z2.object({
|
|
1779
|
+
name: z2.string().min(1),
|
|
1780
|
+
extension: z2.string().min(1)
|
|
1781
|
+
});
|
|
1782
|
+
var objectContentSchema = objectRefSchema.extend({
|
|
1783
|
+
content: z2.string(),
|
|
1784
|
+
description: z2.string().optional(),
|
|
1785
|
+
implementationType: z2.nativeEnum(BehaviorImplementationType).optional()
|
|
1786
|
+
});
|
|
1787
|
+
var treeQuerySchema = z2.object({
|
|
1788
|
+
package: z2.string().min(1).optional(),
|
|
1789
|
+
path: z2.string().optional(),
|
|
1790
|
+
owner: z2.string().min(1).optional()
|
|
1791
|
+
});
|
|
1792
|
+
var previewQuerySchema = z2.object({
|
|
1793
|
+
objectName: z2.string().min(1),
|
|
1794
|
+
objectType: z2.enum(["table", "view"]),
|
|
1795
|
+
sqlQuery: z2.string().min(1),
|
|
1796
|
+
limit: z2.number().positive().max(5e4).optional()
|
|
1797
|
+
});
|
|
1798
|
+
|
|
1515
1799
|
// src/core/adt/craud/create.ts
|
|
1516
1800
|
async function createObject(client, object, packageName, transport, username) {
|
|
1517
1801
|
const [config, configErr] = requireConfig(object.extension);
|
|
1518
1802
|
if (configErr) return err(configErr);
|
|
1519
1803
|
const description = object.description ?? "";
|
|
1804
|
+
const extraAttrs = config.rootAttributes ? Object.entries(config.rootAttributes).map(([key, value]) => `
|
|
1805
|
+
${key}="${escapeXml(value)}"`).join("") : "";
|
|
1806
|
+
const implementationType = object.implementationType ?? "Managed" /* Managed */;
|
|
1807
|
+
const adtTemplate = config.requiresImplementationType ? ` <adtcore:adtTemplate>
|
|
1808
|
+
<adtcore:adtProperty adtcore:key="implementation_type">${implementationType}</adtcore:adtProperty>
|
|
1809
|
+
</adtcore:adtTemplate>` : "";
|
|
1520
1810
|
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1521
1811
|
<${config.rootName} ${config.nameSpace}
|
|
1522
1812
|
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
@@ -1524,8 +1814,8 @@ async function createObject(client, object, packageName, transport, username) {
|
|
|
1524
1814
|
adtcore:language="EN"
|
|
1525
1815
|
adtcore:name="${object.name.toUpperCase()}"
|
|
1526
1816
|
adtcore:type="${config.type}"
|
|
1527
|
-
adtcore:responsible="${username.toUpperCase()}">
|
|
1528
|
-
|
|
1817
|
+
adtcore:responsible="${username.toUpperCase()}"${extraAttrs}>
|
|
1818
|
+
${adtTemplate}
|
|
1529
1819
|
<adtcore:packageRef adtcore:name="${packageName}"/>
|
|
1530
1820
|
|
|
1531
1821
|
</${config.rootName}>`;
|
|
@@ -1586,14 +1876,26 @@ async function activateObjects(client, objects) {
|
|
|
1586
1876
|
if (objects.length === 0) {
|
|
1587
1877
|
return ok([]);
|
|
1588
1878
|
}
|
|
1879
|
+
const references = [];
|
|
1589
1880
|
for (const obj of objects) {
|
|
1590
1881
|
const config = getConfigByExtension(obj.extension);
|
|
1591
1882
|
if (!config) return err(new Error(`Unsupported extension: ${obj.extension}`));
|
|
1883
|
+
references.push({
|
|
1884
|
+
uri: `/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}`,
|
|
1885
|
+
type: config.type,
|
|
1886
|
+
name: obj.name,
|
|
1887
|
+
extension: obj.extension
|
|
1888
|
+
});
|
|
1592
1889
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1890
|
+
return activateByReferences(client, references);
|
|
1891
|
+
}
|
|
1892
|
+
async function activateByReferences(client, references) {
|
|
1893
|
+
if (references.length === 0) {
|
|
1894
|
+
return ok([]);
|
|
1895
|
+
}
|
|
1896
|
+
const objectRefs = references.map(
|
|
1897
|
+
(ref) => `<adtcore:objectReference adtcore:uri="${ref.uri}" adtcore:type="${ref.type}" adtcore:name="${ref.name}"/>`
|
|
1898
|
+
).join("\n ");
|
|
1597
1899
|
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1598
1900
|
<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
|
|
1599
1901
|
${objectRefs}
|
|
@@ -1657,7 +1959,7 @@ async function activateObjects(client, objects) {
|
|
|
1657
1959
|
if (!resultsRes.ok) {
|
|
1658
1960
|
return err(new Error(`Failed to fetch activation results: ${extractError(resultsText)}`));
|
|
1659
1961
|
}
|
|
1660
|
-
const [results, parseErr] = extractActivationErrors(
|
|
1962
|
+
const [results, parseErr] = extractActivationErrors(references, resultsText);
|
|
1661
1963
|
if (parseErr) return err(parseErr);
|
|
1662
1964
|
return ok(results);
|
|
1663
1965
|
}
|
|
@@ -2346,16 +2648,64 @@ function parseDataPreview(xml, maxRows, isTable) {
|
|
|
2346
2648
|
const namespace = "http://www.sap.com/adt/dataPreview";
|
|
2347
2649
|
const metadataElements = doc.getElementsByTagNameNS(namespace, "metadata");
|
|
2348
2650
|
const columns = [];
|
|
2651
|
+
const SAP_TYPE_MAP = {
|
|
2652
|
+
"8": "integer",
|
|
2653
|
+
// Int8
|
|
2654
|
+
"I": "integer",
|
|
2655
|
+
// Integer
|
|
2656
|
+
"P": "decimal",
|
|
2657
|
+
// Packed decimal
|
|
2658
|
+
"F": "float",
|
|
2659
|
+
// Floating point
|
|
2660
|
+
"D": "date",
|
|
2661
|
+
// Date (YYYYMMDD)
|
|
2662
|
+
"T": "time",
|
|
2663
|
+
// Time (HHMMSS)
|
|
2664
|
+
"S": "timestamp",
|
|
2665
|
+
// Timestamp
|
|
2666
|
+
"C": "string",
|
|
2667
|
+
// Character
|
|
2668
|
+
"N": "string",
|
|
2669
|
+
// Numeric character string
|
|
2670
|
+
"V": "string",
|
|
2671
|
+
// Variable-length character
|
|
2672
|
+
"X": "binary"
|
|
2673
|
+
// Raw binary/hex
|
|
2674
|
+
};
|
|
2349
2675
|
for (let i = 0; i < metadataElements.length; i++) {
|
|
2350
2676
|
const meta = metadataElements[i];
|
|
2351
2677
|
if (!meta) continue;
|
|
2352
2678
|
const nameAttr = isTable ? "name" : "camelCaseName";
|
|
2353
2679
|
const name = meta.getAttributeNS(namespace, nameAttr) || meta.getAttribute("name");
|
|
2354
|
-
const
|
|
2680
|
+
const colType = meta.getAttributeNS(namespace, "colType") || meta.getAttribute("colType");
|
|
2681
|
+
const rawType = meta.getAttributeNS(namespace, "type") || meta.getAttribute("type");
|
|
2682
|
+
const isKeyFigure = meta.getAttributeNS(namespace, "isKeyFigure") === "true";
|
|
2683
|
+
let dataType;
|
|
2684
|
+
if (colType && colType.trim() !== "") {
|
|
2685
|
+
dataType = colType;
|
|
2686
|
+
} else if (isKeyFigure) {
|
|
2687
|
+
dataType = "decimal";
|
|
2688
|
+
} else if (rawType && SAP_TYPE_MAP[rawType]) {
|
|
2689
|
+
dataType = SAP_TYPE_MAP[rawType];
|
|
2690
|
+
} else {
|
|
2691
|
+
dataType = "string";
|
|
2692
|
+
}
|
|
2693
|
+
const allAttrs = {};
|
|
2694
|
+
for (let j = 0; j < meta.attributes.length; j++) {
|
|
2695
|
+
const attr = meta.attributes[j];
|
|
2696
|
+
if (!attr) {
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
allAttrs[attr.name] = attr.value;
|
|
2700
|
+
}
|
|
2355
2701
|
if (!name || !dataType) continue;
|
|
2356
2702
|
columns.push({ name, dataType });
|
|
2357
2703
|
}
|
|
2358
2704
|
const dataSetElements = doc.getElementsByTagNameNS(namespace, "dataSet");
|
|
2705
|
+
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2706
|
+
const dataSet = dataSetElements[i];
|
|
2707
|
+
if (!dataSet) continue;
|
|
2708
|
+
}
|
|
2359
2709
|
if (columns.length === 0 && dataSetElements.length > 0) {
|
|
2360
2710
|
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2361
2711
|
const dataSet = dataSetElements[i];
|
|
@@ -2438,7 +2788,7 @@ async function previewData(client, query) {
|
|
|
2438
2788
|
|
|
2439
2789
|
// src/core/adt/data_extraction/freestyle.ts
|
|
2440
2790
|
var DEFAULT_ROW_LIMIT = 100;
|
|
2441
|
-
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
2791
|
+
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT, timeout) {
|
|
2442
2792
|
debug(`Freestyle query: ${sqlQuery}`);
|
|
2443
2793
|
const [response, requestErr] = await client.request({
|
|
2444
2794
|
method: "POST",
|
|
@@ -2448,16 +2798,21 @@ async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
|
2448
2798
|
},
|
|
2449
2799
|
headers: {
|
|
2450
2800
|
"Accept": "application/xml, application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
2451
|
-
"Content-Type": "text/plain"
|
|
2801
|
+
"Content-Type": "text/plain",
|
|
2802
|
+
// Override stateful base header: each preview request is independent; stateless
|
|
2803
|
+
// lets SAP route to any work process and recycle it after the request, preventing
|
|
2804
|
+
// GENERATE_SUBPOOL_DIR_FULL (36-pool limit per work process).
|
|
2805
|
+
"X-sap-adt-sessiontype": "stateless"
|
|
2452
2806
|
},
|
|
2453
|
-
body: sqlQuery
|
|
2807
|
+
body: sqlQuery,
|
|
2808
|
+
...timeout !== void 0 && { timeout }
|
|
2454
2809
|
});
|
|
2455
2810
|
if (requestErr) return err(requestErr);
|
|
2456
2811
|
if (!response.ok) {
|
|
2457
2812
|
const text2 = await response.text();
|
|
2458
2813
|
debug(`Freestyle query error response: ${text2.substring(0, 500)}`);
|
|
2459
2814
|
const errorMsg = extractError(text2);
|
|
2460
|
-
return err(new Error(`Freestyle query failed: ${errorMsg}
|
|
2815
|
+
return err(new Error(`Freestyle query failed: ${errorMsg}`, { cause: text2 }));
|
|
2461
2816
|
}
|
|
2462
2817
|
const text = await response.text();
|
|
2463
2818
|
const [dataFrame, parseErr] = parseDataPreview(text, limit, true);
|
|
@@ -2718,7 +3073,16 @@ function parseTransportTasks(doc) {
|
|
|
2718
3073
|
position: el.getAttribute("tm:position") || ""
|
|
2719
3074
|
});
|
|
2720
3075
|
}
|
|
2721
|
-
|
|
3076
|
+
const owner = taskEl.getAttribute("tm:owner");
|
|
3077
|
+
const description = taskEl.getAttribute("tm:desc");
|
|
3078
|
+
const status = taskEl.getAttribute("tm:status");
|
|
3079
|
+
tasks.push({
|
|
3080
|
+
taskId,
|
|
3081
|
+
...owner ? { owner } : {},
|
|
3082
|
+
...description ? { description } : {},
|
|
3083
|
+
...status ? { status } : {},
|
|
3084
|
+
objects
|
|
3085
|
+
});
|
|
2722
3086
|
}
|
|
2723
3087
|
return tasks;
|
|
2724
3088
|
}
|
|
@@ -2956,6 +3320,203 @@ async function gitDiff(client, object) {
|
|
|
2956
3320
|
});
|
|
2957
3321
|
}
|
|
2958
3322
|
|
|
3323
|
+
// src/core/adt/businessservices/validate.ts
|
|
3324
|
+
var SEVERITY_OK = "OK";
|
|
3325
|
+
async function validateServiceBinding(client, options) {
|
|
3326
|
+
const bindingType = options.bindingType ?? "ODATA";
|
|
3327
|
+
const bindingVersion = options.bindingVersion ?? "V4";
|
|
3328
|
+
const [response, requestErr] = await client.request({
|
|
3329
|
+
method: "POST",
|
|
3330
|
+
path: "/sap/bc/adt/businessservices/bindings/validation",
|
|
3331
|
+
params: {
|
|
3332
|
+
objname: options.bindingName.toUpperCase(),
|
|
3333
|
+
description: options.description ?? "",
|
|
3334
|
+
serviceBindingVersion: `${bindingType}\\${bindingVersion}`,
|
|
3335
|
+
serviceDefinition: options.serviceDefinition.toUpperCase(),
|
|
3336
|
+
package: options.packageName.toUpperCase()
|
|
3337
|
+
}
|
|
3338
|
+
});
|
|
3339
|
+
const [text, checkErr] = await checkResponse(
|
|
3340
|
+
response,
|
|
3341
|
+
requestErr,
|
|
3342
|
+
`Failed to validate service binding ${options.bindingName}`
|
|
3343
|
+
);
|
|
3344
|
+
if (checkErr) return err(checkErr);
|
|
3345
|
+
const severity = extractTagText(text, "SEVERITY");
|
|
3346
|
+
if (severity && severity !== SEVERITY_OK) {
|
|
3347
|
+
const shortText = extractTagText(text, "SHORT_TEXT") ?? "";
|
|
3348
|
+
return err(new Error(`Service binding validation failed (${severity}): ${shortText}`));
|
|
3349
|
+
}
|
|
3350
|
+
return ok(void 0);
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
// src/core/adt/businessservices/create.ts
|
|
3354
|
+
var SERVICE_BINDING_TYPE_CODE = "SRVB/SVB";
|
|
3355
|
+
var BINDING_CATEGORY = "1";
|
|
3356
|
+
var CONTENT_VERSION = "0001";
|
|
3357
|
+
async function createServiceBindingObject(client, options, username) {
|
|
3358
|
+
const bindingType = options.bindingType ?? "ODATA";
|
|
3359
|
+
const bindingVersion = options.bindingVersion ?? "V4";
|
|
3360
|
+
const description = options.description ?? "";
|
|
3361
|
+
const bindingName = options.bindingName.toUpperCase();
|
|
3362
|
+
const serviceDefinition = options.serviceDefinition.toUpperCase();
|
|
3363
|
+
const packageName = options.packageName.toUpperCase();
|
|
3364
|
+
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
3365
|
+
<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()}">
|
|
3366
|
+
<adtcore:packageRef adtcore:name="${packageName}"/>
|
|
3367
|
+
<srvb:services srvb:name="${serviceDefinition}">
|
|
3368
|
+
<srvb:content srvb:version="${CONTENT_VERSION}">
|
|
3369
|
+
<srvb:serviceDefinition adtcore:name="${serviceDefinition}"/>
|
|
3370
|
+
</srvb:content>
|
|
3371
|
+
</srvb:services>
|
|
3372
|
+
<srvb:binding srvb:category="${BINDING_CATEGORY}" srvb:type="${bindingType}" srvb:version="${bindingVersion}">
|
|
3373
|
+
<srvb:implementation adtcore:name=""/>
|
|
3374
|
+
</srvb:binding>
|
|
3375
|
+
</srvb:serviceBinding>`;
|
|
3376
|
+
const params = {};
|
|
3377
|
+
if (options.transport) {
|
|
3378
|
+
params["corrNr"] = options.transport;
|
|
3379
|
+
}
|
|
3380
|
+
const [response, requestErr] = await client.request({
|
|
3381
|
+
method: "POST",
|
|
3382
|
+
path: "/sap/bc/adt/businessservices/bindings",
|
|
3383
|
+
params,
|
|
3384
|
+
headers: { "Content-Type": "application/*" },
|
|
3385
|
+
body
|
|
3386
|
+
});
|
|
3387
|
+
const [, checkErr] = await checkResponse(
|
|
3388
|
+
response,
|
|
3389
|
+
requestErr,
|
|
3390
|
+
`Failed to create service binding ${options.bindingName}`
|
|
3391
|
+
);
|
|
3392
|
+
if (checkErr) return err(checkErr);
|
|
3393
|
+
return ok(void 0);
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
// src/core/adt/businessservices/activate.ts
|
|
3397
|
+
var SERVICE_BINDING_TYPE_CODE2 = "SRVB/SVB";
|
|
3398
|
+
async function activateServiceBinding(client, bindingName) {
|
|
3399
|
+
return activateByReferences(client, [{
|
|
3400
|
+
uri: `/sap/bc/adt/businessservices/bindings/${bindingName.toLowerCase()}`,
|
|
3401
|
+
type: SERVICE_BINDING_TYPE_CODE2,
|
|
3402
|
+
name: bindingName.toUpperCase(),
|
|
3403
|
+
extension: ""
|
|
3404
|
+
}]);
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
// src/core/adt/businessservices/helpers.ts
|
|
3408
|
+
var BINDINGS_BASE_PATH = "/sap/bc/adt/businessservices/bindings";
|
|
3409
|
+
var LOCK_ACCEPT_HEADER = "application/*,application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.lock.result";
|
|
3410
|
+
var PUBLISH_JOBS_PATH = "/sap/bc/adt/businessservices/odatav4/publishjobs";
|
|
3411
|
+
var UNPUBLISH_JOBS_PATH = "/sap/bc/adt/businessservices/odatav4/unpublishjobs";
|
|
3412
|
+
var SEVERITY_OK2 = "OK";
|
|
3413
|
+
function bindingPath(bindingName) {
|
|
3414
|
+
return `${BINDINGS_BASE_PATH}/${bindingName.toLowerCase()}`;
|
|
3415
|
+
}
|
|
3416
|
+
async function lockServiceBinding(client, bindingName) {
|
|
3417
|
+
const [response, requestErr] = await client.request({
|
|
3418
|
+
method: "POST",
|
|
3419
|
+
path: bindingPath(bindingName),
|
|
3420
|
+
params: {
|
|
3421
|
+
"_action": "LOCK",
|
|
3422
|
+
"accessMode": "MODIFY"
|
|
3423
|
+
},
|
|
3424
|
+
headers: { "Accept": LOCK_ACCEPT_HEADER }
|
|
3425
|
+
});
|
|
3426
|
+
const [text, checkErr] = await checkResponse(
|
|
3427
|
+
response,
|
|
3428
|
+
requestErr,
|
|
3429
|
+
`Failed to lock service binding ${bindingName}`
|
|
3430
|
+
);
|
|
3431
|
+
if (checkErr) return err(checkErr);
|
|
3432
|
+
const [lockHandle, extractErr] = extractLockHandle(text);
|
|
3433
|
+
if (extractErr) return err(new Error(`Failed to extract lock handle: ${extractErr.message}`));
|
|
3434
|
+
return ok(lockHandle);
|
|
3435
|
+
}
|
|
3436
|
+
async function unlockServiceBinding(client, bindingName, lockHandle) {
|
|
3437
|
+
const [response, requestErr] = await client.request({
|
|
3438
|
+
method: "POST",
|
|
3439
|
+
path: bindingPath(bindingName),
|
|
3440
|
+
params: {
|
|
3441
|
+
"_action": "UNLOCK",
|
|
3442
|
+
"lockHandle": lockHandle
|
|
3443
|
+
}
|
|
3444
|
+
});
|
|
3445
|
+
const [, checkErr] = await checkResponse(
|
|
3446
|
+
response,
|
|
3447
|
+
requestErr,
|
|
3448
|
+
`Failed to unlock service binding ${bindingName}`
|
|
3449
|
+
);
|
|
3450
|
+
if (checkErr) return err(checkErr);
|
|
3451
|
+
return ok(void 0);
|
|
3452
|
+
}
|
|
3453
|
+
async function submitServiceBindingJob(client, bindingName, action) {
|
|
3454
|
+
const path = action === "publish" ? PUBLISH_JOBS_PATH : UNPUBLISH_JOBS_PATH;
|
|
3455
|
+
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
3456
|
+
<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
|
|
3457
|
+
<adtcore:objectReference adtcore:type="SCGR" adtcore:name="${bindingName.toUpperCase()}"/>
|
|
3458
|
+
</adtcore:objectReferences>`;
|
|
3459
|
+
const [response, requestErr] = await client.request({
|
|
3460
|
+
method: "POST",
|
|
3461
|
+
path,
|
|
3462
|
+
headers: { "Content-Type": "application/xml" },
|
|
3463
|
+
body
|
|
3464
|
+
});
|
|
3465
|
+
const [text, checkErr] = await checkResponse(
|
|
3466
|
+
response,
|
|
3467
|
+
requestErr,
|
|
3468
|
+
`Failed to ${action} service binding ${bindingName}`
|
|
3469
|
+
);
|
|
3470
|
+
if (checkErr) return err(checkErr);
|
|
3471
|
+
const severity = extractTagText(text, "SEVERITY");
|
|
3472
|
+
if (severity && severity !== SEVERITY_OK2) {
|
|
3473
|
+
const shortText = extractTagText(text, "SHORT_TEXT") ?? "";
|
|
3474
|
+
return err(new Error(`Service binding ${action} failed (${severity}): ${shortText}`));
|
|
3475
|
+
}
|
|
3476
|
+
return ok(extractTagText(text, "SHORT_TEXT") ?? "");
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3479
|
+
// src/core/adt/businessservices/publish.ts
|
|
3480
|
+
async function publishServiceBinding(client, bindingName) {
|
|
3481
|
+
return runBindingJob(client, bindingName, "publish");
|
|
3482
|
+
}
|
|
3483
|
+
async function runBindingJob(client, bindingName, action) {
|
|
3484
|
+
const [lockHandle, lockErr] = await lockServiceBinding(client, bindingName);
|
|
3485
|
+
if (lockErr) return err(lockErr);
|
|
3486
|
+
debug(`Service binding lock acquired for ${action}: handle=${lockHandle}`);
|
|
3487
|
+
const [message, jobErr] = await submitServiceBindingJob(client, bindingName, action);
|
|
3488
|
+
const [, unlockErr] = await unlockServiceBinding(client, bindingName, lockHandle);
|
|
3489
|
+
if (jobErr) return err(jobErr);
|
|
3490
|
+
if (unlockErr) return err(unlockErr);
|
|
3491
|
+
return ok(message);
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3494
|
+
// src/core/adt/businessservices/delete.ts
|
|
3495
|
+
async function deleteServiceBinding(client, bindingName, transport) {
|
|
3496
|
+
const [lockHandle, lockErr] = await lockServiceBinding(client, bindingName);
|
|
3497
|
+
if (lockErr) return err(lockErr);
|
|
3498
|
+
const [, unpublishErr] = await submitServiceBindingJob(client, bindingName, "unpublish");
|
|
3499
|
+
if (unpublishErr) debug(`Unpublish before delete skipped: ${unpublishErr.message}`);
|
|
3500
|
+
const params = { lockHandle };
|
|
3501
|
+
if (transport) params["corrNr"] = transport;
|
|
3502
|
+
const [response, requestErr] = await client.request({
|
|
3503
|
+
method: "DELETE",
|
|
3504
|
+
path: bindingPath(bindingName),
|
|
3505
|
+
params,
|
|
3506
|
+
headers: { "Accept": "text/plain" }
|
|
3507
|
+
});
|
|
3508
|
+
const [, checkErr] = await checkResponse(
|
|
3509
|
+
response,
|
|
3510
|
+
requestErr,
|
|
3511
|
+
`Failed to delete service binding ${bindingName}`
|
|
3512
|
+
);
|
|
3513
|
+
if (checkErr) {
|
|
3514
|
+
await unlockServiceBinding(client, bindingName, lockHandle);
|
|
3515
|
+
return err(checkErr);
|
|
3516
|
+
}
|
|
3517
|
+
return ok(void 0);
|
|
3518
|
+
}
|
|
3519
|
+
|
|
2959
3520
|
// src/client/methods/craud/read.ts
|
|
2960
3521
|
async function read(state, requestor, objects) {
|
|
2961
3522
|
if (!state.session) return err(new Error("Not logged in"));
|
|
@@ -3112,6 +3673,12 @@ async function countRows2(state, requestor, objectName, objectType, parameters =
|
|
|
3112
3673
|
return countRows(requestor, objectName, objectType, parameters);
|
|
3113
3674
|
}
|
|
3114
3675
|
|
|
3676
|
+
// src/client/methods/preview/freestyleQuery.ts
|
|
3677
|
+
async function freestyleQuery2(state, requestor, sqlQuery, limit, timeout) {
|
|
3678
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3679
|
+
return freestyleQuery(requestor, sqlQuery, limit, timeout);
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3115
3682
|
// src/client/methods/search/search.ts
|
|
3116
3683
|
async function search(state, requestor, query, options) {
|
|
3117
3684
|
if (!state.session) return err(new Error("Not logged in"));
|
|
@@ -3166,6 +3733,41 @@ function getObjectConfig() {
|
|
|
3166
3733
|
return Object.values(OBJECT_CONFIG_MAP);
|
|
3167
3734
|
}
|
|
3168
3735
|
|
|
3736
|
+
// src/client/methods/businessservices/createServiceBinding.ts
|
|
3737
|
+
async function createServiceBinding(state, requestor, options) {
|
|
3738
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3739
|
+
const [, validateErr] = await validateServiceBinding(requestor, options);
|
|
3740
|
+
if (validateErr) return err(validateErr);
|
|
3741
|
+
const [, createErr] = await createServiceBindingObject(requestor, options, state.session.username);
|
|
3742
|
+
if (createErr) return err(createErr);
|
|
3743
|
+
const [activation, activateErr] = await activateServiceBinding(requestor, options.bindingName);
|
|
3744
|
+
if (activateErr) return err(activateErr);
|
|
3745
|
+
if (activation.some((result2) => result2.status === "error")) {
|
|
3746
|
+
return err(new Error(`Service binding ${options.bindingName} failed activation`));
|
|
3747
|
+
}
|
|
3748
|
+
const result = {
|
|
3749
|
+
name: options.bindingName.toUpperCase(),
|
|
3750
|
+
serviceDefinition: options.serviceDefinition.toUpperCase(),
|
|
3751
|
+
created: true,
|
|
3752
|
+
activation,
|
|
3753
|
+
published: false
|
|
3754
|
+
};
|
|
3755
|
+
if (options.publish === false) {
|
|
3756
|
+
return ok(result);
|
|
3757
|
+
}
|
|
3758
|
+
const [publishMessage, publishErr] = await publishServiceBinding(requestor, options.bindingName);
|
|
3759
|
+
if (publishErr) return err(publishErr);
|
|
3760
|
+
result.published = true;
|
|
3761
|
+
if (publishMessage) result.publishMessage = publishMessage;
|
|
3762
|
+
return ok(result);
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
// src/client/methods/businessservices/deleteServiceBinding.ts
|
|
3766
|
+
async function deleteServiceBinding2(state, requestor, bindingName, transport) {
|
|
3767
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3768
|
+
return deleteServiceBinding(requestor, bindingName, transport);
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3169
3771
|
// src/client/methods/internal/cookies.ts
|
|
3170
3772
|
function storeCookies(cookies, response) {
|
|
3171
3773
|
const setCookieHeader = response.headers.get("set-cookie");
|
|
@@ -3295,7 +3897,7 @@ function buildUrl2(baseUrl, path, params) {
|
|
|
3295
3897
|
// src/client/methods/internal/request.ts
|
|
3296
3898
|
async function executeRequest(deps, options, selfRequest) {
|
|
3297
3899
|
const { state, ssoCerts, getCookieHeader, storeCookies: storeCookies2 } = deps;
|
|
3298
|
-
const { method, path, params, headers: customHeaders, body } = options;
|
|
3900
|
+
const { method, path, params, headers: customHeaders, body, timeout: requestTimeout } = options;
|
|
3299
3901
|
const { config } = state;
|
|
3300
3902
|
debug(`Request ${method} ${path} - CSRF token in state: ${state.csrfToken?.substring(0, 20) || "null"}...`);
|
|
3301
3903
|
const headers = buildRequestHeaders(
|
|
@@ -3322,7 +3924,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3322
3924
|
cert: ssoCerts?.cert,
|
|
3323
3925
|
key: ssoCerts?.key,
|
|
3324
3926
|
rejectUnauthorized: !config.insecure,
|
|
3325
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3927
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3326
3928
|
});
|
|
3327
3929
|
storeCookies2(response);
|
|
3328
3930
|
if (response.status === 403) {
|
|
@@ -3345,7 +3947,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3345
3947
|
cert: ssoCerts?.cert,
|
|
3346
3948
|
key: ssoCerts?.key,
|
|
3347
3949
|
rejectUnauthorized: !config.insecure,
|
|
3348
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3950
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3349
3951
|
});
|
|
3350
3952
|
storeCookies2(retryResponse);
|
|
3351
3953
|
return ok(retryResponse);
|
|
@@ -3516,6 +4118,9 @@ var ADTClientImpl = class {
|
|
|
3516
4118
|
async countRows(objectName, objectType, parameters = []) {
|
|
3517
4119
|
return countRows2(this.state, this.requestor, objectName, objectType, parameters);
|
|
3518
4120
|
}
|
|
4121
|
+
async freestyleQuery(sqlQuery, limit, timeout) {
|
|
4122
|
+
return freestyleQuery2(this.state, this.requestor, sqlQuery, limit, timeout);
|
|
4123
|
+
}
|
|
3519
4124
|
// --- Search ---
|
|
3520
4125
|
async search(query, options) {
|
|
3521
4126
|
return search(this.state, this.requestor, query, options);
|
|
@@ -3540,6 +4145,13 @@ var ADTClientImpl = class {
|
|
|
3540
4145
|
async gitDiff(objects) {
|
|
3541
4146
|
return gitDiff2(this.state, this.requestor, objects);
|
|
3542
4147
|
}
|
|
4148
|
+
// --- Business Services ---
|
|
4149
|
+
async createServiceBinding(options) {
|
|
4150
|
+
return createServiceBinding(this.state, this.requestor, options);
|
|
4151
|
+
}
|
|
4152
|
+
async deleteServiceBinding(bindingName, transport) {
|
|
4153
|
+
return deleteServiceBinding2(this.state, this.requestor, bindingName, transport);
|
|
4154
|
+
}
|
|
3543
4155
|
// --- Configuration ---
|
|
3544
4156
|
getObjectConfig() {
|
|
3545
4157
|
return getObjectConfig();
|
|
@@ -3556,6 +4168,7 @@ function createClient(config) {
|
|
|
3556
4168
|
return ok(new ADTClientImpl(config));
|
|
3557
4169
|
}
|
|
3558
4170
|
export {
|
|
4171
|
+
BehaviorImplementationType,
|
|
3559
4172
|
ExternalReferencesError,
|
|
3560
4173
|
activateLogging,
|
|
3561
4174
|
buildSQLQuery,
|