@mcp-abap-adt/adt-backup 0.1.2 → 1.0.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.
Files changed (66) hide show
  1. package/README.md +4 -2
  2. package/dist/bin/adt-backup.js +0 -0
  3. package/dist/lib/auth/createTokenProvider.d.ts +1 -1
  4. package/dist/lib/auth/createTokenProvider.d.ts.map +1 -1
  5. package/dist/lib/auth/createTokenProvider.js +2 -1
  6. package/dist/lib/auth/getSapConfigFromBroker.d.ts +1 -0
  7. package/dist/lib/auth/getSapConfigFromBroker.d.ts.map +1 -1
  8. package/dist/lib/auth/getSapConfigFromBroker.js +94 -95
  9. package/dist/lib/backup/backupObject.js +5 -5
  10. package/dist/lib/backup/readMetadataXmlForType.d.ts +1 -1
  11. package/dist/lib/backup/readMetadataXmlForType.d.ts.map +1 -1
  12. package/dist/lib/backup/readMetadataXmlForType.js +113 -98
  13. package/dist/lib/backup/readSourceText.d.ts +1 -1
  14. package/dist/lib/backup/readSourceText.d.ts.map +1 -1
  15. package/dist/lib/backup/readSourceText.js +96 -93
  16. package/dist/lib/cli/createLogger.d.ts.map +1 -1
  17. package/dist/lib/cli/createLogger.js +18 -0
  18. package/dist/lib/cli/parseArgs.d.ts +1 -1
  19. package/dist/lib/cli/parseArgs.d.ts.map +1 -1
  20. package/dist/lib/cli/parseArgs.js +25 -10
  21. package/dist/lib/cli/usage.d.ts.map +1 -1
  22. package/dist/lib/cli/usage.js +92 -88
  23. package/dist/lib/restore/analyzeDependencies.d.ts +13 -0
  24. package/dist/lib/restore/analyzeDependencies.d.ts.map +1 -0
  25. package/dist/lib/restore/analyzeDependencies.js +187 -0
  26. package/dist/lib/restore/restoreObjects.d.ts.map +1 -1
  27. package/dist/lib/restore/restoreObjects.js +49 -10
  28. package/dist/lib/restore/restoreTreeBackup.d.ts +1 -1
  29. package/dist/lib/restore/restoreTreeBackup.d.ts.map +1 -1
  30. package/dist/lib/restore/restoreTreeBackup.js +192 -42
  31. package/dist/lib/restore/restoreTreeNode.d.ts +1 -1
  32. package/dist/lib/restore/restoreTreeNode.d.ts.map +1 -1
  33. package/dist/lib/restore/restoreTreeNode.js +116 -37
  34. package/dist/lib/run.d.ts.map +1 -1
  35. package/dist/lib/run.js +393 -559
  36. package/dist/lib/tree/buildConfigForNode.d.ts.map +1 -1
  37. package/dist/lib/tree/buildConfigForNode.js +11 -0
  38. package/dist/lib/tree/buildPackageBackupTree.d.ts.map +1 -1
  39. package/dist/lib/tree/buildPackageBackupTree.js +9 -3
  40. package/dist/lib/tree/enrichTreeNode.d.ts.map +1 -1
  41. package/dist/lib/tree/enrichTreeNode.js +17 -1
  42. package/dist/lib/tree/isRestoreImplemented.d.ts.map +1 -1
  43. package/dist/lib/tree/isRestoreImplemented.js +1 -0
  44. package/dist/lib/tree/mapAdtTypeToSupported.d.ts.map +1 -1
  45. package/dist/lib/tree/mapAdtTypeToSupported.js +3 -0
  46. package/dist/lib/tree/readPayloadForType.d.ts.map +1 -1
  47. package/dist/lib/tree/readPayloadForType.js +3 -2
  48. package/dist/lib/types.d.ts +22 -2
  49. package/dist/lib/types.d.ts.map +1 -1
  50. package/dist/lib/utils/applyConfigName.d.ts.map +1 -1
  51. package/dist/lib/utils/applyConfigName.js +3 -0
  52. package/dist/lib/utils/parseBdefSource.d.ts +9 -0
  53. package/dist/lib/utils/parseBdefSource.d.ts.map +1 -0
  54. package/dist/lib/utils/parseBdefSource.js +18 -0
  55. package/dist/lib/verify/formatVerifyResultsText.d.ts +1 -1
  56. package/dist/lib/verify/formatVerifyResultsText.d.ts.map +1 -1
  57. package/dist/lib/verify/formatVerifyResultsText.js +76 -14
  58. package/dist/lib/verify/types.d.ts +3 -0
  59. package/dist/lib/verify/types.d.ts.map +1 -1
  60. package/dist/lib/verify/verifyBackup.d.ts +4 -2
  61. package/dist/lib/verify/verifyBackup.d.ts.map +1 -1
  62. package/dist/lib/verify/verifyBackup.js +67 -32
  63. package/dist/lib/verify/verifyObjectInSystem.d.ts +1 -1
  64. package/dist/lib/verify/verifyObjectInSystem.d.ts.map +1 -1
  65. package/dist/lib/verify/verifyObjectInSystem.js +39 -105
  66. package/package.json +6 -6
@@ -5,13 +5,34 @@ const logVerbose_1 = require("../cli/logVerbose");
5
5
  const decodeBase64_1 = require("../crypto/decodeBase64");
6
6
  const asConfig_1 = require("../utils/asConfig");
7
7
  const ensureDescription_1 = require("../utils/ensureDescription");
8
+ const parseBdefSource_1 = require("../utils/parseBdefSource");
9
+ const parsePackageConfig_1 = require("../xml/parsePackageConfig");
8
10
  const applyTransportRequest_1 = require("./applyTransportRequest");
9
- async function restoreTreeNode(client, node, mode, activate, transportRequest, softwareComponentOverride, backupPackageNames) {
11
+ async function restoreTreeNode(client, node, mode, activate, transportRequest, softwareComponentOverride, backupPackageNames, superPackageOverride, transportLayerOverride) {
12
+ if (mode === 'skip') {
13
+ (0, logVerbose_1.logVerbose)(2, ` [SKIP] ${node.type}:${node.name}`);
14
+ return;
15
+ }
10
16
  if (!node.type || node.restoreStatus !== 'ok') {
11
17
  return;
12
18
  }
13
- const config = (0, applyTransportRequest_1.applyTransportRequest)((0, ensureDescription_1.ensureDescription)(node.config || {}, node.name), transportRequest);
19
+ // Use existing config or try to extract from XML if missing
20
+ let nodeConfig = node.config;
21
+ if (!nodeConfig &&
22
+ node.codeBase64 &&
23
+ node.codeFormat === 'xml' &&
24
+ node.type === 'package') {
25
+ try {
26
+ const xml = (0, decodeBase64_1.decodeBase64)(node.codeBase64);
27
+ nodeConfig = (0, parsePackageConfig_1.parsePackageConfig)(xml);
28
+ }
29
+ catch (_e) {
30
+ (0, logVerbose_1.logVerbose)(2, ` Could not parse XML config for package ${node.name}`);
31
+ }
32
+ }
33
+ const config = (0, applyTransportRequest_1.applyTransportRequest)((0, ensureDescription_1.ensureDescription)(nodeConfig || {}, node.name), transportRequest);
14
34
  const payload = node.codeBase64 ? (0, decodeBase64_1.decodeBase64)(node.codeBase64) : undefined;
35
+ // Standard options for most objects
15
36
  const options = {
16
37
  activateOnCreate: activate,
17
38
  activateOnUpdate: activate,
@@ -20,30 +41,48 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
20
41
  switch (node.type) {
21
42
  case 'package': {
22
43
  const pkgConfig = (0, asConfig_1.asConfig)(config);
23
- // Remove responsible field - let system use current user
24
- // (backup might have user that doesn't exist in target system)
44
+ if (!pkgConfig.packageName) {
45
+ pkgConfig.packageName = node.name;
46
+ }
25
47
  if (pkgConfig.responsible) {
26
48
  delete pkgConfig.responsible;
27
49
  }
28
- // Check if this package's superPackage is within our backup tree
29
50
  const superPackageInBackup = pkgConfig.superPackage &&
30
51
  backupPackageNames?.has(pkgConfig.superPackage);
31
- (0, logVerbose_1.logVerbose)(3, `Package ${node.name}: superPackage=${pkgConfig.superPackage}, softwareComponent=${pkgConfig.softwareComponent}, superPackageInBackup=${superPackageInBackup}`);
32
- // Set softwareComponent for all packages
33
- // Priority: CLI override > config value > default 'ZLOCAL'
34
- // For sub-packages, use CLI override to ensure consistency with parent
52
+ if (!superPackageInBackup && superPackageOverride) {
53
+ pkgConfig.superPackage = superPackageOverride;
54
+ }
35
55
  if (softwareComponentOverride) {
36
56
  pkgConfig.softwareComponent = softwareComponentOverride;
37
57
  }
38
58
  else if (!pkgConfig.softwareComponent) {
39
59
  pkgConfig.softwareComponent = 'ZLOCAL';
40
60
  }
41
- (0, logVerbose_1.logVerbose)(3, `Package ${node.name}: final softwareComponent=${pkgConfig.softwareComponent}`);
61
+ // Fix for the transport layer mapping issue in adt-clients
62
+ if (transportLayerOverride) {
63
+ pkgConfig.transportLayer = transportLayerOverride;
64
+ pkgConfig.transport_layer = transportLayerOverride;
65
+ }
66
+ pkgConfig.recordChanges = true;
42
67
  if (mode !== 'update') {
68
+ if (!pkgConfig.superPackage && node.type === 'package') {
69
+ throw new Error(`Package ${node.name} cannot be created: superPackage is missing.`);
70
+ }
71
+ (0, logVerbose_1.logVerbose)(3, ` Creating package ${node.name} (Layer: ${pkgConfig.transportLayer}, SoftwareComp: ${pkgConfig.softwareComponent})`);
43
72
  await client.getPackage().create(pkgConfig, options);
73
+ // Wait for SAP to commit the package to the database
74
+ // ADT has no event subscription for creation completion
75
+ await delay(2000);
44
76
  }
45
77
  if (mode !== 'create') {
46
- await client.getPackage().update(pkgConfig, options);
78
+ try {
79
+ await client.getPackage().update(pkgConfig, options);
80
+ }
81
+ catch (error) {
82
+ const msg = error instanceof Error ? error.message : String(error);
83
+ (0, logVerbose_1.logVerbose)(1, ` [SKIP] Package ${node.name} update skipped`);
84
+ (0, logVerbose_1.logVerbose)(3, ` Reason: ${msg.slice(0, 200)}`);
85
+ }
47
86
  }
48
87
  return;
49
88
  }
@@ -53,11 +92,10 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
53
92
  .getDomain()
54
93
  .create((0, asConfig_1.asConfig)(config), options);
55
94
  }
56
- if (mode !== 'create') {
57
- await client
58
- .getDomain()
59
- .update((0, asConfig_1.asConfig)(config), options);
60
- }
95
+ // Always update to set datatype/length/decimals (create only registers the name)
96
+ await client
97
+ .getDomain()
98
+ .update((0, asConfig_1.asConfig)(config), options);
61
99
  return;
62
100
  }
63
101
  case 'dataElement': {
@@ -66,11 +104,10 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
66
104
  .getDataElement()
67
105
  .create((0, asConfig_1.asConfig)(config), options);
68
106
  }
69
- if (mode !== 'create') {
70
- await client
71
- .getDataElement()
72
- .update((0, asConfig_1.asConfig)(config), options);
73
- }
107
+ // Always update to set typeKind/typeName/dataType (create only registers the name)
108
+ await client
109
+ .getDataElement()
110
+ .update((0, asConfig_1.asConfig)(config), options);
74
111
  return;
75
112
  }
76
113
  case 'structure': {
@@ -159,11 +196,10 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
159
196
  .getFunctionGroup()
160
197
  .create((0, asConfig_1.asConfig)(config), options);
161
198
  }
162
- if (mode !== 'create') {
163
- await client
164
- .getFunctionGroup()
165
- .update((0, asConfig_1.asConfig)(config), options);
166
- }
199
+ // Always update to set properties (create only registers the name)
200
+ await client
201
+ .getFunctionGroup()
202
+ .update((0, asConfig_1.asConfig)(config), options);
167
203
  return;
168
204
  }
169
205
  case 'functionModule': {
@@ -200,11 +236,29 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
200
236
  .getServiceBinding()
201
237
  .create((0, asConfig_1.asConfig)(config), options);
202
238
  }
203
- if (mode !== 'create') {
239
+ // Always update to set properties (create only registers the name)
240
+ try {
204
241
  await client
205
242
  .getServiceBinding()
206
243
  .update((0, asConfig_1.asConfig)(config));
207
244
  }
245
+ catch (updateError) {
246
+ const msg = updateError instanceof Error
247
+ ? updateError.message
248
+ : String(updateError);
249
+ if (mode === 'update' && msg.includes('404')) {
250
+ // Object missing despite verify — fallback to create + update
251
+ await client
252
+ .getServiceBinding()
253
+ .create((0, asConfig_1.asConfig)(config), options);
254
+ await client
255
+ .getServiceBinding()
256
+ .update((0, asConfig_1.asConfig)(config));
257
+ }
258
+ else {
259
+ throw updateError;
260
+ }
261
+ }
208
262
  return;
209
263
  }
210
264
  case 'metadataExtension': {
@@ -223,9 +277,19 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
223
277
  }
224
278
  case 'behaviorDefinition': {
225
279
  if (mode !== 'update') {
280
+ // Fill rootEntity/implementationType from source if missing in config
281
+ let bdefConfig = config;
282
+ if (payload && (!config.rootEntity || !config.implementationType)) {
283
+ const parsed = (0, parseBdefSource_1.parseBdefSource)(payload);
284
+ bdefConfig = {
285
+ ...config,
286
+ rootEntity: config.rootEntity || parsed.rootEntity,
287
+ implementationType: config.implementationType || parsed.implementationType,
288
+ };
289
+ }
226
290
  await client
227
291
  .getBehaviorDefinition()
228
- .create((0, asConfig_1.asConfig)(config), options);
292
+ .create((0, asConfig_1.asConfig)(bdefConfig), options);
229
293
  }
230
294
  if (payload) {
231
295
  await client.getBehaviorDefinition().update((0, asConfig_1.asConfig)({
@@ -263,28 +327,43 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
263
327
  }
264
328
  return;
265
329
  }
266
- case 'tableType': {
330
+ case 'accessControl': {
267
331
  if (mode !== 'update') {
268
332
  await client
269
- .getTableType()
333
+ .getAccessControl()
270
334
  .create((0, asConfig_1.asConfig)(config), options);
271
335
  }
272
- if (mode !== 'create') {
336
+ if (payload) {
337
+ await client.getAccessControl().update((0, asConfig_1.asConfig)({
338
+ ...config,
339
+ sourceCode: payload,
340
+ }), options);
341
+ }
342
+ return;
343
+ }
344
+ case 'tableType': {
345
+ if (mode !== 'update') {
273
346
  await client
274
347
  .getTableType()
275
- .update((0, asConfig_1.asConfig)(config), options);
348
+ .create((0, asConfig_1.asConfig)(config), options);
276
349
  }
350
+ // Always update to set properties (create only registers the name)
351
+ await client
352
+ .getTableType()
353
+ .update((0, asConfig_1.asConfig)(config), options);
277
354
  return;
278
355
  }
279
356
  }
280
357
  }
281
358
  catch (error) {
282
- const err = error;
283
- if (err.response?.data) {
284
- console.error(`Error restoring ${node.type}:${node.name}:`, typeof err.response.data === 'string'
285
- ? err.response.data
286
- : JSON.stringify(err.response.data, null, 2));
359
+ const data = error.response?.data;
360
+ if (data) {
361
+ const errorMsg = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
362
+ console.error(`Error restoring ${node.type}:${node.name}:\n${errorMsg}`);
287
363
  }
288
364
  throw error;
289
365
  }
290
366
  }
367
+ function delay(ms) {
368
+ return new Promise((resolve) => setTimeout(resolve, ms));
369
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAqDA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA4wBzC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAiDA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAsoBzC"}