catalyst-relay 0.5.12 → 0.5.14
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 +30 -16
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +92 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +92 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1579,7 +1579,9 @@ async function updateObject(client, object, lockHandle, transport) {
|
|
|
1579
1579
|
|
|
1580
1580
|
// src/core/adt/craud/activation.ts
|
|
1581
1581
|
var MAX_POLL_ATTEMPTS = 30;
|
|
1582
|
+
var POLL_RETRY_DELAY_MS = 1e3;
|
|
1582
1583
|
var RUN_ID_REGEX = /\/activation\/runs\/([^?/]+)/;
|
|
1584
|
+
var BACKGROUND_RUN_MEDIA_TYPE = "application/vnd.sap.adt.backgroundrun.v1+xml";
|
|
1583
1585
|
async function activateObjects(client, objects) {
|
|
1584
1586
|
if (objects.length === 0) {
|
|
1585
1587
|
return ok([]);
|
|
@@ -1605,7 +1607,7 @@ async function activateObjects(client, objects) {
|
|
|
1605
1607
|
},
|
|
1606
1608
|
headers: {
|
|
1607
1609
|
"Content-Type": "application/xml",
|
|
1608
|
-
"Accept":
|
|
1610
|
+
"Accept": BACKGROUND_RUN_MEDIA_TYPE
|
|
1609
1611
|
},
|
|
1610
1612
|
body
|
|
1611
1613
|
});
|
|
@@ -1623,22 +1625,25 @@ async function activateObjects(client, objects) {
|
|
|
1623
1625
|
}
|
|
1624
1626
|
const runId = runIdMatch[1];
|
|
1625
1627
|
debug(`Activation run ID: ${runId}`);
|
|
1626
|
-
let pollAttempt =
|
|
1627
|
-
while (pollAttempt < MAX_POLL_ATTEMPTS) {
|
|
1628
|
+
for (let pollAttempt = 1; pollAttempt <= MAX_POLL_ATTEMPTS; pollAttempt++) {
|
|
1628
1629
|
const [pollRes, pollErr] = await client.request({
|
|
1629
1630
|
method: "GET",
|
|
1630
1631
|
path: `/sap/bc/adt/activation/runs/${runId}`,
|
|
1631
1632
|
params: { "withLongPolling": "true" },
|
|
1632
|
-
headers: { "Accept":
|
|
1633
|
+
headers: { "Accept": BACKGROUND_RUN_MEDIA_TYPE }
|
|
1633
1634
|
});
|
|
1634
1635
|
if (pollErr) return err(pollErr);
|
|
1635
|
-
debug(`Activation poll attempt ${pollAttempt
|
|
1636
|
+
debug(`Activation poll attempt ${pollAttempt} status: ${pollRes.status}`);
|
|
1636
1637
|
if (pollRes.ok) break;
|
|
1637
|
-
|
|
1638
|
+
if (pollRes.status >= 400 && pollRes.status < 500) {
|
|
1639
|
+
const errText = await pollRes.text();
|
|
1640
|
+
return err(new Error(`Activation run ${runId} polling rejected (${pollRes.status}): ${extractError(errText)}`));
|
|
1641
|
+
}
|
|
1638
1642
|
if (pollAttempt >= MAX_POLL_ATTEMPTS) {
|
|
1639
1643
|
const errText = await pollRes.text();
|
|
1640
|
-
return err(new Error(`Activation run ${runId} did not complete: ${extractError(errText)}`));
|
|
1644
|
+
return err(new Error(`Activation run ${runId} did not complete after ${MAX_POLL_ATTEMPTS} attempts: ${extractError(errText)}`));
|
|
1641
1645
|
}
|
|
1646
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_RETRY_DELAY_MS));
|
|
1642
1647
|
}
|
|
1643
1648
|
const [resultsRes, resultsErr] = await client.request({
|
|
1644
1649
|
method: "GET",
|
|
@@ -2341,16 +2346,64 @@ function parseDataPreview(xml, maxRows, isTable) {
|
|
|
2341
2346
|
const namespace = "http://www.sap.com/adt/dataPreview";
|
|
2342
2347
|
const metadataElements = doc.getElementsByTagNameNS(namespace, "metadata");
|
|
2343
2348
|
const columns = [];
|
|
2349
|
+
const SAP_TYPE_MAP = {
|
|
2350
|
+
"8": "integer",
|
|
2351
|
+
// Int8
|
|
2352
|
+
"I": "integer",
|
|
2353
|
+
// Integer
|
|
2354
|
+
"P": "decimal",
|
|
2355
|
+
// Packed decimal
|
|
2356
|
+
"F": "float",
|
|
2357
|
+
// Floating point
|
|
2358
|
+
"D": "date",
|
|
2359
|
+
// Date (YYYYMMDD)
|
|
2360
|
+
"T": "time",
|
|
2361
|
+
// Time (HHMMSS)
|
|
2362
|
+
"S": "timestamp",
|
|
2363
|
+
// Timestamp
|
|
2364
|
+
"C": "string",
|
|
2365
|
+
// Character
|
|
2366
|
+
"N": "string",
|
|
2367
|
+
// Numeric character string
|
|
2368
|
+
"V": "string",
|
|
2369
|
+
// Variable-length character
|
|
2370
|
+
"X": "binary"
|
|
2371
|
+
// Raw binary/hex
|
|
2372
|
+
};
|
|
2344
2373
|
for (let i = 0; i < metadataElements.length; i++) {
|
|
2345
2374
|
const meta = metadataElements[i];
|
|
2346
2375
|
if (!meta) continue;
|
|
2347
2376
|
const nameAttr = isTable ? "name" : "camelCaseName";
|
|
2348
2377
|
const name = meta.getAttributeNS(namespace, nameAttr) || meta.getAttribute("name");
|
|
2349
|
-
const
|
|
2378
|
+
const colType = meta.getAttributeNS(namespace, "colType") || meta.getAttribute("colType");
|
|
2379
|
+
const rawType = meta.getAttributeNS(namespace, "type") || meta.getAttribute("type");
|
|
2380
|
+
const isKeyFigure = meta.getAttributeNS(namespace, "isKeyFigure") === "true";
|
|
2381
|
+
let dataType;
|
|
2382
|
+
if (colType && colType.trim() !== "") {
|
|
2383
|
+
dataType = colType;
|
|
2384
|
+
} else if (isKeyFigure) {
|
|
2385
|
+
dataType = "decimal";
|
|
2386
|
+
} else if (rawType && SAP_TYPE_MAP[rawType]) {
|
|
2387
|
+
dataType = SAP_TYPE_MAP[rawType];
|
|
2388
|
+
} else {
|
|
2389
|
+
dataType = "string";
|
|
2390
|
+
}
|
|
2391
|
+
const allAttrs = {};
|
|
2392
|
+
for (let j = 0; j < meta.attributes.length; j++) {
|
|
2393
|
+
const attr = meta.attributes[j];
|
|
2394
|
+
if (!attr) {
|
|
2395
|
+
continue;
|
|
2396
|
+
}
|
|
2397
|
+
allAttrs[attr.name] = attr.value;
|
|
2398
|
+
}
|
|
2350
2399
|
if (!name || !dataType) continue;
|
|
2351
2400
|
columns.push({ name, dataType });
|
|
2352
2401
|
}
|
|
2353
2402
|
const dataSetElements = doc.getElementsByTagNameNS(namespace, "dataSet");
|
|
2403
|
+
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2404
|
+
const dataSet = dataSetElements[i];
|
|
2405
|
+
if (!dataSet) continue;
|
|
2406
|
+
}
|
|
2354
2407
|
if (columns.length === 0 && dataSetElements.length > 0) {
|
|
2355
2408
|
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2356
2409
|
const dataSet = dataSetElements[i];
|
|
@@ -2433,7 +2486,7 @@ async function previewData(client, query) {
|
|
|
2433
2486
|
|
|
2434
2487
|
// src/core/adt/data_extraction/freestyle.ts
|
|
2435
2488
|
var DEFAULT_ROW_LIMIT = 100;
|
|
2436
|
-
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
2489
|
+
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT, timeout) {
|
|
2437
2490
|
debug(`Freestyle query: ${sqlQuery}`);
|
|
2438
2491
|
const [response, requestErr] = await client.request({
|
|
2439
2492
|
method: "POST",
|
|
@@ -2443,16 +2496,21 @@ async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
|
2443
2496
|
},
|
|
2444
2497
|
headers: {
|
|
2445
2498
|
"Accept": "application/xml, application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
2446
|
-
"Content-Type": "text/plain"
|
|
2499
|
+
"Content-Type": "text/plain",
|
|
2500
|
+
// Override stateful base header: each preview request is independent; stateless
|
|
2501
|
+
// lets SAP route to any work process and recycle it after the request, preventing
|
|
2502
|
+
// GENERATE_SUBPOOL_DIR_FULL (36-pool limit per work process).
|
|
2503
|
+
"X-sap-adt-sessiontype": "stateless"
|
|
2447
2504
|
},
|
|
2448
|
-
body: sqlQuery
|
|
2505
|
+
body: sqlQuery,
|
|
2506
|
+
...timeout !== void 0 && { timeout }
|
|
2449
2507
|
});
|
|
2450
2508
|
if (requestErr) return err(requestErr);
|
|
2451
2509
|
if (!response.ok) {
|
|
2452
2510
|
const text2 = await response.text();
|
|
2453
2511
|
debug(`Freestyle query error response: ${text2.substring(0, 500)}`);
|
|
2454
2512
|
const errorMsg = extractError(text2);
|
|
2455
|
-
return err(new Error(`Freestyle query failed: ${errorMsg}
|
|
2513
|
+
return err(new Error(`Freestyle query failed: ${errorMsg}`, { cause: text2 }));
|
|
2456
2514
|
}
|
|
2457
2515
|
const text = await response.text();
|
|
2458
2516
|
const [dataFrame, parseErr] = parseDataPreview(text, limit, true);
|
|
@@ -2713,7 +2771,16 @@ function parseTransportTasks(doc) {
|
|
|
2713
2771
|
position: el.getAttribute("tm:position") || ""
|
|
2714
2772
|
});
|
|
2715
2773
|
}
|
|
2716
|
-
|
|
2774
|
+
const owner = taskEl.getAttribute("tm:owner");
|
|
2775
|
+
const description = taskEl.getAttribute("tm:desc");
|
|
2776
|
+
const status = taskEl.getAttribute("tm:status");
|
|
2777
|
+
tasks.push({
|
|
2778
|
+
taskId,
|
|
2779
|
+
...owner ? { owner } : {},
|
|
2780
|
+
...description ? { description } : {},
|
|
2781
|
+
...status ? { status } : {},
|
|
2782
|
+
objects
|
|
2783
|
+
});
|
|
2717
2784
|
}
|
|
2718
2785
|
return tasks;
|
|
2719
2786
|
}
|
|
@@ -3107,6 +3174,12 @@ async function countRows2(state, requestor, objectName, objectType, parameters =
|
|
|
3107
3174
|
return countRows(requestor, objectName, objectType, parameters);
|
|
3108
3175
|
}
|
|
3109
3176
|
|
|
3177
|
+
// src/client/methods/preview/freestyleQuery.ts
|
|
3178
|
+
async function freestyleQuery2(state, requestor, sqlQuery, limit, timeout) {
|
|
3179
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3180
|
+
return freestyleQuery(requestor, sqlQuery, limit, timeout);
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3110
3183
|
// src/client/methods/search/search.ts
|
|
3111
3184
|
async function search(state, requestor, query, options) {
|
|
3112
3185
|
if (!state.session) return err(new Error("Not logged in"));
|
|
@@ -3290,7 +3363,7 @@ function buildUrl2(baseUrl, path, params) {
|
|
|
3290
3363
|
// src/client/methods/internal/request.ts
|
|
3291
3364
|
async function executeRequest(deps, options, selfRequest) {
|
|
3292
3365
|
const { state, ssoCerts, getCookieHeader, storeCookies: storeCookies2 } = deps;
|
|
3293
|
-
const { method, path, params, headers: customHeaders, body } = options;
|
|
3366
|
+
const { method, path, params, headers: customHeaders, body, timeout: requestTimeout } = options;
|
|
3294
3367
|
const { config } = state;
|
|
3295
3368
|
debug(`Request ${method} ${path} - CSRF token in state: ${state.csrfToken?.substring(0, 20) || "null"}...`);
|
|
3296
3369
|
const headers = buildRequestHeaders(
|
|
@@ -3317,7 +3390,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3317
3390
|
cert: ssoCerts?.cert,
|
|
3318
3391
|
key: ssoCerts?.key,
|
|
3319
3392
|
rejectUnauthorized: !config.insecure,
|
|
3320
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3393
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3321
3394
|
});
|
|
3322
3395
|
storeCookies2(response);
|
|
3323
3396
|
if (response.status === 403) {
|
|
@@ -3340,7 +3413,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3340
3413
|
cert: ssoCerts?.cert,
|
|
3341
3414
|
key: ssoCerts?.key,
|
|
3342
3415
|
rejectUnauthorized: !config.insecure,
|
|
3343
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3416
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3344
3417
|
});
|
|
3345
3418
|
storeCookies2(retryResponse);
|
|
3346
3419
|
return ok(retryResponse);
|
|
@@ -3511,6 +3584,9 @@ var ADTClientImpl = class {
|
|
|
3511
3584
|
async countRows(objectName, objectType, parameters = []) {
|
|
3512
3585
|
return countRows2(this.state, this.requestor, objectName, objectType, parameters);
|
|
3513
3586
|
}
|
|
3587
|
+
async freestyleQuery(sqlQuery, limit, timeout) {
|
|
3588
|
+
return freestyleQuery2(this.state, this.requestor, sqlQuery, limit, timeout);
|
|
3589
|
+
}
|
|
3514
3590
|
// --- Search ---
|
|
3515
3591
|
async search(query, options) {
|
|
3516
3592
|
return search(this.state, this.requestor, query, options);
|