@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
package/README.md CHANGED
@@ -36,6 +36,9 @@ Use `--no-activate-on-create` or `--no-activate-on-update` to skip activation fo
36
36
  # Extract / patch a single object payload
37
37
  adt-backup extract --input backup.yaml --object class:ZCL_TEST --out ZCL_TEST.abap
38
38
  adt-backup patch --input backup.yaml --object class:ZCL_TEST --file ZCL_TEST.abap
39
+
40
+ # Single object backup (Service Binding)
41
+ adt-backup backup --objects serviceBinding:Z_UI_SERVICE --output srvb_backup.yaml --destination TRIAL
39
42
  ```
40
43
 
41
44
  ## Help
@@ -59,6 +62,37 @@ Use `-v` for main stages, `-vv` for per-object details, and `-vvv` for ADT/conne
59
62
 
60
63
  See `docs/roadmap.yaml` for per-object backup/restore status and the plan for remaining types.
61
64
 
65
+ ## Supported Object Types
66
+
67
+ | Object Type | Backup | Restore | Payload |
68
+ |---|---|---|---|
69
+ | `package` | implemented | implemented | metadata-xml |
70
+ | `domain` | implemented | implemented | metadata-xml |
71
+ | `dataElement` | implemented | implemented | metadata-xml |
72
+ | `structure` | implemented | implemented | source |
73
+ | `table` | implemented | implemented | source |
74
+ | `tableType` | implemented | implemented | metadata-xml |
75
+ | `view` | implemented | implemented | source |
76
+ | `functionGroup` | implemented | implemented | metadata-xml |
77
+ | `functionModule` | implemented | implemented | source |
78
+ | `interface` | implemented | implemented | source |
79
+ | `class` | implemented | implemented | source |
80
+ | `program` | implemented | implemented | source |
81
+ | `serviceDefinition` | implemented | implemented | source |
82
+ | `serviceBinding` | implemented | implemented | metadata-xml |
83
+ | `metadataExtension` | implemented | implemented | source |
84
+ | `behaviorDefinition` | implemented | implemented | source |
85
+ | `behaviorImplementation` | implemented | implemented | source |
86
+ | `enhancement` | implemented | implemented | source |
87
+ | `unitTest` | implemented | implemented | as class |
88
+ | `cdsUnitTest` | implemented | implemented | as class |
89
+
90
+ > **Note**: Unit tests are stored as classes in backups. When restoring, they are created as test classes in the system.
91
+
92
+ ## Smoke Checklist
93
+
94
+ When your landscape is ready, use `docs/SMOKE_CHECKLIST.md` for a focused backup/restore/verify checklist.
95
+
62
96
  ## Changelog
63
97
 
64
98
  See [CHANGELOG.md](./CHANGELOG.md) for a history of changes.
File without changes
@@ -1,4 +1,4 @@
1
1
  import type { IAuthorizationConfig, ITokenProvider } from '@mcp-abap-adt/interfaces';
2
2
  import type { createLogger } from '../cli/createLogger';
3
- export declare function createTokenProvider(authConfig?: IAuthorizationConfig | null, logger?: ReturnType<typeof createLogger>): ITokenProvider;
3
+ export declare function createTokenProvider(authConfig?: IAuthorizationConfig | null, browserAuthPort?: number, logger?: ReturnType<typeof createLogger>): ITokenProvider;
4
4
  //# sourceMappingURL=createTokenProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createTokenProvider.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/createTokenProvider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACf,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,wBAAgB,mBAAmB,CACjC,UAAU,CAAC,EAAE,oBAAoB,GAAG,IAAI,EACxC,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,GACvC,cAAc,CAkBhB"}
1
+ {"version":3,"file":"createTokenProvider.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/createTokenProvider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACf,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,wBAAgB,mBAAmB,CACjC,UAAU,CAAC,EAAE,oBAAoB,GAAG,IAAI,EACxC,eAAe,CAAC,EAAE,MAAM,EACxB,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,GACvC,cAAc,CAmBhB"}
@@ -4,7 +4,7 @@ exports.createTokenProvider = createTokenProvider;
4
4
  const auth_providers_1 = require("@mcp-abap-adt/auth-providers");
5
5
  const NoopTokenProvider_1 = require("../auth/NoopTokenProvider");
6
6
  const shouldEnableProviderLogger_1 = require("../cli/shouldEnableProviderLogger");
7
- function createTokenProvider(authConfig, logger) {
7
+ function createTokenProvider(authConfig, browserAuthPort, logger) {
8
8
  if (!authConfig ||
9
9
  !authConfig.uaaUrl ||
10
10
  !authConfig.uaaClientId ||
@@ -17,6 +17,7 @@ function createTokenProvider(authConfig, logger) {
17
17
  clientSecret: authConfig.uaaClientSecret,
18
18
  refreshToken: authConfig.refreshToken,
19
19
  browser: 'system',
20
+ redirectPort: browserAuthPort || 10001,
20
21
  logger: (0, shouldEnableProviderLogger_1.shouldEnableProviderLogger)() ? logger : undefined,
21
22
  });
22
23
  }
@@ -5,6 +5,7 @@ export declare function getSapConfigFromBroker(options: {
5
5
  destination?: string;
6
6
  envPath?: string;
7
7
  authRoot?: string;
8
+ browserAuthPort?: number;
8
9
  logger: ReturnType<typeof createLogger>;
9
10
  }): Promise<{
10
11
  config: SapConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"getSapConfigFromBroker.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/getSapConfigFromBroker.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;CACzC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,cAAc,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CA4BnE"}
1
+ {"version":3,"file":"getSapConfigFromBroker.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/getSapConfigFromBroker.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMxD,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;CACzC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,cAAc,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CA0HnE"}
@@ -39,6 +39,7 @@ const os = __importStar(require("node:os"));
39
39
  const path = __importStar(require("node:path"));
40
40
  const auth_broker_1 = require("@mcp-abap-adt/auth-broker");
41
41
  const auth_stores_1 = require("@mcp-abap-adt/auth-stores");
42
+ const logVerbose_1 = require("../cli/logVerbose");
42
43
  const shouldEnableBrokerLogger_1 = require("../cli/shouldEnableBrokerLogger");
43
44
  const shouldEnableStoreLogger_1 = require("../cli/shouldEnableStoreLogger");
44
45
  const createTokenProvider_1 = require("./createTokenProvider");
@@ -46,28 +47,105 @@ async function getSapConfigFromBroker(options) {
46
47
  const { logger } = options;
47
48
  const brokerLogger = (0, shouldEnableBrokerLogger_1.shouldEnableBrokerLogger)() ? logger : undefined;
48
49
  const storeLogger = (0, shouldEnableStoreLogger_1.shouldEnableStoreLogger)() ? logger : undefined;
49
- const destination = options.destination || 'env';
50
- if (options.envPath) {
51
- const sessionStore = new auth_stores_1.EnvFileSessionStore(options.envPath, storeLogger);
52
- return getConfigWithStores({
53
- destination,
54
- sessionStore,
55
- serviceKeyStore: undefined,
56
- logger,
57
- brokerLogger,
58
- });
50
+ // 1. If --env-path is provided, we load it into process.env first
51
+ if (options.envPath && fs.existsSync(options.envPath)) {
52
+ const content = fs.readFileSync(options.envPath, 'utf8');
53
+ const envVars = parseEnvContent(content);
54
+ for (const [key, value] of Object.entries(envVars)) {
55
+ process.env[key] = value;
56
+ }
59
57
  }
58
+ const destination = options.destination || 'env';
60
59
  const roots = resolveAuthRoots(options.authRoot);
61
60
  const { sessionDir, serviceKeyDir } = resolveStoreDirs(roots, destination);
62
- const sessionStore = new auth_stores_1.AbapSessionStore(sessionDir, storeLogger);
61
+ // 2. Initialize stores
62
+ const sessionStore = options.envPath
63
+ ? new auth_stores_1.EnvFileSessionStore(options.envPath, storeLogger)
64
+ : new auth_stores_1.AbapSessionStore(sessionDir, storeLogger);
63
65
  const serviceKeyStore = new auth_stores_1.AbapServiceKeyStore(serviceKeyDir, storeLogger);
64
- return getConfigWithStores({
65
- destination,
66
+ // 3. Get authorization config from store
67
+ const sessionAuthConfig = (await sessionStore.getAuthorizationConfig(destination));
68
+ const serviceKeyAuthConfig = (await serviceKeyStore.getAuthorizationConfig(destination));
69
+ const authConfig = sessionAuthConfig || serviceKeyAuthConfig;
70
+ const broker = new auth_broker_1.AuthBroker({
66
71
  sessionStore,
67
72
  serviceKeyStore,
68
- logger,
69
- brokerLogger,
70
- });
73
+ tokenProvider: (0, createTokenProvider_1.createTokenProvider)(authConfig, options.browserAuthPort, logger),
74
+ }, undefined, brokerLogger);
75
+ // 4. Try to get connection.
76
+ let connection = (await broker.getConnectionConfig(destination));
77
+ // Perform authentication if session is missing but auth config is available
78
+ if (!connection && authConfig && destination !== 'env') {
79
+ (0, logVerbose_1.logVerbose)(1, `Initiating authentication for ${destination}...`);
80
+ await broker.getToken(destination);
81
+ connection = (await broker.getConnectionConfig(destination));
82
+ }
83
+ // Fallback to process.env if not found in stores
84
+ if (!connection &&
85
+ (destination === 'env' || destination === 'SAP' || options.envPath)) {
86
+ const url = process.env.SAP_URL || process.env.SAP_SERVICEURL;
87
+ if (url) {
88
+ connection = {
89
+ serviceUrl: url,
90
+ authorizationToken: process.env.SAP_JWT_TOKEN || process.env.SAP_TOKEN,
91
+ username: process.env.SAP_USERNAME || process.env.SAP_USER,
92
+ password: process.env.SAP_PASSWORD || process.env.SAP_PASS,
93
+ authType: (process.env.SAP_AUTH_TYPE ||
94
+ (process.env.SAP_JWT_TOKEN ? 'jwt' : 'basic')),
95
+ };
96
+ }
97
+ }
98
+ if (!connection) {
99
+ throw new Error(`Missing connection config for destination ${destination}. If using service keys, ensure the JSON file exists in ${serviceKeyDir}`);
100
+ }
101
+ // If we have authConfig but no token in session, try to refresh/get it
102
+ if (!connection.authorizationToken &&
103
+ !connection.username &&
104
+ authConfig &&
105
+ destination !== 'env') {
106
+ await broker.getToken(destination);
107
+ connection = (await broker.getConnectionConfig(destination));
108
+ }
109
+ const authType = connection.authType ||
110
+ (connection.authorizationToken
111
+ ? 'jwt'
112
+ : connection.username && connection.password
113
+ ? 'basic'
114
+ : 'jwt');
115
+ const serviceUrl = connection.serviceUrl;
116
+ if (!serviceUrl) {
117
+ throw new Error(`Missing service URL for destination ${destination}`);
118
+ }
119
+ const config = {
120
+ url: serviceUrl,
121
+ authType: authType,
122
+ };
123
+ if (authType === 'jwt') {
124
+ config.jwtToken = connection.authorizationToken;
125
+ }
126
+ else {
127
+ config.username = connection.username;
128
+ config.password = connection.password;
129
+ }
130
+ const tokenRefresher = authType === 'jwt' ? broker.createTokenRefresher(destination) : undefined;
131
+ return { config, tokenRefresher };
132
+ }
133
+ function parseEnvContent(content) {
134
+ const envVars = {};
135
+ for (const line of content.split(/\r?\n/)) {
136
+ const trimmed = line.trim();
137
+ if (!trimmed || trimmed.startsWith('#'))
138
+ continue;
139
+ const eqIndex = trimmed.indexOf('=');
140
+ if (eqIndex === -1)
141
+ continue;
142
+ const key = trimmed.substring(0, eqIndex).trim();
143
+ let value = trimmed.substring(eqIndex + 1).trim();
144
+ value = value.replace(/^["']+|["']+$/g, '').trim();
145
+ if (key)
146
+ envVars[key] = value;
147
+ }
148
+ return envVars;
71
149
  }
72
150
  function resolveAuthRoots(authRoot) {
73
151
  if (authRoot) {
@@ -89,18 +167,6 @@ function resolveAuthRoots(authRoot) {
89
167
  function resolveStoreDirs(roots, destination) {
90
168
  const candidates = roots.map((root) => {
91
169
  const normalized = path.resolve(root);
92
- if (normalized.endsWith(`${path.sep}sessions`)) {
93
- return {
94
- sessionDir: normalized,
95
- serviceKeyDir: path.join(path.dirname(normalized), 'service-keys'),
96
- };
97
- }
98
- if (normalized.endsWith(`${path.sep}service-keys`)) {
99
- return {
100
- sessionDir: path.join(path.dirname(normalized), 'sessions'),
101
- serviceKeyDir: normalized,
102
- };
103
- }
104
170
  return {
105
171
  sessionDir: path.join(normalized, 'sessions'),
106
172
  serviceKeyDir: path.join(normalized, 'service-keys'),
@@ -115,70 +181,3 @@ function resolveStoreDirs(roots, destination) {
115
181
  }
116
182
  return candidates[0];
117
183
  }
118
- async function getConfigWithStores(options) {
119
- const { destination, sessionStore, serviceKeyStore, logger, brokerLogger } = options;
120
- const sessionAuthConfig = destination === 'env'
121
- ? null
122
- : await sessionStore.getAuthorizationConfig(destination);
123
- const serviceKeyAuthConfig = destination === 'env' || !serviceKeyStore?.getAuthorizationConfig
124
- ? null
125
- : await serviceKeyStore.getAuthorizationConfig(destination);
126
- const authConfig = sessionAuthConfig || serviceKeyAuthConfig;
127
- const broker = new auth_broker_1.AuthBroker({
128
- sessionStore,
129
- serviceKeyStore,
130
- tokenProvider: (0, createTokenProvider_1.createTokenProvider)(authConfig, logger),
131
- }, undefined, brokerLogger);
132
- const session = await sessionStore.loadSession(destination);
133
- let connection = await broker.getConnectionConfig(destination);
134
- if (!connection && authConfig && destination !== 'env') {
135
- await broker.getToken(destination);
136
- connection = await broker.getConnectionConfig(destination);
137
- }
138
- if (!connection) {
139
- throw new Error(`Missing connection config for destination ${destination}`);
140
- }
141
- if (!connection.authorizationToken &&
142
- !connection.username &&
143
- !connection.password &&
144
- authConfig &&
145
- destination !== 'env') {
146
- await broker.getToken(destination);
147
- connection = await broker.getConnectionConfig(destination);
148
- if (!connection) {
149
- throw new Error(`Missing connection config for destination ${destination}`);
150
- }
151
- }
152
- const resolvedAuthType = connection.authorizationToken
153
- ? 'jwt'
154
- : connection.username && connection.password
155
- ? 'basic'
156
- : authConfig && destination !== 'env'
157
- ? 'jwt'
158
- : connection.authType || 'basic';
159
- const serviceUrl = connection.serviceUrl || session?.serviceUrl;
160
- if (!serviceUrl) {
161
- throw new Error(`Missing service URL for destination ${destination}`);
162
- }
163
- const config = {
164
- url: serviceUrl,
165
- authType: resolvedAuthType,
166
- };
167
- if (resolvedAuthType === 'jwt') {
168
- if (!connection.authorizationToken) {
169
- throw new Error(`Missing JWT token for destination ${destination}`);
170
- }
171
- config.jwtToken = connection.authorizationToken;
172
- }
173
- else {
174
- if (!connection.username || !connection.password) {
175
- throw new Error(`Missing username/password for destination ${destination}`);
176
- }
177
- config.username = connection.username;
178
- config.password = connection.password;
179
- }
180
- const tokenRefresher = resolvedAuthType === 'jwt'
181
- ? broker.createTokenRefresher(destination)
182
- : undefined;
183
- return { config, tokenRefresher };
184
- }
@@ -1 +1 @@
1
- {"version":3,"file":"backupObject.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/backupObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAgB,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAavE,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CAuNvB"}
1
+ {"version":3,"file":"backupObject.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/backupObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAgB,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAcvE,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CA6OvB"}
@@ -9,6 +9,7 @@ const extractMetadata_1 = require("../xml/extractMetadata");
9
9
  const parseDataElementConfig_1 = require("../xml/parseDataElementConfig");
10
10
  const parseDomainConfig_1 = require("../xml/parseDomainConfig");
11
11
  const parsePackageConfig_1 = require("../xml/parsePackageConfig");
12
+ const parseServiceBindingConfig_1 = require("../xml/parseServiceBindingConfig");
12
13
  const readBasicMetadata_1 = require("./readBasicMetadata");
13
14
  const readMetadataXmlForType_1 = require("./readMetadataXmlForType");
14
15
  const readSourceText_1 = require("./readSourceText");
@@ -89,7 +90,20 @@ async function backupObject(client, spec) {
89
90
  type: spec.type,
90
91
  name: spec.name,
91
92
  config: (0, applyConfigName_1.applyConfigName)(spec.type, spec.name, undefined, (0, toBackupConfig_1.toBackupConfig)(config)),
92
- source,
93
+ source: source ?? undefined,
94
+ };
95
+ }
96
+ case 'serviceBinding': {
97
+ const metadataXml = await (0, readMetadataXmlForType_1.readMetadataXmlForType)(client, spec.type, spec.name);
98
+ if (!metadataXml) {
99
+ throw new Error(`Service binding not found: ${spec.name}`);
100
+ }
101
+ const config = (0, parseServiceBindingConfig_1.parseServiceBindingConfig)(metadataXml);
102
+ return {
103
+ id,
104
+ type: spec.type,
105
+ name: spec.name,
106
+ config: (0, applyConfigName_1.applyConfigName)(spec.type, spec.name, undefined, (0, toBackupConfig_1.toBackupConfig)(config)),
93
107
  };
94
108
  }
95
109
  case 'metadataExtension':
@@ -106,7 +120,7 @@ async function backupObject(client, spec) {
106
120
  type: spec.type,
107
121
  name: spec.name,
108
122
  config,
109
- source,
123
+ source: source ?? undefined,
110
124
  };
111
125
  }
112
126
  case 'behaviorImplementation':
@@ -126,7 +140,7 @@ async function backupObject(client, spec) {
126
140
  type: spec.type,
127
141
  name: spec.name,
128
142
  config,
129
- source,
143
+ source: source ?? undefined,
130
144
  };
131
145
  }
132
146
  case 'functionModule': {
@@ -144,7 +158,7 @@ async function backupObject(client, spec) {
144
158
  name: spec.name,
145
159
  functionGroupName: spec.functionGroupName,
146
160
  config,
147
- source,
161
+ source: source ?? undefined,
148
162
  };
149
163
  }
150
164
  default: {
@@ -159,7 +173,7 @@ async function backupObject(client, spec) {
159
173
  type: spec.type,
160
174
  name: spec.name,
161
175
  config,
162
- source,
176
+ source: source ?? undefined,
163
177
  };
164
178
  }
165
179
  }
@@ -1,4 +1,4 @@
1
1
  import type { AdtClient } from '@mcp-abap-adt/adt-clients';
2
2
  import type { SupportedType } from '../types';
3
- export declare function readMetadataXmlForType(client: AdtClient, type: SupportedType, name: string, functionGroupName?: string): Promise<string | undefined>;
3
+ export declare function readMetadataXmlForType(client: AdtClient, type: SupportedType, name: string, _functionGroupName?: string): Promise<string | null | undefined>;
4
4
  //# sourceMappingURL=readMetadataXmlForType.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"readMetadataXmlForType.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readMetadataXmlForType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+F7B"}
1
+ {"version":3,"file":"readMetadataXmlForType.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readMetadataXmlForType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAsHpC"}
@@ -2,99 +2,120 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readMetadataXmlForType = readMetadataXmlForType;
4
4
  const responseToText_1 = require("../utils/responseToText");
5
- async function readMetadataXmlForType(client, type, name, functionGroupName) {
6
- switch (type) {
7
- case 'class': {
8
- const state = await client.getClass().readMetadata({ className: name });
9
- return (0, responseToText_1.responseToText)(state.metadataResult);
10
- }
11
- case 'interface': {
12
- const state = await client
13
- .getInterface()
14
- .readMetadata({ interfaceName: name });
15
- return (0, responseToText_1.responseToText)(state.metadataResult);
16
- }
17
- case 'program': {
18
- const state = await client
19
- .getProgram()
20
- .readMetadata({ programName: name });
21
- return (0, responseToText_1.responseToText)(state.metadataResult);
22
- }
23
- case 'structure': {
24
- const state = await client
25
- .getStructure()
26
- .readMetadata({ structureName: name });
27
- return (0, responseToText_1.responseToText)(state.metadataResult);
28
- }
29
- case 'table': {
30
- const state = await client.getTable().readMetadata({ tableName: name });
31
- return (0, responseToText_1.responseToText)(state.metadataResult);
32
- }
33
- case 'tableType': {
34
- const state = await client
35
- .getTableType()
36
- .readMetadata({ tableTypeName: name });
37
- return (0, responseToText_1.responseToText)(state.metadataResult);
38
- }
39
- case 'view': {
40
- const state = await client.getView().readMetadata({ viewName: name });
41
- return (0, responseToText_1.responseToText)(state.metadataResult);
42
- }
43
- case 'domain': {
44
- const state = await client.getDomain().readMetadata({ domainName: name });
45
- return (0, responseToText_1.responseToText)(state.metadataResult);
46
- }
47
- case 'dataElement': {
48
- const state = await client
49
- .getDataElement()
50
- .readMetadata({ dataElementName: name });
51
- return (0, responseToText_1.responseToText)(state.metadataResult);
52
- }
53
- case 'functionGroup': {
54
- const state = await client
55
- .getFunctionGroup()
56
- .readMetadata({ functionGroupName: name });
57
- return (0, responseToText_1.responseToText)(state.metadataResult);
58
- }
59
- case 'functionModule': {
60
- if (!functionGroupName) {
61
- return undefined;
5
+ async function readMetadataXmlForType(client, type, name, _functionGroupName) {
6
+ try {
7
+ switch (type) {
8
+ case 'package': {
9
+ const state = await client
10
+ .getPackage()
11
+ .readMetadata({ packageName: name });
12
+ return (0, responseToText_1.responseToText)(state.metadataResult);
62
13
  }
63
- const state = await client.getFunctionModule().readMetadata({
64
- functionGroupName,
65
- functionModuleName: name,
66
- });
67
- return (0, responseToText_1.responseToText)(state.metadataResult);
68
- }
69
- case 'package': {
70
- const state = await client
71
- .getPackage()
72
- .readMetadata({ packageName: name });
73
- return (0, responseToText_1.responseToText)(state.metadataResult);
74
- }
75
- case 'serviceDefinition': {
76
- const state = await client
77
- .getServiceDefinition()
78
- .readMetadata({ serviceDefinitionName: name });
79
- return (0, responseToText_1.responseToText)(state.metadataResult);
80
- }
81
- case 'metadataExtension': {
82
- const state = await client.getMetadataExtension().readMetadata({ name });
83
- return (0, responseToText_1.responseToText)(state.metadataResult);
84
- }
85
- case 'behaviorDefinition': {
86
- const state = await client
87
- .getBehaviorDefinition()
88
- .read({ name }, 'active');
89
- return (0, responseToText_1.responseToText)(state?.readResult);
90
- }
91
- case 'behaviorImplementation': {
92
- const state = await client
93
- .getBehaviorImplementation()
94
- .readMetadata({ className: name });
95
- return (0, responseToText_1.responseToText)(state.metadataResult);
14
+ case 'class': {
15
+ const state = await client.getClass().readMetadata({ className: name });
16
+ return (0, responseToText_1.responseToText)(state.metadataResult);
17
+ }
18
+ case 'interface': {
19
+ const state = await client
20
+ .getInterface()
21
+ .readMetadata({ interfaceName: name });
22
+ return (0, responseToText_1.responseToText)(state.metadataResult);
23
+ }
24
+ case 'domain': {
25
+ const state = await client
26
+ .getDomain()
27
+ .readMetadata({ domainName: name });
28
+ return (0, responseToText_1.responseToText)(state.metadataResult);
29
+ }
30
+ case 'dataElement': {
31
+ const state = await client
32
+ .getDataElement()
33
+ .readMetadata({ dataElementName: name });
34
+ return (0, responseToText_1.responseToText)(state.metadataResult);
35
+ }
36
+ case 'table': {
37
+ const state = await client.getTable().readMetadata({ tableName: name });
38
+ return (0, responseToText_1.responseToText)(state.metadataResult);
39
+ }
40
+ case 'tableType': {
41
+ const state = await client
42
+ .getTableType()
43
+ .readMetadata({ tableTypeName: name });
44
+ return (0, responseToText_1.responseToText)(state.metadataResult);
45
+ }
46
+ case 'structure': {
47
+ const state = await client
48
+ .getStructure()
49
+ .readMetadata({ structureName: name });
50
+ return (0, responseToText_1.responseToText)(state.metadataResult);
51
+ }
52
+ case 'view': {
53
+ const state = await client.getView().readMetadata({ viewName: name });
54
+ return (0, responseToText_1.responseToText)(state.metadataResult);
55
+ }
56
+ case 'behaviorDefinition': {
57
+ const state = await client
58
+ .getBehaviorDefinition()
59
+ .readMetadata({ name });
60
+ return (0, responseToText_1.responseToText)(state.metadataResult);
61
+ }
62
+ case 'behaviorImplementation': {
63
+ const state = await client
64
+ .getBehaviorImplementation()
65
+ .readMetadata({ className: name });
66
+ return (0, responseToText_1.responseToText)(state.metadataResult);
67
+ }
68
+ case 'serviceDefinition': {
69
+ const state = await client
70
+ .getServiceDefinition()
71
+ .readMetadata({ serviceDefinitionName: name });
72
+ return (0, responseToText_1.responseToText)(state.metadataResult);
73
+ }
74
+ case 'serviceBinding': {
75
+ const state = await client
76
+ .getServiceBinding()
77
+ .readMetadata({ bindingName: name });
78
+ return (0, responseToText_1.responseToText)(state.metadataResult);
79
+ }
80
+ case 'metadataExtension': {
81
+ const state = await client
82
+ .getMetadataExtension()
83
+ .readMetadata({ name });
84
+ return (0, responseToText_1.responseToText)(state.metadataResult);
85
+ }
86
+ case 'functionGroup': {
87
+ const state = await client
88
+ .getFunctionGroup()
89
+ .readMetadata({ functionGroupName: name });
90
+ return (0, responseToText_1.responseToText)(state.metadataResult);
91
+ }
92
+ case 'enhancement': {
93
+ const state = await client
94
+ .getEnhancement()
95
+ .readMetadata({ enhancementName: name, enhancementType: 'enhoxh' });
96
+ return (0, responseToText_1.responseToText)(state.metadataResult);
97
+ }
98
+ case 'accessControl': {
99
+ const state = await client
100
+ .getAccessControl()
101
+ .readMetadata({ accessControlName: name });
102
+ return (0, responseToText_1.responseToText)(state.metadataResult);
103
+ }
104
+ default:
105
+ return undefined;
96
106
  }
97
- default:
98
- return undefined;
107
+ }
108
+ catch (error) {
109
+ const status = error.status || error.response?.status;
110
+ const message = error.message || String(error);
111
+ const isNotFound = status === 404 ||
112
+ status === 410 ||
113
+ /not found/i.test(message) ||
114
+ /does not exist/i.test(message) ||
115
+ /ExceptionResourceNotFound/i.test(message);
116
+ if (isNotFound) {
117
+ return null;
118
+ }
119
+ throw error;
99
120
  }
100
121
  }
@@ -1,4 +1,4 @@
1
1
  import type { AdtClient } from '@mcp-abap-adt/adt-clients';
2
2
  import type { ObjectSpec } from '../types';
3
- export declare function readSourceText(client: AdtClient, spec: ObjectSpec): Promise<string | undefined>;
3
+ export declare function readSourceText(client: AdtClient, spec: ObjectSpec, version?: 'active' | 'inactive'): Promise<string | null | undefined>;
4
4
  //# sourceMappingURL=readSourceText.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"readSourceText.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readSourceText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiG7B"}
1
+ {"version":3,"file":"readSourceText.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readSourceText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,QAAQ,GAAG,UAAqB,GACxC,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAwGpC"}