catalyst-relay 0.5.10 → 0.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -182,7 +182,7 @@ type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
182
182
  /**
183
183
  * Machine-readable error codes
184
184
  */
185
- type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'CHECK_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
185
+ type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'CHECK_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'EXTERNAL_REFERENCES' | 'UNKNOWN_ERROR';
186
186
 
187
187
  /**
188
188
  * Session management type definitions
@@ -308,6 +308,27 @@ interface ActivationMessage {
308
308
  column?: number;
309
309
  }
310
310
 
311
+ /**
312
+ * Where-Used — Find object dependencies
313
+ */
314
+
315
+ /**
316
+ * Where-used dependency
317
+ */
318
+ interface Dependency {
319
+ name: string;
320
+ extension: string;
321
+ package: string;
322
+ usageType: string;
323
+ }
324
+
325
+ interface DeleteResult {
326
+ name: string;
327
+ extension: string;
328
+ status: 'success' | 'error';
329
+ message?: string;
330
+ }
331
+
311
332
  interface CheckResult {
312
333
  name: string;
313
334
  extension: string;
@@ -528,20 +549,6 @@ interface SearchOptions {
528
549
  includePackages?: boolean;
529
550
  }
530
551
 
531
- /**
532
- * Where-Used — Find object dependencies
533
- */
534
-
535
- /**
536
- * Where-used dependency
537
- */
538
- interface Dependency {
539
- name: string;
540
- extension: string;
541
- package: string;
542
- usageType: string;
543
- }
544
-
545
552
  /**
546
553
  * Create Transport — Create a new transport request for a package
547
554
  */
@@ -649,7 +656,7 @@ interface ADTClient {
649
656
  upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;
650
657
  activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;
651
658
  checkSyntax(objects: ObjectRef[]): AsyncResult<CheckResult[]>;
652
- delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;
659
+ delete(objects: ObjectRef[], transport?: string): AsyncResult<DeleteResult[]>;
653
660
  getPackages(options?: GetPackagesOptions): AsyncResult<Package[]>;
654
661
  getTree(query: TreeQuery): AsyncResult<TreeResponse>;
655
662
  getPackageStats(packageName: string): AsyncResult<PackageNode>;
package/dist/index.d.ts CHANGED
@@ -182,7 +182,7 @@ type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
182
182
  /**
183
183
  * Machine-readable error codes
184
184
  */
185
- type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'CHECK_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
185
+ type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'CHECK_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'EXTERNAL_REFERENCES' | 'UNKNOWN_ERROR';
186
186
 
187
187
  /**
188
188
  * Session management type definitions
@@ -308,6 +308,27 @@ interface ActivationMessage {
308
308
  column?: number;
309
309
  }
310
310
 
311
+ /**
312
+ * Where-Used — Find object dependencies
313
+ */
314
+
315
+ /**
316
+ * Where-used dependency
317
+ */
318
+ interface Dependency {
319
+ name: string;
320
+ extension: string;
321
+ package: string;
322
+ usageType: string;
323
+ }
324
+
325
+ interface DeleteResult {
326
+ name: string;
327
+ extension: string;
328
+ status: 'success' | 'error';
329
+ message?: string;
330
+ }
331
+
311
332
  interface CheckResult {
312
333
  name: string;
313
334
  extension: string;
@@ -528,20 +549,6 @@ interface SearchOptions {
528
549
  includePackages?: boolean;
529
550
  }
530
551
 
531
- /**
532
- * Where-Used — Find object dependencies
533
- */
534
-
535
- /**
536
- * Where-used dependency
537
- */
538
- interface Dependency {
539
- name: string;
540
- extension: string;
541
- package: string;
542
- usageType: string;
543
- }
544
-
545
552
  /**
546
553
  * Create Transport — Create a new transport request for a package
547
554
  */
@@ -649,7 +656,7 @@ interface ADTClient {
649
656
  upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;
650
657
  activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;
651
658
  checkSyntax(objects: ObjectRef[]): AsyncResult<CheckResult[]>;
652
- delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;
659
+ delete(objects: ObjectRef[], transport?: string): AsyncResult<DeleteResult[]>;
653
660
  getPackages(options?: GetPackagesOptions): AsyncResult<Package[]>;
654
661
  getTree(query: TreeQuery): AsyncResult<TreeResponse>;
655
662
  getPackageStats(packageName: string): AsyncResult<PackageNode>;
package/dist/index.js CHANGED
@@ -1226,6 +1226,14 @@ var OBJECT_CONFIG_MAP = {
1226
1226
  type: "PROG/P",
1227
1227
  label: "ABAP Program" /* PROGRAM */,
1228
1228
  extension: "asprog"
1229
+ },
1230
+ "asinc": {
1231
+ endpoint: "programs/includes",
1232
+ nameSpace: 'xmlns:include="http://www.sap.com/adt/programs/includes"',
1233
+ rootName: "include:abapInclude",
1234
+ type: "PROG/I",
1235
+ label: "ABAP Include" /* INCLUDE */,
1236
+ extension: "asinc"
1229
1237
  }
1230
1238
  };
1231
1239
  function getConfigByExtension(extension) {
@@ -1287,6 +1295,80 @@ async function readObject(client, object) {
1287
1295
  return ok(result);
1288
1296
  }
1289
1297
 
1298
+ // src/core/adt/discovery/whereUsed.ts
1299
+ async function findWhereUsed(client, object) {
1300
+ const config = getConfigByExtension(object.extension);
1301
+ if (!config) {
1302
+ return err(new Error(`Unsupported extension: ${object.extension}`));
1303
+ }
1304
+ const uri = `/sap/bc/adt/${config.endpoint}/${object.name}`;
1305
+ const body = `<?xml version="1.0" encoding="UTF-8"?>
1306
+ <usagereferences:usageReferenceRequest xmlns:usagereferences="http://www.sap.com/adt/ris/usageReferences">
1307
+ <usagereferences:affectedObjects/>
1308
+ </usagereferences:usageReferenceRequest>`;
1309
+ const [response, requestErr] = await client.request({
1310
+ method: "POST",
1311
+ path: "/sap/bc/adt/repository/informationsystem/usageReferences",
1312
+ params: {
1313
+ "uri": uri,
1314
+ "ris_request_type": "usageReferences"
1315
+ },
1316
+ headers: {
1317
+ "Content-Type": "application/vnd.sap.adt.repository.usagereferences.request.v1+xml",
1318
+ "Accept": "application/vnd.sap.adt.repository.usagereferences.result.v1+xml"
1319
+ },
1320
+ body
1321
+ });
1322
+ if (requestErr) {
1323
+ return err(requestErr);
1324
+ }
1325
+ if (!response.ok) {
1326
+ const text2 = await response.text();
1327
+ const errorMsg = extractError(text2);
1328
+ return err(new Error(`Where-used query failed: ${errorMsg}`));
1329
+ }
1330
+ const text = await response.text();
1331
+ const [dependencies, parseErr] = parseWhereUsed(text);
1332
+ if (parseErr) {
1333
+ return err(parseErr);
1334
+ }
1335
+ return ok(dependencies);
1336
+ }
1337
+ function parseWhereUsed(xml) {
1338
+ const [doc, parseErr] = safeParseXml(xml);
1339
+ if (parseErr) {
1340
+ return err(parseErr);
1341
+ }
1342
+ const dependencies = [];
1343
+ const referencedObjects = doc.getElementsByTagNameNS(
1344
+ "http://www.sap.com/adt/ris/usageReferences",
1345
+ "referencedObject"
1346
+ );
1347
+ for (let i = 0; i < referencedObjects.length; i++) {
1348
+ const refObj = referencedObjects[i];
1349
+ if (!refObj) continue;
1350
+ const adtObject = refObj.getElementsByTagNameNS(
1351
+ "http://www.sap.com/adt/ris/usageReferences",
1352
+ "adtObject"
1353
+ )[0];
1354
+ if (!adtObject) continue;
1355
+ const name = adtObject.getAttributeNS("http://www.sap.com/adt/core", "name") || adtObject.getAttribute("adtcore:name");
1356
+ const type = adtObject.getAttributeNS("http://www.sap.com/adt/core", "type") || adtObject.getAttribute("adtcore:type");
1357
+ if (!name || !type) continue;
1358
+ const config = getConfigByType(type);
1359
+ if (!config) continue;
1360
+ const packageRef = adtObject.getElementsByTagNameNS("http://www.sap.com/adt/core", "packageRef")[0];
1361
+ const packageName = packageRef ? packageRef.getAttributeNS("http://www.sap.com/adt/core", "name") || packageRef.getAttribute("adtcore:name") : "";
1362
+ dependencies.push({
1363
+ name,
1364
+ extension: config.extension,
1365
+ package: packageName || "",
1366
+ usageType: "reference"
1367
+ });
1368
+ }
1369
+ return ok(dependencies);
1370
+ }
1371
+
1290
1372
  // src/core/adt/craud/lock.ts
1291
1373
  async function lockObject(client, object) {
1292
1374
  const [config, configErr] = requireConfig(object.extension);
@@ -1335,6 +1417,135 @@ async function unlockObject(client, object, lockHandle) {
1335
1417
  return ok(void 0);
1336
1418
  }
1337
1419
 
1420
+ // src/core/adt/craud/delete.ts
1421
+ async function deleteObject(client, object, lockHandle, transport) {
1422
+ const [config, configErr] = requireConfig(object.extension);
1423
+ if (configErr) return err(configErr);
1424
+ const params = {
1425
+ "lockHandle": lockHandle
1426
+ };
1427
+ if (transport) {
1428
+ params["corrNr"] = transport;
1429
+ }
1430
+ const [response, requestErr] = await client.request({
1431
+ method: "DELETE",
1432
+ path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,
1433
+ params,
1434
+ headers: { "Accept": "text/plain" }
1435
+ });
1436
+ const [_, checkErr] = await checkResponse(
1437
+ response,
1438
+ requestErr,
1439
+ `Failed to delete ${config.label} ${object.name}`
1440
+ );
1441
+ if (checkErr) return err(checkErr);
1442
+ return ok(void 0);
1443
+ }
1444
+
1445
+ // src/core/adt/craud/multiDelete.ts
1446
+ var ExternalReferencesError = class extends Error {
1447
+ constructor(references) {
1448
+ super(`Cannot delete: ${references.length} external reference(s) prevent the operation`);
1449
+ this.references = references;
1450
+ this.name = "ExternalReferencesError";
1451
+ }
1452
+ };
1453
+ function objKey(o) {
1454
+ return `${o.name.toLowerCase()}|${o.extension}`;
1455
+ }
1456
+ async function multiDeleteObjects(client, objects, transport) {
1457
+ if (objects.length === 0) return ok([]);
1458
+ for (const obj of objects) {
1459
+ if (!getConfigByExtension(obj.extension)) {
1460
+ return err(new Error(`Unsupported extension: ${obj.extension}`));
1461
+ }
1462
+ }
1463
+ const setKeys = /* @__PURE__ */ new Set();
1464
+ const unique = [];
1465
+ for (const obj of objects) {
1466
+ const key = objKey(obj);
1467
+ if (setKeys.has(key)) continue;
1468
+ setKeys.add(key);
1469
+ unique.push(obj);
1470
+ }
1471
+ const whereUsedResults = await Promise.all(
1472
+ unique.map((obj) => findWhereUsed(client, obj))
1473
+ );
1474
+ for (let i = 0; i < whereUsedResults.length; i++) {
1475
+ const [, e] = whereUsedResults[i];
1476
+ if (e) return err(new Error(`where-used failed for ${unique[i].name}: ${e.message}`));
1477
+ }
1478
+ const referencers = /* @__PURE__ */ new Map();
1479
+ const dependents = /* @__PURE__ */ new Map();
1480
+ const externalRefs = [];
1481
+ for (const obj of unique) {
1482
+ referencers.set(objKey(obj), []);
1483
+ dependents.set(objKey(obj), []);
1484
+ }
1485
+ for (let i = 0; i < unique.length; i++) {
1486
+ const obj = unique[i];
1487
+ const oKey = objKey(obj);
1488
+ const [deps] = whereUsedResults[i];
1489
+ for (const dep of deps) {
1490
+ const dKey = objKey(dep);
1491
+ if (dKey === oKey) continue;
1492
+ if (!setKeys.has(dKey)) {
1493
+ externalRefs.push({
1494
+ object: { name: obj.name, extension: obj.extension },
1495
+ referencedBy: dep
1496
+ });
1497
+ continue;
1498
+ }
1499
+ referencers.get(oKey).push(dKey);
1500
+ dependents.get(dKey).push(oKey);
1501
+ }
1502
+ }
1503
+ if (externalRefs.length > 0) {
1504
+ return err(new ExternalReferencesError(externalRefs));
1505
+ }
1506
+ const objByKey = /* @__PURE__ */ new Map();
1507
+ for (const obj of unique) objByKey.set(objKey(obj), obj);
1508
+ const inDegree = /* @__PURE__ */ new Map();
1509
+ for (const [k, refs] of referencers.entries()) {
1510
+ inDegree.set(k, refs.length);
1511
+ }
1512
+ const remaining = new Set(setKeys);
1513
+ const results = [];
1514
+ const deleteOne = async (obj) => {
1515
+ const [lockHandle, lockErr] = await lockObject(client, obj);
1516
+ if (lockErr) {
1517
+ return { name: obj.name, extension: obj.extension, status: "error", message: lockErr.message };
1518
+ }
1519
+ const [, deleteErr] = await deleteObject(client, obj, lockHandle, transport);
1520
+ if (deleteErr) {
1521
+ await unlockObject(client, obj, lockHandle);
1522
+ return { name: obj.name, extension: obj.extension, status: "error", message: deleteErr.message };
1523
+ }
1524
+ return { name: obj.name, extension: obj.extension, status: "success" };
1525
+ };
1526
+ while (remaining.size > 0) {
1527
+ const ready = [];
1528
+ for (const key of remaining) {
1529
+ if ((inDegree.get(key) ?? 0) === 0) ready.push(key);
1530
+ }
1531
+ const waveKeys = ready.length > 0 ? ready : [...remaining];
1532
+ const waveObjects = waveKeys.map((k) => objByKey.get(k));
1533
+ const waveResults = await Promise.all(waveObjects.map(deleteOne));
1534
+ for (let i = 0; i < waveResults.length; i++) {
1535
+ const result = waveResults[i];
1536
+ const key = waveKeys[i];
1537
+ results.push(result);
1538
+ remaining.delete(key);
1539
+ if (result.status === "success") {
1540
+ for (const o of dependents.get(key) ?? []) {
1541
+ inDegree.set(o, (inDegree.get(o) ?? 0) - 1);
1542
+ }
1543
+ }
1544
+ }
1545
+ }
1546
+ return ok(results);
1547
+ }
1548
+
1338
1549
  // src/core/adt/craud/create.ts
1339
1550
  async function createObject(client, object, packageName, transport, username) {
1340
1551
  const [config, configErr] = requireConfig(object.extension);
@@ -1400,59 +1611,31 @@ async function updateObject(client, object, lockHandle, transport) {
1400
1611
  return ok(void 0);
1401
1612
  }
1402
1613
 
1403
- // src/core/adt/craud/delete.ts
1404
- async function deleteObject(client, object, lockHandle, transport) {
1405
- const [config, configErr] = requireConfig(object.extension);
1406
- if (configErr) return err(configErr);
1407
- const params = {
1408
- "lockHandle": lockHandle
1409
- };
1410
- if (transport) {
1411
- params["corrNr"] = transport;
1412
- }
1413
- const [response, requestErr] = await client.request({
1414
- method: "DELETE",
1415
- path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,
1416
- params,
1417
- headers: { "Accept": "text/plain" }
1418
- });
1419
- const [_, checkErr] = await checkResponse(
1420
- response,
1421
- requestErr,
1422
- `Failed to delete ${config.label} ${object.name}`
1423
- );
1424
- if (checkErr) return err(checkErr);
1425
- return ok(void 0);
1426
- }
1427
-
1428
1614
  // src/core/adt/craud/activation.ts
1615
+ var MAX_POLL_ATTEMPTS = 30;
1616
+ var RUN_ID_REGEX = /\/activation\/runs\/([^?/]+)/;
1429
1617
  async function activateObjects(client, objects) {
1430
1618
  if (objects.length === 0) {
1431
1619
  return ok([]);
1432
1620
  }
1433
- const extension = objects[0].extension;
1434
- const config = getConfigByExtension(extension);
1435
- if (!config) return err(new Error(`Unsupported extension: ${extension}`));
1436
1621
  for (const obj of objects) {
1437
- if (obj.extension !== extension) {
1438
- return err(new Error("All objects must have the same extension for batch activation"));
1439
- }
1622
+ const config = getConfigByExtension(obj.extension);
1623
+ if (!config) return err(new Error(`Unsupported extension: ${obj.extension}`));
1440
1624
  }
1441
- const objectRefs = objects.map((obj) => `<adtcore:objectReference
1442
- adtcore:uri="/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}"
1443
- adtcore:type="${config.type}"
1444
- adtcore:name="${obj.name}"
1445
- adtcore:description="*"/>`).join("\n ");
1625
+ const objectRefs = objects.map((obj) => {
1626
+ const config = getConfigByExtension(obj.extension);
1627
+ return `<adtcore:objectReference adtcore:uri="/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}" adtcore:type="${config.type}" adtcore:name="${obj.name}"/>`;
1628
+ }).join("\n ");
1446
1629
  const body = `<?xml version="1.0" encoding="UTF-8"?>
1447
- <adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
1448
- ${objectRefs}
1449
- </adtcore:objectReferences>`;
1450
- const [response, requestErr] = await client.request({
1630
+ <adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
1631
+ ${objectRefs}
1632
+ </adtcore:objectReferences>`;
1633
+ const [startRes, startErr] = await client.request({
1451
1634
  method: "POST",
1452
- path: "/sap/bc/adt/activation",
1635
+ path: "/sap/bc/adt/activation/runs",
1453
1636
  params: {
1454
1637
  "method": "activate",
1455
- "preAuditRequested": "true"
1638
+ "preauditRequested": "false"
1456
1639
  },
1457
1640
  headers: {
1458
1641
  "Content-Type": "application/xml",
@@ -1460,23 +1643,54 @@ async function activateObjects(client, objects) {
1460
1643
  },
1461
1644
  body
1462
1645
  });
1463
- if (requestErr) {
1464
- return err(requestErr);
1465
- }
1466
- const text = await response.text();
1467
- debug(`Activation response status: ${response.status}`);
1468
- debug(`Activation response: ${text.substring(0, 500)}`);
1469
- if (!response.ok) {
1470
- const errorMsg = extractError(text);
1471
- return err(new Error(`Activation failed: ${errorMsg}`));
1472
- }
1473
- const [results, parseErr] = extractActivationErrors(objects, text, extension);
1474
- if (parseErr) {
1475
- return err(parseErr);
1646
+ if (startErr) return err(startErr);
1647
+ debug(`Activation run start status: ${startRes.status}`);
1648
+ if (!startRes.ok) {
1649
+ const errText = await startRes.text();
1650
+ return err(new Error(`Activation start failed: ${extractError(errText)}`));
1651
+ }
1652
+ const location = startRes.headers.get("location");
1653
+ if (!location) return err(new Error("Activation start response missing Location header"));
1654
+ const runIdMatch = RUN_ID_REGEX.exec(location);
1655
+ if (!runIdMatch || !runIdMatch[1]) {
1656
+ return err(new Error(`Could not extract run ID from Location header: ${location}`));
1657
+ }
1658
+ const runId = runIdMatch[1];
1659
+ debug(`Activation run ID: ${runId}`);
1660
+ let pollAttempt = 0;
1661
+ while (pollAttempt < MAX_POLL_ATTEMPTS) {
1662
+ const [pollRes, pollErr] = await client.request({
1663
+ method: "GET",
1664
+ path: `/sap/bc/adt/activation/runs/${runId}`,
1665
+ params: { "withLongPolling": "true" },
1666
+ headers: { "Accept": "application/xml" }
1667
+ });
1668
+ if (pollErr) return err(pollErr);
1669
+ debug(`Activation poll attempt ${pollAttempt + 1} status: ${pollRes.status}`);
1670
+ if (pollRes.ok) break;
1671
+ pollAttempt++;
1672
+ if (pollAttempt >= MAX_POLL_ATTEMPTS) {
1673
+ const errText = await pollRes.text();
1674
+ return err(new Error(`Activation run ${runId} did not complete: ${extractError(errText)}`));
1675
+ }
1476
1676
  }
1677
+ const [resultsRes, resultsErr] = await client.request({
1678
+ method: "GET",
1679
+ path: `/sap/bc/adt/activation/results/${runId}`,
1680
+ headers: { "Accept": "application/xml" }
1681
+ });
1682
+ if (resultsErr) return err(resultsErr);
1683
+ const resultsText = await resultsRes.text();
1684
+ debug(`Activation results status: ${resultsRes.status}`);
1685
+ debug(`Activation results body: ${resultsText.substring(0, 500)}`);
1686
+ if (!resultsRes.ok) {
1687
+ return err(new Error(`Failed to fetch activation results: ${extractError(resultsText)}`));
1688
+ }
1689
+ const [results, parseErr] = extractActivationErrors(objects, resultsText);
1690
+ if (parseErr) return err(parseErr);
1477
1691
  return ok(results);
1478
1692
  }
1479
- function extractActivationErrors(objects, xml, _extension) {
1693
+ function extractActivationErrors(objects, xml) {
1480
1694
  const [doc, parseErr] = safeParseXml(xml);
1481
1695
  if (parseErr) {
1482
1696
  return err(parseErr);
@@ -2478,80 +2692,6 @@ function parseSearchResults(xml) {
2478
2692
  return ok(results);
2479
2693
  }
2480
2694
 
2481
- // src/core/adt/discovery/whereUsed.ts
2482
- async function findWhereUsed(client, object) {
2483
- const config = getConfigByExtension(object.extension);
2484
- if (!config) {
2485
- return err(new Error(`Unsupported extension: ${object.extension}`));
2486
- }
2487
- const uri = `/sap/bc/adt/${config.endpoint}/${object.name}`;
2488
- const body = `<?xml version="1.0" encoding="UTF-8"?>
2489
- <usagereferences:usageReferenceRequest xmlns:usagereferences="http://www.sap.com/adt/ris/usageReferences">
2490
- <usagereferences:affectedObjects/>
2491
- </usagereferences:usageReferenceRequest>`;
2492
- const [response, requestErr] = await client.request({
2493
- method: "POST",
2494
- path: "/sap/bc/adt/repository/informationsystem/usageReferences",
2495
- params: {
2496
- "uri": uri,
2497
- "ris_request_type": "usageReferences"
2498
- },
2499
- headers: {
2500
- "Content-Type": "application/vnd.sap.adt.repository.usagereferences.request.v1+xml",
2501
- "Accept": "application/vnd.sap.adt.repository.usagereferences.result.v1+xml"
2502
- },
2503
- body
2504
- });
2505
- if (requestErr) {
2506
- return err(requestErr);
2507
- }
2508
- if (!response.ok) {
2509
- const text2 = await response.text();
2510
- const errorMsg = extractError(text2);
2511
- return err(new Error(`Where-used query failed: ${errorMsg}`));
2512
- }
2513
- const text = await response.text();
2514
- const [dependencies, parseErr] = parseWhereUsed(text);
2515
- if (parseErr) {
2516
- return err(parseErr);
2517
- }
2518
- return ok(dependencies);
2519
- }
2520
- function parseWhereUsed(xml) {
2521
- const [doc, parseErr] = safeParseXml(xml);
2522
- if (parseErr) {
2523
- return err(parseErr);
2524
- }
2525
- const dependencies = [];
2526
- const referencedObjects = doc.getElementsByTagNameNS(
2527
- "http://www.sap.com/adt/ris/usageReferences",
2528
- "referencedObject"
2529
- );
2530
- for (let i = 0; i < referencedObjects.length; i++) {
2531
- const refObj = referencedObjects[i];
2532
- if (!refObj) continue;
2533
- const adtObject = refObj.getElementsByTagNameNS(
2534
- "http://www.sap.com/adt/ris/usageReferences",
2535
- "adtObject"
2536
- )[0];
2537
- if (!adtObject) continue;
2538
- const name = adtObject.getAttributeNS("http://www.sap.com/adt/core", "name") || adtObject.getAttribute("adtcore:name");
2539
- const type = adtObject.getAttributeNS("http://www.sap.com/adt/core", "type") || adtObject.getAttribute("adtcore:type");
2540
- if (!name || !type) continue;
2541
- const config = getConfigByType(type);
2542
- if (!config) continue;
2543
- const packageRef = adtObject.getElementsByTagNameNS("http://www.sap.com/adt/core", "packageRef")[0];
2544
- const packageName = packageRef ? packageRef.getAttributeNS("http://www.sap.com/adt/core", "name") || packageRef.getAttribute("adtcore:name") : "";
2545
- dependencies.push({
2546
- name,
2547
- extension: config.extension,
2548
- package: packageName || "",
2549
- usageType: "reference"
2550
- });
2551
- }
2552
- return ok(dependencies);
2553
- }
2554
-
2555
2695
  // src/core/adt/transports/createTransport.ts
2556
2696
  async function createTransport(client, config) {
2557
2697
  const body = dictToAbapXml({
@@ -2944,16 +3084,7 @@ async function activate(state, requestor, objects) {
2944
3084
  // src/client/methods/craud/delete.ts
2945
3085
  async function deleteObjects(state, requestor, objects, transport) {
2946
3086
  if (!state.session) return err(new Error("Not logged in"));
2947
- for (const obj of objects) {
2948
- const [lockHandle, lockErr] = await lockObject(requestor, obj);
2949
- if (lockErr) return err(lockErr);
2950
- const [, deleteErr] = await deleteObject(requestor, obj, lockHandle, transport);
2951
- if (deleteErr) {
2952
- await unlockObject(requestor, obj, lockHandle);
2953
- return err(deleteErr);
2954
- }
2955
- }
2956
- return ok(void 0);
3087
+ return multiDeleteObjects(requestor, objects, transport);
2957
3088
  }
2958
3089
 
2959
3090
  // src/client/methods/craud/checkSyntax.ts