@mcp-abap-adt/adt-clients 7.2.1 → 7.3.1

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 (46) hide show
  1. package/dist/clients/AdtClient.d.ts +12 -0
  2. package/dist/clients/AdtClient.d.ts.map +1 -1
  3. package/dist/clients/AdtClient.js +16 -0
  4. package/dist/constants/contentTypes.d.ts +1 -0
  5. package/dist/constants/contentTypes.d.ts.map +1 -1
  6. package/dist/constants/contentTypes.js +3 -1
  7. package/dist/core/messageClass/AdtMessageClass.d.ts +81 -0
  8. package/dist/core/messageClass/AdtMessageClass.d.ts.map +1 -0
  9. package/dist/core/messageClass/AdtMessageClass.js +245 -0
  10. package/dist/core/messageClass/AdtMessageClassMessage.d.ts +77 -0
  11. package/dist/core/messageClass/AdtMessageClassMessage.d.ts.map +1 -0
  12. package/dist/core/messageClass/AdtMessageClassMessage.js +321 -0
  13. package/dist/core/messageClass/create.d.ts +13 -0
  14. package/dist/core/messageClass/create.d.ts.map +1 -0
  15. package/dist/core/messageClass/create.js +40 -0
  16. package/dist/core/messageClass/delete.d.ts +25 -0
  17. package/dist/core/messageClass/delete.d.ts.map +1 -0
  18. package/dist/core/messageClass/delete.js +71 -0
  19. package/dist/core/messageClass/index.d.ts +13 -0
  20. package/dist/core/messageClass/index.d.ts.map +1 -0
  21. package/dist/core/messageClass/index.js +28 -0
  22. package/dist/core/messageClass/lock.d.ts +26 -0
  23. package/dist/core/messageClass/lock.d.ts.map +1 -0
  24. package/dist/core/messageClass/lock.js +82 -0
  25. package/dist/core/messageClass/read.d.ts +10 -0
  26. package/dist/core/messageClass/read.d.ts.map +1 -0
  27. package/dist/core/messageClass/read.js +24 -0
  28. package/dist/core/messageClass/types.d.ts +53 -0
  29. package/dist/core/messageClass/types.d.ts.map +1 -0
  30. package/dist/core/messageClass/types.js +5 -0
  31. package/dist/core/messageClass/unlock.d.ts +16 -0
  32. package/dist/core/messageClass/unlock.d.ts.map +1 -0
  33. package/dist/core/messageClass/unlock.js +39 -0
  34. package/dist/core/messageClass/update.d.ts +16 -0
  35. package/dist/core/messageClass/update.d.ts.map +1 -0
  36. package/dist/core/messageClass/update.js +47 -0
  37. package/dist/core/messageClass/xml.d.ts +24 -0
  38. package/dist/core/messageClass/xml.d.ts.map +1 -0
  39. package/dist/core/messageClass/xml.js +107 -0
  40. package/dist/core/shared/unsupported.d.ts +3 -0
  41. package/dist/core/shared/unsupported.d.ts.map +1 -0
  42. package/dist/core/shared/unsupported.js +10 -0
  43. package/dist/index.core.d.ts +2 -0
  44. package/dist/index.core.d.ts.map +1 -1
  45. package/dist/index.core.js +4 -1
  46. package/package.json +2 -2
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+ /**
3
+ * AdtMessageClassMessage — read-modify-write operations for a single message
4
+ * within a Message Class (MSAG/N).
5
+ *
6
+ * Implements IAdtObject<IMessageClassMessageConfig, IMessageClassMessageState>.
7
+ *
8
+ * Operation chains:
9
+ * - read: GET class XML → find message by msgno → return state.message
10
+ * - create/update: GET class → merge message → stateful → lockMessage (MH) +
11
+ * lockClassForMessage (CH) → PUT full class XML (message with
12
+ * mc:lockhandle=MH, lockHandle=CH) → unlockAllMessages →
13
+ * unlock class (CH) → stateless
14
+ * - delete: GET class → stateful → lockMessage (MH) + lockClassForMessage (CH)
15
+ * → PUT class XML with target message as <mc:deletedmessages
16
+ * mc:lockhandle=MH>, all other messages as <mc:messages> →
17
+ * unlockAllMessages → unlock class (CH) → stateless.
18
+ * (SAP does NOT delete omitted messages on PUT — <mc:deletedmessages>
19
+ * is the correct mechanism. A message-level DELETE /messages/{no}
20
+ * returns 423 and is NOT used.)
21
+ *
22
+ * Unsupported: activate, check, validate, lock, unlock, getVersions,
23
+ * getVersionSource, readTransport → throwUnsupportedOperation.
24
+ *
25
+ * transport: when config.transportRequest is set (transportable package), it is
26
+ * appended as &corrNr= on the class PUT, like the other CRUD object types.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.AdtMessageClassMessage = void 0;
30
+ const interfaces_1 = require("@mcp-abap-adt/interfaces");
31
+ const contentTypes_1 = require("../../constants/contentTypes");
32
+ const internalUtils_1 = require("../../utils/internalUtils");
33
+ const timeouts_1 = require("../../utils/timeouts");
34
+ const unsupported_1 = require("../shared/unsupported");
35
+ const lock_1 = require("./lock");
36
+ const read_1 = require("./read");
37
+ const unlock_1 = require("./unlock");
38
+ const xml_1 = require("./xml");
39
+ const BASE = '/sap/bc/adt/messageclass';
40
+ class AdtMessageClassMessage {
41
+ connection;
42
+ logger;
43
+ objectType = 'MessageClassMessage';
44
+ constructor(connection, logger) {
45
+ this.connection = connection;
46
+ this.logger = logger;
47
+ }
48
+ // ── read ──────────────────────────────────────────────────────────────────
49
+ /**
50
+ * Read a single message from the parent class.
51
+ * Returns undefined when the parent class itself is absent (404).
52
+ * Throws OBJECT_NOT_FOUND when the class exists but the message number is absent.
53
+ */
54
+ async read(config) {
55
+ if (!config.className)
56
+ throw new Error('className is required');
57
+ if (!config.msgno)
58
+ throw new Error('msgno is required');
59
+ const no = String(config.msgno);
60
+ try {
61
+ const response = await (0, read_1.getMessageClassSource)(this.connection, config.className);
62
+ const cls = (0, xml_1.parseMessageClass)(String(response.data));
63
+ const message = cls.messages.find((m) => m.msgno === no);
64
+ if (!message) {
65
+ const e = new interfaces_1.AdtOperationError(`Message ${no} not found in class ${config.className}`);
66
+ e.code = interfaces_1.AdtObjectErrorCodes.OBJECT_NOT_FOUND;
67
+ throw e;
68
+ }
69
+ return { message, errors: [] };
70
+ }
71
+ catch (error) {
72
+ const e = error;
73
+ if (e.response?.status === 404) {
74
+ return undefined;
75
+ }
76
+ throw error;
77
+ }
78
+ }
79
+ // ── create / update (upsert) ───────────────────────────────────────────────
80
+ /**
81
+ * Create or upsert a single message in the parent class.
82
+ * Delegates to the update logic.
83
+ */
84
+ async create(config, _options) {
85
+ return this._upsertMessage(config);
86
+ }
87
+ /**
88
+ * Update (upsert) a single message in the parent class.
89
+ * Full chain: GET class → merge message → stateful → LOCK_MSG + class LOCK →
90
+ * PUT class XML → unlock class → unlockAllMessages → stateless.
91
+ */
92
+ async update(config, _options) {
93
+ return this._upsertMessage(config);
94
+ }
95
+ async _upsertMessage(config) {
96
+ if (!config.className)
97
+ throw new Error('className is required');
98
+ if (!config.msgno)
99
+ throw new Error('msgno is required');
100
+ const name = config.className;
101
+ const no = String(config.msgno);
102
+ // 1. Read current class state to preserve all messages
103
+ const response = await (0, read_1.getMessageClassSource)(this.connection, name);
104
+ const cls = (0, xml_1.parseMessageClass)(String(response.data));
105
+ // 2. Merge/set the message in the messages array
106
+ const existingIdx = cls.messages.findIndex((m) => m.msgno === no);
107
+ if (existingIdx >= 0) {
108
+ // Update existing message — only override fields when explicitly provided in config
109
+ cls.messages[existingIdx] = {
110
+ ...cls.messages[existingIdx],
111
+ ...(config.msgtext !== undefined ? { msgtext: config.msgtext } : {}),
112
+ ...(config.selfExplanatory !== undefined
113
+ ? { selfExplanatory: config.selfExplanatory }
114
+ : {}),
115
+ ...(config.description !== undefined
116
+ ? { description: config.description }
117
+ : {}),
118
+ };
119
+ }
120
+ else {
121
+ // Add new message with all authorable fields
122
+ cls.messages.push({
123
+ msgno: no,
124
+ msgtext: config.msgtext ?? '',
125
+ ...(config.selfExplanatory !== undefined
126
+ ? { selfExplanatory: config.selfExplanatory }
127
+ : {}),
128
+ ...(config.description !== undefined
129
+ ? { description: config.description }
130
+ : {}),
131
+ });
132
+ }
133
+ let messageLockHandle;
134
+ let classLockHandle;
135
+ try {
136
+ this.logger?.info?.('upsertMessage: stateful');
137
+ this.connection.setSessionType('stateful');
138
+ // 3. Lock individual message
139
+ this.logger?.info?.('upsertMessage: lockMessage');
140
+ messageLockHandle = await (0, lock_1.lockMessage)(this.connection, name, no);
141
+ // 4. Lock class for message save
142
+ this.logger?.info?.('upsertMessage: lockClassForMessage');
143
+ classLockHandle = await (0, lock_1.lockClassForMessage)(this.connection, name, no);
144
+ // 5. PUT full class XML with message lock handle embedded
145
+ this.logger?.info?.('upsertMessage: PUT');
146
+ const xmlBody = (0, xml_1.buildMessageClassXml)(cls, {
147
+ messageLockHandles: { [no]: messageLockHandle },
148
+ });
149
+ const encoded = (0, internalUtils_1.encodeSapObjectName)(name.toLowerCase());
150
+ const corrNr = config.transportRequest?.trim()
151
+ ? `&corrNr=${encodeURIComponent(config.transportRequest)}`
152
+ : '';
153
+ const updateResult = await this.connection.makeAdtRequest({
154
+ url: `${BASE}/${encoded}?lockHandle=${encodeURIComponent(classLockHandle)}${corrNr}`,
155
+ method: 'PUT',
156
+ timeout: (0, timeouts_1.getTimeout)('default'),
157
+ data: xmlBody,
158
+ headers: { 'Content-Type': contentTypes_1.MESSAGE_CLASS_UPDATE_CONTENT_TYPE },
159
+ });
160
+ // 6. Release the message lock first, then unlock the whole class last —
161
+ // the class edit-lock must be the final release of the process.
162
+ this.logger?.info?.('upsertMessage: unlockAllMessages');
163
+ await (0, unlock_1.unlockAllMessages)(this.connection, name, no);
164
+ messageLockHandle = undefined;
165
+ // 7. Unlock the whole class (final release)
166
+ this.logger?.info?.('upsertMessage: unlock class');
167
+ await (0, unlock_1.unlockMessageClass)(this.connection, name, classLockHandle);
168
+ classLockHandle = undefined;
169
+ // 8. Back to stateless
170
+ this.connection.setSessionType('stateless');
171
+ this.logger?.info?.('upsertMessage: done');
172
+ return { updateResult, errors: [] };
173
+ }
174
+ catch (error) {
175
+ // Always clean up locks and reset session on failure — release the
176
+ // message lock first, then the class (final release), mirroring the happy path.
177
+ if (messageLockHandle) {
178
+ try {
179
+ await (0, unlock_1.unlockAllMessages)(this.connection, name, no);
180
+ }
181
+ catch (ue) {
182
+ this.logger?.warn?.('Failed to unlock messages during cleanup:', (0, internalUtils_1.safeErrorMessage)(ue));
183
+ }
184
+ }
185
+ if (classLockHandle) {
186
+ try {
187
+ await (0, unlock_1.unlockMessageClass)(this.connection, name, classLockHandle);
188
+ }
189
+ catch (ue) {
190
+ this.logger?.warn?.('Failed to unlock class during cleanup:', (0, internalUtils_1.safeErrorMessage)(ue));
191
+ }
192
+ }
193
+ this.connection.setSessionType('stateless');
194
+ this.logger?.error('upsertMessage failed:', (0, internalUtils_1.safeErrorMessage)(error));
195
+ throw error;
196
+ }
197
+ }
198
+ // ── delete ────────────────────────────────────────────────────────────────
199
+ /**
200
+ * Delete a single message from the parent class.
201
+ *
202
+ * SAP does NOT remove messages that are merely omitted from a class PUT — it
203
+ * only upserts what is present. The correct mechanism is to PUT the class
204
+ * with the target message placed in <mc:deletedmessages> (carrying its own
205
+ * message lock handle), while every other message remains in <mc:messages>.
206
+ *
207
+ * Chain: GET class → stateful → lockMessage (MH) + lockClassForMessage (CH)
208
+ * → PUT class XML with target in <mc:deletedmessages mc:lockhandle=MH>,
209
+ * remaining messages in <mc:messages> → unlockAllMessages →
210
+ * unlock class (CH) → stateless.
211
+ */
212
+ async delete(config) {
213
+ if (!config.className)
214
+ throw new Error('className is required');
215
+ if (!config.msgno)
216
+ throw new Error('msgno is required');
217
+ const name = config.className;
218
+ const no = String(config.msgno);
219
+ // 1. Read current class state — keep ALL messages (including the one being
220
+ // deleted) so the builder can emit <mc:deletedmessages> for the target
221
+ const response = await (0, read_1.getMessageClassSource)(this.connection, name);
222
+ const cls = (0, xml_1.parseMessageClass)(String(response.data));
223
+ let messageLockHandle;
224
+ let classLockHandle;
225
+ try {
226
+ this.logger?.info?.('deleteMessage: stateful');
227
+ this.connection.setSessionType('stateful');
228
+ // 2. Lock the individual message (required for <mc:deletedmessages>)
229
+ this.logger?.info?.('deleteMessage: lockMessage');
230
+ messageLockHandle = await (0, lock_1.lockMessage)(this.connection, name, no);
231
+ // 3. Lock the class for a message-save (msgNo + onSave=X)
232
+ this.logger?.info?.('deleteMessage: lockClassForMessage');
233
+ classLockHandle = await (0, lock_1.lockClassForMessage)(this.connection, name, no);
234
+ // 4. PUT: target message → <mc:deletedmessages>; all others → <mc:messages>
235
+ this.logger?.info?.('deleteMessage: PUT');
236
+ const xmlBody = (0, xml_1.buildMessageClassXml)(cls, {
237
+ deletedMsgnos: [no],
238
+ messageLockHandles: { [no]: messageLockHandle },
239
+ });
240
+ const encoded = (0, internalUtils_1.encodeSapObjectName)(name.toLowerCase());
241
+ const corrNr = config.transportRequest?.trim()
242
+ ? `&corrNr=${encodeURIComponent(config.transportRequest)}`
243
+ : '';
244
+ const deleteResult = await this.connection.makeAdtRequest({
245
+ url: `${BASE}/${encoded}?lockHandle=${encodeURIComponent(classLockHandle)}${corrNr}`,
246
+ method: 'PUT',
247
+ timeout: (0, timeouts_1.getTimeout)('default'),
248
+ data: xmlBody,
249
+ headers: { 'Content-Type': contentTypes_1.MESSAGE_CLASS_UPDATE_CONTENT_TYPE },
250
+ });
251
+ // 5. Release the message lock first, then unlock the whole class last.
252
+ this.logger?.info?.('deleteMessage: unlockAllMessages');
253
+ await (0, unlock_1.unlockAllMessages)(this.connection, name, no);
254
+ messageLockHandle = undefined;
255
+ // 6. Unlock the whole class (final release)
256
+ this.logger?.info?.('deleteMessage: unlock class');
257
+ await (0, unlock_1.unlockMessageClass)(this.connection, name, classLockHandle);
258
+ classLockHandle = undefined;
259
+ this.connection.setSessionType('stateless');
260
+ this.logger?.info?.('deleteMessage: done');
261
+ return { deleteResult, errors: [] };
262
+ }
263
+ catch (error) {
264
+ // Release the message lock first, then the class (final release).
265
+ if (messageLockHandle) {
266
+ try {
267
+ await (0, unlock_1.unlockAllMessages)(this.connection, name, no);
268
+ }
269
+ catch (ue) {
270
+ this.logger?.warn?.('Failed to unlock messages during cleanup:', (0, internalUtils_1.safeErrorMessage)(ue));
271
+ }
272
+ }
273
+ if (classLockHandle) {
274
+ try {
275
+ await (0, unlock_1.unlockMessageClass)(this.connection, name, classLockHandle);
276
+ }
277
+ catch (ue) {
278
+ this.logger?.warn?.('Failed to unlock class during cleanup:', (0, internalUtils_1.safeErrorMessage)(ue));
279
+ }
280
+ }
281
+ this.connection.setSessionType('stateless');
282
+ this.logger?.error('deleteMessage failed:', (0, internalUtils_1.safeErrorMessage)(error));
283
+ throw error;
284
+ }
285
+ }
286
+ // ── readMetadata ───────────────────────────────────────────────────────────
287
+ /** Delegates to read() — individual messages have no separate metadata endpoint. */
288
+ async readMetadata(config) {
289
+ const state = await this.read(config);
290
+ if (!state) {
291
+ throw new Error(`Message ${config.msgno} not found in class ${config.className}`);
292
+ }
293
+ return state;
294
+ }
295
+ // ── unsupported operations ─────────────────────────────────────────────────
296
+ async validate(_config) {
297
+ (0, unsupported_1.throwUnsupportedOperation)('validate', 'message class message');
298
+ }
299
+ async activate(_config) {
300
+ (0, unsupported_1.throwUnsupportedOperation)('activate', 'message class message');
301
+ }
302
+ async check(_config) {
303
+ (0, unsupported_1.throwUnsupportedOperation)('check', 'message class message');
304
+ }
305
+ async readTransport(_config) {
306
+ (0, unsupported_1.throwUnsupportedOperation)('readTransport', 'message class message');
307
+ }
308
+ async lock(_config) {
309
+ (0, unsupported_1.throwUnsupportedOperation)('lock', 'message class message');
310
+ }
311
+ async unlock(_config, _lockHandle) {
312
+ (0, unsupported_1.throwUnsupportedOperation)('unlock', 'message class message');
313
+ }
314
+ async getVersions(_config) {
315
+ (0, unsupported_1.throwUnsupportedOperation)('getVersions', 'message class message');
316
+ }
317
+ async getVersionSource(_contentUri) {
318
+ (0, unsupported_1.throwUnsupportedOperation)('getVersionSource', 'message class message');
319
+ }
320
+ }
321
+ exports.AdtMessageClassMessage = AdtMessageClassMessage;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Message class create operations
3
+ */
4
+ import type { IAbapConnection, IAdtResponse } from '@mcp-abap-adt/interfaces';
5
+ import type { ICreateMessageClassParams } from './types';
6
+ /**
7
+ * Create a new message class (shell — no messages yet).
8
+ * POST /sap/bc/adt/messageclass[?corrNr={transport}] with Content-Type application/xml.
9
+ * For a transportable package pass `transport_request` (added as `?corrNr=`), like
10
+ * domain/class create; local packages send no corrNr.
11
+ */
12
+ export declare function createMessageClass(connection: IAbapConnection, params: ICreateMessageClassParams): Promise<IAdtResponse>;
13
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/core/messageClass/create.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE9E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAKzD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,YAAY,CAAC,CA0BvB"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Message class create operations
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createMessageClass = createMessageClass;
7
+ const timeouts_1 = require("../../utils/timeouts");
8
+ const xml_1 = require("./xml");
9
+ const BASE = '/sap/bc/adt/messageclass';
10
+ /**
11
+ * Create a new message class (shell — no messages yet).
12
+ * POST /sap/bc/adt/messageclass[?corrNr={transport}] with Content-Type application/xml.
13
+ * For a transportable package pass `transport_request` (added as `?corrNr=`), like
14
+ * domain/class create; local packages send no corrNr.
15
+ */
16
+ async function createMessageClass(connection, params) {
17
+ // Emit BOTH adtcore:language and adtcore:masterLanguage (like domain/class),
18
+ // both set to the resolved language.
19
+ const lang = params.master_language ?? 'EN';
20
+ const xmlBody = (0, xml_1.buildMessageClassXml)({
21
+ name: params.name.toUpperCase(),
22
+ description: params.description,
23
+ packageName: params.package_name.toUpperCase(),
24
+ language: lang,
25
+ masterLanguage: lang,
26
+ messages: [],
27
+ });
28
+ const corrNrParam = params.transport_request?.trim()
29
+ ? `?corrNr=${encodeURIComponent(params.transport_request)}`
30
+ : '';
31
+ return connection.makeAdtRequest({
32
+ url: `${BASE}${corrNrParam}`,
33
+ method: 'POST',
34
+ timeout: (0, timeouts_1.getTimeout)('default'),
35
+ data: xmlBody,
36
+ headers: {
37
+ 'Content-Type': 'application/xml',
38
+ },
39
+ });
40
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Message class delete operations.
3
+ *
4
+ * Uses the stateless ADT deletion service (`/sap/bc/adt/deletion/check` +
5
+ * `/sap/bc/adt/deletion/delete`) — the same mechanism Eclipse ADT and the other
6
+ * object types (domain, serviceDefinition, …) use. A direct
7
+ * `DELETE /messageclass/{name}?lockHandle=` leaves a lingering message-editing
8
+ * enqueue ("User is currently editing …") that blocks a same-name re-create, so
9
+ * it is NOT used here.
10
+ */
11
+ import type { IAbapConnection, IAdtResponse } from '@mcp-abap-adt/interfaces';
12
+ /**
13
+ * Low-level: check whether the message class can be deleted.
14
+ * POST /sap/bc/adt/deletion/check
15
+ */
16
+ export declare function checkDeletion(connection: IAbapConnection, name: string): Promise<IAdtResponse>;
17
+ /**
18
+ * Low-level: delete the message class via the deletion service.
19
+ * POST /sap/bc/adt/deletion/delete (stateless — no lock handle).
20
+ *
21
+ * For a transportable package pass `transportRequest` (emitted as
22
+ * `<del:transportNumber>`), like domain; local packages send an empty tag.
23
+ */
24
+ export declare function deleteMessageClass(connection: IAbapConnection, name: string, transportRequest?: string): Promise<IAdtResponse>;
25
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/core/messageClass/delete.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAe9E;;;GAGG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,EACZ,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,YAAY,CAAC,CAwBvB"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Message class delete operations.
4
+ *
5
+ * Uses the stateless ADT deletion service (`/sap/bc/adt/deletion/check` +
6
+ * `/sap/bc/adt/deletion/delete`) — the same mechanism Eclipse ADT and the other
7
+ * object types (domain, serviceDefinition, …) use. A direct
8
+ * `DELETE /messageclass/{name}?lockHandle=` leaves a lingering message-editing
9
+ * enqueue ("User is currently editing …") that blocks a same-name re-create, so
10
+ * it is NOT used here.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.checkDeletion = checkDeletion;
14
+ exports.deleteMessageClass = deleteMessageClass;
15
+ const contentTypes_1 = require("../../constants/contentTypes");
16
+ const internalUtils_1 = require("../../utils/internalUtils");
17
+ const timeouts_1 = require("../../utils/timeouts");
18
+ const BASE = '/sap/bc/adt/messageclass';
19
+ const objectUri = (name) => `${BASE}/${(0, internalUtils_1.encodeSapObjectName)(name.toLowerCase())}`;
20
+ /**
21
+ * Low-level: check whether the message class can be deleted.
22
+ * POST /sap/bc/adt/deletion/check
23
+ */
24
+ async function checkDeletion(connection, name) {
25
+ if (!name)
26
+ throw new Error('name is required');
27
+ const xmlPayload = `<?xml version="1.0" encoding="UTF-8"?>
28
+ <del:checkRequest xmlns:del="http://www.sap.com/adt/deletion" xmlns:adtcore="http://www.sap.com/adt/core">
29
+ <del:object adtcore:uri="${objectUri(name)}"/>
30
+ </del:checkRequest>`;
31
+ return connection.makeAdtRequest({
32
+ url: '/sap/bc/adt/deletion/check',
33
+ method: 'POST',
34
+ timeout: (0, timeouts_1.getTimeout)('default'),
35
+ data: xmlPayload,
36
+ headers: {
37
+ Accept: contentTypes_1.ACCEPT_DELETION_CHECK,
38
+ 'Content-Type': contentTypes_1.CT_DELETION_CHECK,
39
+ },
40
+ });
41
+ }
42
+ /**
43
+ * Low-level: delete the message class via the deletion service.
44
+ * POST /sap/bc/adt/deletion/delete (stateless — no lock handle).
45
+ *
46
+ * For a transportable package pass `transportRequest` (emitted as
47
+ * `<del:transportNumber>`), like domain; local packages send an empty tag.
48
+ */
49
+ async function deleteMessageClass(connection, name, transportRequest) {
50
+ if (!name)
51
+ throw new Error('name is required');
52
+ const transportNumberTag = transportRequest?.trim()
53
+ ? `<del:transportNumber>${transportRequest}</del:transportNumber>`
54
+ : '<del:transportNumber/>';
55
+ const xmlPayload = `<?xml version="1.0" encoding="UTF-8"?>
56
+ <del:deletionRequest xmlns:del="http://www.sap.com/adt/deletion" xmlns:adtcore="http://www.sap.com/adt/core">
57
+ <del:object adtcore:uri="${objectUri(name)}">
58
+ ${transportNumberTag}
59
+ </del:object>
60
+ </del:deletionRequest>`;
61
+ return connection.makeAdtRequest({
62
+ url: '/sap/bc/adt/deletion/delete',
63
+ method: 'POST',
64
+ timeout: (0, timeouts_1.getTimeout)('default'),
65
+ data: xmlPayload,
66
+ headers: {
67
+ Accept: contentTypes_1.ACCEPT_DELETION,
68
+ 'Content-Type': contentTypes_1.CT_DELETION,
69
+ },
70
+ });
71
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Message class operations - public exports
3
+ */
4
+ import type { IAdtObject } from '@mcp-abap-adt/interfaces';
5
+ import type { IMessageClassConfig, IMessageClassMessageConfig, IMessageClassMessageState, IMessageClassState } from './types';
6
+ export { AdtMessageClass } from './AdtMessageClass';
7
+ export { AdtMessageClassMessage } from './AdtMessageClassMessage';
8
+ export * from './types';
9
+ export type { IParsedMessage, IParsedMessageClass } from './xml';
10
+ export { buildMessageClassXml, parseMessageClass } from './xml';
11
+ export type AdtMessageClassType = IAdtObject<IMessageClassConfig, IMessageClassState>;
12
+ export type AdtMessageClassMessageType = IAdtObject<IMessageClassMessageConfig, IMessageClassMessageState>;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/messageClass/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,cAAc,SAAS,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAGhE,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAC1C,mBAAmB,EACnB,kBAAkB,CACnB,CAAC;AAGF,MAAM,MAAM,0BAA0B,GAAG,UAAU,CACjD,0BAA0B,EAC1B,yBAAyB,CAC1B,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Message class operations - public exports
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.parseMessageClass = exports.buildMessageClassXml = exports.AdtMessageClassMessage = exports.AdtMessageClass = void 0;
21
+ var AdtMessageClass_1 = require("./AdtMessageClass");
22
+ Object.defineProperty(exports, "AdtMessageClass", { enumerable: true, get: function () { return AdtMessageClass_1.AdtMessageClass; } });
23
+ var AdtMessageClassMessage_1 = require("./AdtMessageClassMessage");
24
+ Object.defineProperty(exports, "AdtMessageClassMessage", { enumerable: true, get: function () { return AdtMessageClassMessage_1.AdtMessageClassMessage; } });
25
+ __exportStar(require("./types"), exports);
26
+ var xml_1 = require("./xml");
27
+ Object.defineProperty(exports, "buildMessageClassXml", { enumerable: true, get: function () { return xml_1.buildMessageClassXml; } });
28
+ Object.defineProperty(exports, "parseMessageClass", { enumerable: true, get: function () { return xml_1.parseMessageClass; } });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Message class lock operations
3
+ */
4
+ import type { IAbapConnection } from '@mcp-abap-adt/interfaces';
5
+ /**
6
+ * Lock a message class for modification.
7
+ * Returns the lock handle that must be used in subsequent update/delete requests.
8
+ *
9
+ * NOTE: Caller must enable stateful session via connection.setSessionType('stateful') first.
10
+ */
11
+ export declare function lockMessageClass(connection: IAbapConnection, name: string): Promise<string>;
12
+ /**
13
+ * Lock an individual message for modification.
14
+ * Returns the message lock handle (MH) used in PUT XML as mc:lockhandle.
15
+ *
16
+ * NOTE: Caller must enable stateful session via connection.setSessionType('stateful') first.
17
+ */
18
+ export declare function lockMessage(connection: IAbapConnection, name: string, no: string): Promise<string>;
19
+ /**
20
+ * Lock a message class in the context of a specific message save.
21
+ * Returns the class lock handle (CH) used in PUT ?lockHandle= parameter.
22
+ *
23
+ * NOTE: Caller must enable stateful session via connection.setSessionType('stateful') first.
24
+ */
25
+ export declare function lockClassForMessage(connection: IAbapConnection, name: string, no: string): Promise<string>;
26
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../../src/core/messageClass/lock.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AA0BhE;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAajB;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,MAAM,CAAC,CAajB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,MAAM,CAAC,CAajB"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * Message class lock operations
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.lockMessageClass = lockMessageClass;
7
+ exports.lockMessage = lockMessage;
8
+ exports.lockClassForMessage = lockClassForMessage;
9
+ const fast_xml_parser_1 = require("fast-xml-parser");
10
+ const contentTypes_1 = require("../../constants/contentTypes");
11
+ const internalUtils_1 = require("../../utils/internalUtils");
12
+ const timeouts_1 = require("../../utils/timeouts");
13
+ const BASE = '/sap/bc/adt/messageclass';
14
+ // Accept header for individual message lock (StatusMessage response type)
15
+ const ACCEPT_LOCK_MSG = 'application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.StatusMessage';
16
+ /** Parse LOCK_HANDLE from the asx:abap lock response XML. Throws with errLabel if absent. */
17
+ function parseLockHandle(data, errLabel) {
18
+ const parser = new fast_xml_parser_1.XMLParser({
19
+ ignoreAttributes: false,
20
+ attributeNamePrefix: '',
21
+ });
22
+ const result = parser.parse(data);
23
+ const lockHandle = result['asx:abap']?.['asx:values']?.DATA?.LOCK_HANDLE;
24
+ if (!lockHandle) {
25
+ throw new Error(`Failed to extract lock handle from ${errLabel}`);
26
+ }
27
+ return lockHandle;
28
+ }
29
+ /**
30
+ * Lock a message class for modification.
31
+ * Returns the lock handle that must be used in subsequent update/delete requests.
32
+ *
33
+ * NOTE: Caller must enable stateful session via connection.setSessionType('stateful') first.
34
+ */
35
+ async function lockMessageClass(connection, name) {
36
+ const encoded = (0, internalUtils_1.encodeSapObjectName)(name.toLowerCase());
37
+ const url = `${BASE}/${encoded}?_action=LOCK&accessMode=MODIFY`;
38
+ const response = await connection.makeAdtRequest({
39
+ url,
40
+ method: 'POST',
41
+ timeout: (0, timeouts_1.getTimeout)('default'),
42
+ data: null,
43
+ headers: { Accept: contentTypes_1.ACCEPT_LOCK },
44
+ });
45
+ return parseLockHandle(response.data, 'message class lock response');
46
+ }
47
+ /**
48
+ * Lock an individual message for modification.
49
+ * Returns the message lock handle (MH) used in PUT XML as mc:lockhandle.
50
+ *
51
+ * NOTE: Caller must enable stateful session via connection.setSessionType('stateful') first.
52
+ */
53
+ async function lockMessage(connection, name, no) {
54
+ const encoded = (0, internalUtils_1.encodeSapObjectName)(name.toLowerCase());
55
+ const url = `${BASE}/${encoded}/messages/${encodeURIComponent(no)}?_action=LOCK_MSG&accessMode=MODIFY`;
56
+ const response = await connection.makeAdtRequest({
57
+ url,
58
+ method: 'POST',
59
+ timeout: (0, timeouts_1.getTimeout)('default'),
60
+ data: null,
61
+ headers: { Accept: ACCEPT_LOCK_MSG },
62
+ });
63
+ return parseLockHandle(response.data, 'message lock response');
64
+ }
65
+ /**
66
+ * Lock a message class in the context of a specific message save.
67
+ * Returns the class lock handle (CH) used in PUT ?lockHandle= parameter.
68
+ *
69
+ * NOTE: Caller must enable stateful session via connection.setSessionType('stateful') first.
70
+ */
71
+ async function lockClassForMessage(connection, name, no) {
72
+ const encoded = (0, internalUtils_1.encodeSapObjectName)(name.toLowerCase());
73
+ const url = `${BASE}/${encoded}?_action=LOCK&accessMode=MODIFY&msgNo=${encodeURIComponent(no)}&onSave=X`;
74
+ const response = await connection.makeAdtRequest({
75
+ url,
76
+ method: 'POST',
77
+ timeout: (0, timeouts_1.getTimeout)('default'),
78
+ data: null,
79
+ headers: { Accept: contentTypes_1.ACCEPT_LOCK },
80
+ });
81
+ return parseLockHandle(response.data, 'class-for-message lock response');
82
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Message class read operations
3
+ */
4
+ import type { IAbapConnection, IAdtResponse } from '@mcp-abap-adt/interfaces';
5
+ /**
6
+ * Read message class metadata and messages.
7
+ * GET /sap/bc/adt/messageclass/{name}
8
+ */
9
+ export declare function getMessageClassSource(connection: IAbapConnection, name: string): Promise<IAdtResponse>;
10
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/messageClass/read.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAU9E;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAQvB"}