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/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": "application/xml"
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 = 0;
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": "application/xml" }
1633
+ headers: { "Accept": BACKGROUND_RUN_MEDIA_TYPE }
1633
1634
  });
1634
1635
  if (pollErr) return err(pollErr);
1635
- debug(`Activation poll attempt ${pollAttempt + 1} status: ${pollRes.status}`);
1636
+ debug(`Activation poll attempt ${pollAttempt} status: ${pollRes.status}`);
1636
1637
  if (pollRes.ok) break;
1637
- pollAttempt++;
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 dataType = meta.getAttributeNS(namespace, "colType") || meta.getAttribute("colType");
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
- tasks.push({ taskId, objects });
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);