@mcp-abap-adt/adt-backup 0.1.1 → 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 (83) hide show
  1. package/README.md +34 -0
  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.d.ts.map +1 -1
  10. package/dist/lib/backup/backupObject.js +19 -5
  11. package/dist/lib/backup/readMetadataXmlForType.d.ts +1 -1
  12. package/dist/lib/backup/readMetadataXmlForType.d.ts.map +1 -1
  13. package/dist/lib/backup/readMetadataXmlForType.js +113 -92
  14. package/dist/lib/backup/readSourceText.d.ts +1 -1
  15. package/dist/lib/backup/readSourceText.d.ts.map +1 -1
  16. package/dist/lib/backup/readSourceText.js +96 -87
  17. package/dist/lib/cli/createLogger.d.ts.map +1 -1
  18. package/dist/lib/cli/createLogger.js +18 -0
  19. package/dist/lib/cli/parseArgs.d.ts +1 -1
  20. package/dist/lib/cli/parseArgs.d.ts.map +1 -1
  21. package/dist/lib/cli/parseArgs.js +25 -10
  22. package/dist/lib/cli/usage.d.ts.map +1 -1
  23. package/dist/lib/cli/usage.js +92 -87
  24. package/dist/lib/constants/typeOrder.d.ts.map +1 -1
  25. package/dist/lib/constants/typeOrder.js +1 -0
  26. package/dist/lib/dependencies/collectTreeDependencies.d.ts.map +1 -1
  27. package/dist/lib/dependencies/collectTreeDependencies.js +1 -0
  28. package/dist/lib/restore/analyzeDependencies.d.ts +13 -0
  29. package/dist/lib/restore/analyzeDependencies.d.ts.map +1 -0
  30. package/dist/lib/restore/analyzeDependencies.js +187 -0
  31. package/dist/lib/restore/restoreObject.d.ts.map +1 -1
  32. package/dist/lib/restore/restoreObject.js +13 -0
  33. package/dist/lib/restore/restoreObjects.d.ts.map +1 -1
  34. package/dist/lib/restore/restoreObjects.js +49 -10
  35. package/dist/lib/restore/restoreTreeBackup.d.ts +1 -1
  36. package/dist/lib/restore/restoreTreeBackup.d.ts.map +1 -1
  37. package/dist/lib/restore/restoreTreeBackup.js +192 -42
  38. package/dist/lib/restore/restoreTreeNode.d.ts +1 -1
  39. package/dist/lib/restore/restoreTreeNode.d.ts.map +1 -1
  40. package/dist/lib/restore/restoreTreeNode.js +128 -36
  41. package/dist/lib/run.d.ts.map +1 -1
  42. package/dist/lib/run.js +393 -559
  43. package/dist/lib/tree/buildConfigForNode.d.ts.map +1 -1
  44. package/dist/lib/tree/buildConfigForNode.js +19 -0
  45. package/dist/lib/tree/buildPackageBackupTree.d.ts.map +1 -1
  46. package/dist/lib/tree/buildPackageBackupTree.js +9 -3
  47. package/dist/lib/tree/enrichTreeNode.d.ts.map +1 -1
  48. package/dist/lib/tree/enrichTreeNode.js +17 -1
  49. package/dist/lib/tree/isRestoreImplemented.d.ts.map +1 -1
  50. package/dist/lib/tree/isRestoreImplemented.js +2 -0
  51. package/dist/lib/tree/mapAdtTypeToSupported.d.ts.map +1 -1
  52. package/dist/lib/tree/mapAdtTypeToSupported.js +6 -0
  53. package/dist/lib/tree/readPayloadForType.d.ts.map +1 -1
  54. package/dist/lib/tree/readPayloadForType.js +5 -3
  55. package/dist/lib/types.d.ts +22 -2
  56. package/dist/lib/types.d.ts.map +1 -1
  57. package/dist/lib/utils/applyConfigName.d.ts.map +1 -1
  58. package/dist/lib/utils/applyConfigName.js +6 -0
  59. package/dist/lib/utils/normalizeType.d.ts.map +1 -1
  60. package/dist/lib/utils/normalizeType.js +2 -0
  61. package/dist/lib/utils/parseBdefSource.d.ts +9 -0
  62. package/dist/lib/utils/parseBdefSource.d.ts.map +1 -0
  63. package/dist/lib/utils/parseBdefSource.js +18 -0
  64. package/dist/lib/verify/findOtherType.d.ts.map +1 -1
  65. package/dist/lib/verify/findOtherType.js +1 -0
  66. package/dist/lib/verify/formatVerifyResultsText.d.ts +1 -1
  67. package/dist/lib/verify/formatVerifyResultsText.d.ts.map +1 -1
  68. package/dist/lib/verify/formatVerifyResultsText.js +76 -14
  69. package/dist/lib/verify/types.d.ts +3 -0
  70. package/dist/lib/verify/types.d.ts.map +1 -1
  71. package/dist/lib/verify/verifyBackup.d.ts +4 -2
  72. package/dist/lib/verify/verifyBackup.d.ts.map +1 -1
  73. package/dist/lib/verify/verifyBackup.js +67 -32
  74. package/dist/lib/verify/verifyObjectInSystem.d.ts +1 -1
  75. package/dist/lib/verify/verifyObjectInSystem.d.ts.map +1 -1
  76. package/dist/lib/verify/verifyObjectInSystem.js +39 -105
  77. package/dist/lib/xml/index.d.ts +1 -0
  78. package/dist/lib/xml/index.d.ts.map +1 -1
  79. package/dist/lib/xml/index.js +1 -0
  80. package/dist/lib/xml/parseServiceBindingConfig.d.ts +3 -0
  81. package/dist/lib/xml/parseServiceBindingConfig.d.ts.map +1 -0
  82. package/dist/lib/xml/parseServiceBindingConfig.js +70 -0
  83. package/package.json +12 -12
@@ -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': {
@@ -194,6 +230,37 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
194
230
  }
195
231
  return;
196
232
  }
233
+ case 'serviceBinding': {
234
+ if (mode !== 'update') {
235
+ await client
236
+ .getServiceBinding()
237
+ .create((0, asConfig_1.asConfig)(config), options);
238
+ }
239
+ // Always update to set properties (create only registers the name)
240
+ try {
241
+ await client
242
+ .getServiceBinding()
243
+ .update((0, asConfig_1.asConfig)(config));
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
+ }
262
+ return;
263
+ }
197
264
  case 'metadataExtension': {
198
265
  if (mode !== 'update') {
199
266
  await client
@@ -210,9 +277,19 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
210
277
  }
211
278
  case 'behaviorDefinition': {
212
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
+ }
213
290
  await client
214
291
  .getBehaviorDefinition()
215
- .create((0, asConfig_1.asConfig)(config), options);
292
+ .create((0, asConfig_1.asConfig)(bdefConfig), options);
216
293
  }
217
294
  if (payload) {
218
295
  await client.getBehaviorDefinition().update((0, asConfig_1.asConfig)({
@@ -250,28 +327,43 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
250
327
  }
251
328
  return;
252
329
  }
253
- case 'tableType': {
330
+ case 'accessControl': {
254
331
  if (mode !== 'update') {
255
332
  await client
256
- .getTableType()
333
+ .getAccessControl()
257
334
  .create((0, asConfig_1.asConfig)(config), options);
258
335
  }
259
- 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') {
260
346
  await client
261
347
  .getTableType()
262
- .update((0, asConfig_1.asConfig)(config), options);
348
+ .create((0, asConfig_1.asConfig)(config), options);
263
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);
264
354
  return;
265
355
  }
266
356
  }
267
357
  }
268
358
  catch (error) {
269
- const err = error;
270
- if (err.response?.data) {
271
- console.error(`Error restoring ${node.type}:${node.name}:`, typeof err.response.data === 'string'
272
- ? err.response.data
273
- : 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}`);
274
363
  }
275
364
  throw error;
276
365
  }
277
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"}