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

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 (85) hide show
  1. package/dist/clients/AdtClient.d.ts +32 -0
  2. package/dist/clients/AdtClient.d.ts.map +1 -1
  3. package/dist/clients/AdtClient.js +75 -30
  4. package/dist/core/accessControl/AdtAccessControl.d.ts +3 -1
  5. package/dist/core/accessControl/AdtAccessControl.d.ts.map +1 -1
  6. package/dist/core/accessControl/AdtAccessControl.js +11 -2
  7. package/dist/core/appendStructure/AdtAppendStructure.d.ts +3 -1
  8. package/dist/core/appendStructure/AdtAppendStructure.d.ts.map +1 -1
  9. package/dist/core/appendStructure/AdtAppendStructure.js +11 -2
  10. package/dist/core/authorizationField/AdtAuthorizationField.d.ts +3 -1
  11. package/dist/core/authorizationField/AdtAuthorizationField.d.ts.map +1 -1
  12. package/dist/core/authorizationField/AdtAuthorizationField.js +14 -3
  13. package/dist/core/behaviorDefinition/AdtBehaviorDefinition.d.ts +3 -1
  14. package/dist/core/behaviorDefinition/AdtBehaviorDefinition.d.ts.map +1 -1
  15. package/dist/core/behaviorDefinition/AdtBehaviorDefinition.js +11 -2
  16. package/dist/core/behaviorImplementation/AdtBehaviorImplementation.d.ts +2 -1
  17. package/dist/core/behaviorImplementation/AdtBehaviorImplementation.d.ts.map +1 -1
  18. package/dist/core/behaviorImplementation/AdtBehaviorImplementation.js +6 -3
  19. package/dist/core/class/AdtClass.d.ts +3 -1
  20. package/dist/core/class/AdtClass.d.ts.map +1 -1
  21. package/dist/core/class/AdtClass.js +16 -3
  22. package/dist/core/dataElement/AdtDataElement.d.ts +3 -1
  23. package/dist/core/dataElement/AdtDataElement.d.ts.map +1 -1
  24. package/dist/core/dataElement/AdtDataElement.js +9 -1
  25. package/dist/core/ddl/AdtDdl.d.ts +3 -1
  26. package/dist/core/ddl/AdtDdl.d.ts.map +1 -1
  27. package/dist/core/ddl/AdtDdl.js +11 -2
  28. package/dist/core/domain/AdtDomain.d.ts +3 -1
  29. package/dist/core/domain/AdtDomain.d.ts.map +1 -1
  30. package/dist/core/domain/AdtDomain.js +11 -1
  31. package/dist/core/enhancement/AdtEnhancement.d.ts +12 -1
  32. package/dist/core/enhancement/AdtEnhancement.d.ts.map +1 -1
  33. package/dist/core/enhancement/AdtEnhancement.js +35 -4
  34. package/dist/core/featureToggle/AdtFeatureToggle.d.ts +3 -1
  35. package/dist/core/featureToggle/AdtFeatureToggle.d.ts.map +1 -1
  36. package/dist/core/featureToggle/AdtFeatureToggle.js +14 -2
  37. package/dist/core/functionGroup/AdtFunctionGroup.d.ts +3 -1
  38. package/dist/core/functionGroup/AdtFunctionGroup.d.ts.map +1 -1
  39. package/dist/core/functionGroup/AdtFunctionGroup.js +9 -1
  40. package/dist/core/functionInclude/AdtFunctionInclude.d.ts +9 -1
  41. package/dist/core/functionInclude/AdtFunctionInclude.d.ts.map +1 -1
  42. package/dist/core/functionInclude/AdtFunctionInclude.js +33 -3
  43. package/dist/core/functionModule/AdtFunctionModule.d.ts +9 -1
  44. package/dist/core/functionModule/AdtFunctionModule.d.ts.map +1 -1
  45. package/dist/core/functionModule/AdtFunctionModule.js +27 -2
  46. package/dist/core/interface/AdtInterface.d.ts +3 -1
  47. package/dist/core/interface/AdtInterface.d.ts.map +1 -1
  48. package/dist/core/interface/AdtInterface.js +11 -2
  49. package/dist/core/messageClass/AdtMessageClass.d.ts +3 -1
  50. package/dist/core/messageClass/AdtMessageClass.d.ts.map +1 -1
  51. package/dist/core/messageClass/AdtMessageClass.js +11 -2
  52. package/dist/core/metadataExtension/AdtMetadataExtension.d.ts +3 -1
  53. package/dist/core/metadataExtension/AdtMetadataExtension.d.ts.map +1 -1
  54. package/dist/core/metadataExtension/AdtMetadataExtension.js +9 -1
  55. package/dist/core/package/AdtPackage.d.ts +3 -1
  56. package/dist/core/package/AdtPackage.d.ts.map +1 -1
  57. package/dist/core/package/AdtPackage.js +11 -2
  58. package/dist/core/program/AdtProgram.d.ts +3 -1
  59. package/dist/core/program/AdtProgram.d.ts.map +1 -1
  60. package/dist/core/program/AdtProgram.js +11 -2
  61. package/dist/core/scalarFunction/AdtScalarFunction.d.ts +3 -1
  62. package/dist/core/scalarFunction/AdtScalarFunction.d.ts.map +1 -1
  63. package/dist/core/scalarFunction/AdtScalarFunction.js +11 -2
  64. package/dist/core/scalarFunctionImplementation/AdtScalarFunctionImplementation.d.ts +3 -1
  65. package/dist/core/scalarFunctionImplementation/AdtScalarFunctionImplementation.d.ts.map +1 -1
  66. package/dist/core/scalarFunctionImplementation/AdtScalarFunctionImplementation.js +14 -2
  67. package/dist/core/serviceDefinition/AdtServiceDefinition.d.ts +6 -3
  68. package/dist/core/serviceDefinition/AdtServiceDefinition.d.ts.map +1 -1
  69. package/dist/core/serviceDefinition/AdtServiceDefinition.js +14 -4
  70. package/dist/core/shared/LockRegistry.d.ts +77 -0
  71. package/dist/core/shared/LockRegistry.d.ts.map +1 -0
  72. package/dist/core/shared/LockRegistry.js +91 -0
  73. package/dist/core/structure/AdtStructure.d.ts +3 -1
  74. package/dist/core/structure/AdtStructure.d.ts.map +1 -1
  75. package/dist/core/structure/AdtStructure.js +11 -2
  76. package/dist/core/table/AdtTable.d.ts +3 -1
  77. package/dist/core/table/AdtTable.d.ts.map +1 -1
  78. package/dist/core/table/AdtTable.js +11 -2
  79. package/dist/core/tabletype/AdtDdicTableType.d.ts +3 -1
  80. package/dist/core/tabletype/AdtDdicTableType.d.ts.map +1 -1
  81. package/dist/core/tabletype/AdtDdicTableType.js +9 -1
  82. package/dist/core/transformation/AdtTransformation.d.ts +3 -1
  83. package/dist/core/transformation/AdtTransformation.d.ts.map +1 -1
  84. package/dist/core/transformation/AdtTransformation.js +11 -2
  85. package/package.json +1 -1
@@ -21,6 +21,7 @@
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.AdtDomain = void 0;
23
23
  const internalUtils_1 = require("../../utils/internalUtils");
24
+ const LockRegistry_1 = require("../shared/LockRegistry");
24
25
  const versions_1 = require("../shared/versions");
25
26
  const activation_1 = require("./activation");
26
27
  const check_1 = require("./check");
@@ -35,11 +36,13 @@ class AdtDomain {
35
36
  connection;
36
37
  logger;
37
38
  systemContext;
39
+ lockTracker;
38
40
  objectType = 'Domain';
39
- constructor(connection, logger, systemContext) {
41
+ constructor(connection, logger, systemContext, lockRegistry) {
40
42
  this.connection = connection;
41
43
  this.logger = logger;
42
44
  this.systemContext = systemContext ?? {};
45
+ this.lockTracker = (0, LockRegistry_1.createLockTracker)(lockRegistry, this.objectType, (domainName, lockHandle) => (0, unlock_1.unlockDomain)(this.connection, domainName, lockHandle));
43
46
  }
44
47
  /**
45
48
  * Validate domain configuration before creation
@@ -230,6 +233,7 @@ class AdtDomain {
230
233
  this.connection.setSessionType('stateful');
231
234
  lockHandle = await (0, lock_1.lockDomain)(this.connection, config.domainName);
232
235
  state.lockHandle = lockHandle;
236
+ this.lockTracker.track(config.domainName, lockHandle);
233
237
  this.logger?.info?.('locked');
234
238
  // 2. Check inactive with XML for update (if provided)
235
239
  const xmlToCheck = options?.xmlContent;
@@ -280,6 +284,7 @@ class AdtDomain {
280
284
  const unlockResponse = await (0, unlock_1.unlockDomain)(this.connection, config.domainName, lockHandle);
281
285
  state.unlockResult = unlockResponse;
282
286
  this.connection.setSessionType('stateless');
287
+ this.lockTracker.untrack(config.domainName);
283
288
  lockHandle = undefined;
284
289
  this.logger?.info?.('unlocked');
285
290
  }
@@ -323,8 +328,11 @@ class AdtDomain {
323
328
  this.connection.setSessionType('stateful');
324
329
  await (0, unlock_1.unlockDomain)(this.connection, config.domainName, lockHandle);
325
330
  this.connection.setSessionType('stateless');
331
+ this.lockTracker.untrack(config.domainName);
326
332
  }
327
333
  catch (unlockError) {
334
+ // Cleanup unlock failed — the lock stays tracked so unlockAll() (or
335
+ // session-drop) remains the last resort.
328
336
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
329
337
  }
330
338
  }
@@ -462,6 +470,7 @@ class AdtDomain {
462
470
  }
463
471
  this.connection.setSessionType('stateful');
464
472
  const lockHandle = await (0, lock_1.lockDomain)(this.connection, config.domainName);
473
+ this.lockTracker.track(config.domainName, lockHandle);
465
474
  return lockHandle;
466
475
  }
467
476
  /**
@@ -474,6 +483,7 @@ class AdtDomain {
474
483
  this.connection.setSessionType('stateful');
475
484
  const result = await (0, unlock_1.unlockDomain)(this.connection, config.domainName, lockHandle);
476
485
  this.connection.setSessionType('stateless');
486
+ this.lockTracker.untrack(config.domainName);
477
487
  return {
478
488
  unlockResult: result,
479
489
  errors: [],
@@ -26,14 +26,25 @@
26
26
  */
27
27
  import type { IAbapConnection, IAdtObject, IAdtOperationOptions, ILogger } from '@mcp-abap-adt/interfaces';
28
28
  import type { IAdtSystemContext } from '../../clients/AdtClient';
29
+ import type { LockRegistry } from '../shared/LockRegistry';
29
30
  import type { IReadOptions } from '../shared/types';
30
31
  import { type IEnhancementConfig, type IEnhancementState } from './types';
31
32
  export declare class AdtEnhancement implements IAdtObject<IEnhancementConfig, IEnhancementState> {
32
33
  private readonly connection;
33
34
  private readonly logger?;
34
35
  private readonly systemContext;
36
+ private readonly lockRegistry?;
35
37
  readonly objectType: string;
36
- constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext);
38
+ constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, lockRegistry?: LockRegistry);
39
+ /** Registry key for a held enhancement lock (e.g. `Enhancement/ZFOO`). */
40
+ private lockKey;
41
+ /**
42
+ * Record a held lock. Enhancement unlock needs the enhancement type, so the
43
+ * unlock thunk captures it alongside the name and handle.
44
+ */
45
+ private trackLock;
46
+ /** Drop a lock from the registry after a clean unlock. */
47
+ private untrackLock;
37
48
  /**
38
49
  * Validate enhancement configuration before creation
39
50
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AdtEnhancement.d.ts","sourceRoot":"","sources":["../../../src/core/enhancement/AdtEnhancement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,OAAO,EACR,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAWpD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAEvB,MAAM,SAAS,CAAC;AASjB,qBAAa,cACX,YAAW,UAAU,CAAC,kBAAkB,EAAE,iBAAiB,CAAC;IAE5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,SAAgB,UAAU,EAAE,MAAM,CAAiB;gBAGjD,UAAU,EAAE,eAAe,EAC3B,MAAM,CAAC,EAAE,OAAO,EAChB,aAAa,CAAC,EAAE,iBAAiB;IAOnC;;OAEG;IACG,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAqC7B;;OAEG;IACG,MAAM,CACV,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IA2E7B;;OAEG;IACG,IAAI,CACR,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,EAC/B,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAqDzC;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,iBAAiB,CAAC;IAgD7B;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,iBAAiB,CAAC;IA+C7B;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IAkP7B;;OAEG;IACG,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAiD7B;;;OAGG;IACG,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAqC7B;;OAEG;IACG,KAAK,CACT,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,CAAC;IAoC7B;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAchE;;OAEG;IACG,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAoB7B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAI/C,gBAAgB,CAAC,UAAU,EAAE,MAAM;CAGpC"}
1
+ {"version":3,"file":"AdtEnhancement.d.ts","sourceRoot":"","sources":["../../../src/core/enhancement/AdtEnhancement.ts"],"names":[],"mappings":"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"}
@@ -43,11 +43,33 @@ class AdtEnhancement {
43
43
  connection;
44
44
  logger;
45
45
  systemContext;
46
+ lockRegistry;
46
47
  objectType = 'Enhancement';
47
- constructor(connection, logger, systemContext) {
48
+ constructor(connection, logger, systemContext, lockRegistry) {
48
49
  this.connection = connection;
49
50
  this.logger = logger;
50
51
  this.systemContext = systemContext ?? {};
52
+ this.lockRegistry = lockRegistry;
53
+ }
54
+ /** Registry key for a held enhancement lock (e.g. `Enhancement/ZFOO`). */
55
+ lockKey(name) {
56
+ return `${this.objectType}/${name.toUpperCase()}`;
57
+ }
58
+ /**
59
+ * Record a held lock. Enhancement unlock needs the enhancement type, so the
60
+ * unlock thunk captures it alongside the name and handle.
61
+ */
62
+ trackLock(type, name, lockHandle) {
63
+ if (!type || !name)
64
+ return;
65
+ // Raw unlock — LockRegistry.unlockAll() manages the session for the batch.
66
+ this.lockRegistry?.track(this.lockKey(name), () => (0, unlock_1.unlockEnhancement)(this.connection, type, name, lockHandle));
67
+ }
68
+ /** Drop a lock from the registry after a clean unlock. */
69
+ untrackLock(name) {
70
+ if (!name)
71
+ return;
72
+ this.lockRegistry?.untrack(this.lockKey(name));
51
73
  }
52
74
  /**
53
75
  * Validate enhancement configuration before creation
@@ -327,6 +349,7 @@ class AdtEnhancement {
327
349
  this.connection.setSessionType('stateful');
328
350
  lockHandle = await (0, lock_1.lockEnhancement)(this.connection, config.enhancementType, config.enhancementName);
329
351
  state.lockHandle = lockHandle;
352
+ this.trackLock(config.enhancementType, config.enhancementName, lockHandle);
330
353
  this.logger?.info?.('Enhancement locked, handle:', lockHandle);
331
354
  // 2. Check inactive with code for update (from options or config)
332
355
  const codeToCheck = options?.sourceCode || config.sourceCode;
@@ -348,13 +371,14 @@ class AdtEnhancement {
348
371
  }, this.logger);
349
372
  state.updateResult = updateResponse;
350
373
  this.logger?.info?.('Enhancement updated');
374
+ // Poll the inactive version: the write above produced it; the active version may not exist yet.
351
375
  // 3.5. Read with long polling (wait for object to be ready after update)
352
376
  this.logger?.info?.('read (wait for object ready after update)');
353
377
  try {
354
378
  await this.read({
355
379
  enhancementName: config.enhancementName,
356
380
  enhancementType: config.enhancementType,
357
- }, 'active', { withLongPolling: true });
381
+ }, 'inactive', { withLongPolling: true });
358
382
  this.logger?.info?.('object is ready after update');
359
383
  }
360
384
  catch (readError) {
@@ -368,6 +392,7 @@ class AdtEnhancement {
368
392
  const unlockResponse = await (0, unlock_1.unlockEnhancement)(this.connection, config.enhancementType, config.enhancementName, lockHandle);
369
393
  state.unlockResult = unlockResponse;
370
394
  this.connection.setSessionType('stateless');
395
+ this.untrackLock(config.enhancementName);
371
396
  lockHandle = undefined;
372
397
  this.logger?.info?.('Enhancement unlocked');
373
398
  }
@@ -396,8 +421,11 @@ class AdtEnhancement {
396
421
  }
397
422
  return state;
398
423
  }
399
- // Read and return result (no stateful needed)
400
- const readResponse = await (0, read_1.getEnhancementSource)(this.connection, config.enhancementType, config.enhancementName);
424
+ // Read and return result (no stateful needed).
425
+ // No activation happened: return the version just written (inactive,
426
+ // i.e. workingArea in the enhancement URI dialect), not the stale active
427
+ // one. getEnhancementSource defaults to 'active', so pass it explicitly.
428
+ const readResponse = await (0, read_1.getEnhancementSource)(this.connection, config.enhancementType, config.enhancementName, 'inactive');
401
429
  state.readResult = readResponse;
402
430
  return state;
403
431
  }
@@ -409,6 +437,7 @@ class AdtEnhancement {
409
437
  this.connection.setSessionType('stateful');
410
438
  await (0, unlock_1.unlockEnhancement)(this.connection, config.enhancementType, config.enhancementName, lockHandle);
411
439
  this.connection.setSessionType('stateless');
440
+ this.untrackLock(config.enhancementName);
412
441
  }
413
442
  catch (unlockError) {
414
443
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
@@ -559,6 +588,7 @@ class AdtEnhancement {
559
588
  }
560
589
  this.connection.setSessionType('stateful');
561
590
  const lockHandle = await (0, lock_1.lockEnhancement)(this.connection, config.enhancementType, config.enhancementName);
591
+ this.trackLock(config.enhancementType, config.enhancementName, lockHandle);
562
592
  return lockHandle;
563
593
  }
564
594
  /**
@@ -571,6 +601,7 @@ class AdtEnhancement {
571
601
  this.connection.setSessionType('stateful');
572
602
  const result = await (0, unlock_1.unlockEnhancement)(this.connection, config.enhancementType, config.enhancementName, lockHandle);
573
603
  this.connection.setSessionType('stateless');
604
+ this.untrackLock(config.enhancementName);
574
605
  return {
575
606
  unlockResult: result,
576
607
  errors: [],
@@ -20,14 +20,16 @@
20
20
  */
21
21
  import type { IAbapConnection, IAdtOperationOptions, ILogger, IObjectVersion } from '@mcp-abap-adt/interfaces';
22
22
  import type { IAdtSystemContext } from '../../clients/AdtClient';
23
+ import { type LockRegistry } from '../shared/LockRegistry';
23
24
  import { type IReadOptions } from './read';
24
25
  import type { IFeatureToggleConfig, IFeatureToggleObject, IFeatureToggleState } from './types';
25
26
  export declare class AdtFeatureToggle implements IFeatureToggleObject {
26
27
  private readonly connection;
27
28
  private readonly logger?;
28
29
  private readonly systemContext;
30
+ private readonly lockTracker;
29
31
  readonly objectType: string;
30
- constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext);
32
+ constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, lockRegistry?: LockRegistry);
31
33
  /**
32
34
  * Map camelCase config to the snake_case low-level params.
33
35
  * `source` is passed through unchanged (it is a structured JSON object,
@@ -1 +1 @@
1
- {"version":3,"file":"AdtFeatureToggle.d.ts","sourceRoot":"","sources":["../../../src/core/featureToggle/AdtFeatureToggle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdtFeatureToggle.d.ts","sourceRoot":"","sources":["../../../src/core/featureToggle/AdtFeatureToggle.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,7 @@
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.AdtFeatureToggle = void 0;
24
24
  const internalUtils_1 = require("../../utils/internalUtils");
25
+ const LockRegistry_1 = require("../shared/LockRegistry");
25
26
  const versions_1 = require("../shared/versions");
26
27
  const activation_1 = require("./activation");
27
28
  const check_1 = require("./check");
@@ -41,11 +42,13 @@ class AdtFeatureToggle {
41
42
  connection;
42
43
  logger;
43
44
  systemContext;
45
+ lockTracker;
44
46
  objectType = 'FeatureToggle';
45
- constructor(connection, logger, systemContext) {
47
+ constructor(connection, logger, systemContext, lockRegistry) {
46
48
  this.connection = connection;
47
49
  this.logger = logger;
48
50
  this.systemContext = systemContext ?? {};
51
+ this.lockTracker = (0, LockRegistry_1.createLockTracker)(lockRegistry, this.objectType, (featureToggleName, lockHandle) => (0, unlock_1.unlockFeatureToggle)(this.connection, featureToggleName, lockHandle));
49
52
  }
50
53
  /**
51
54
  * Map camelCase config to the snake_case low-level params.
@@ -112,6 +115,7 @@ class AdtFeatureToggle {
112
115
  this.connection.setSessionType('stateful');
113
116
  lockHandle = await (0, lock_1.lockFeatureToggle)(this.connection, config.featureToggleName, this.logger);
114
117
  state.lockHandle = lockHandle;
118
+ this.lockTracker.track(config.featureToggleName, lockHandle);
115
119
  config.onLock?.(lockHandle);
116
120
  this.logger?.info?.('Feature toggle locked, handle:', lockHandle);
117
121
  // 2. Upload source
@@ -121,6 +125,7 @@ class AdtFeatureToggle {
121
125
  this.connection.setSessionType('stateful');
122
126
  await (0, unlock_1.unlockFeatureToggle)(this.connection, config.featureToggleName, lockHandle);
123
127
  this.connection.setSessionType('stateless');
128
+ this.lockTracker.untrack(config.featureToggleName);
124
129
  lockHandle = undefined;
125
130
  this.logger?.info?.('Feature toggle unlocked');
126
131
  // 4. Activate
@@ -137,6 +142,7 @@ class AdtFeatureToggle {
137
142
  this.logger?.warn?.('Unlocking feature toggle during create error cleanup');
138
143
  this.connection.setSessionType('stateful');
139
144
  await (0, unlock_1.unlockFeatureToggle)(this.connection, config.featureToggleName, lockHandle);
145
+ this.lockTracker.untrack(config.featureToggleName);
140
146
  }
141
147
  catch (unlockError) {
142
148
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
@@ -259,6 +265,7 @@ class AdtFeatureToggle {
259
265
  this.connection.setSessionType('stateful');
260
266
  lockHandle = await (0, lock_1.lockFeatureToggle)(this.connection, fullConfig.featureToggleName, this.logger);
261
267
  state.lockHandle = lockHandle;
268
+ this.lockTracker.track(fullConfig.featureToggleName, lockHandle);
262
269
  fullConfig.onLock?.(lockHandle);
263
270
  this.logger?.info?.('Feature toggle locked, handle:', lockHandle);
264
271
  // 2. Check inactive with XML for update (if provided)
@@ -279,10 +286,11 @@ class AdtFeatureToggle {
279
286
  await (0, updateSource_1.uploadFeatureToggleSource)(this.connection, fullConfig.featureToggleName, fullConfig.source, lockHandle, fullConfig.transportRequest);
280
287
  this.logger?.info?.('Feature toggle source uploaded');
281
288
  }
289
+ // Poll the inactive version: the write above produced it; the active version may not exist yet.
282
290
  // 3.5. Read with long polling to ensure object is ready after update
283
291
  this.logger?.info?.('read (wait for object ready after update)');
284
292
  try {
285
- const readState = await this.read({ featureToggleName: fullConfig.featureToggleName }, 'active', { withLongPolling: true });
293
+ const readState = await this.read({ featureToggleName: fullConfig.featureToggleName }, 'inactive', { withLongPolling: true });
286
294
  if (readState) {
287
295
  state.readResult = readState.readResult;
288
296
  }
@@ -296,6 +304,7 @@ class AdtFeatureToggle {
296
304
  this.connection.setSessionType('stateful');
297
305
  await (0, unlock_1.unlockFeatureToggle)(this.connection, fullConfig.featureToggleName, lockHandle);
298
306
  this.connection.setSessionType('stateless');
307
+ this.lockTracker.untrack(fullConfig.featureToggleName);
299
308
  lockHandle = undefined;
300
309
  this.logger?.info?.('Feature toggle unlocked');
301
310
  // 5. Final check
@@ -331,6 +340,7 @@ class AdtFeatureToggle {
331
340
  this.connection.setSessionType('stateful');
332
341
  await (0, unlock_1.unlockFeatureToggle)(this.connection, fullConfig.featureToggleName, lockHandle);
333
342
  this.connection.setSessionType('stateless');
343
+ this.lockTracker.untrack(fullConfig.featureToggleName);
334
344
  }
335
345
  catch (unlockError) {
336
346
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
@@ -431,6 +441,7 @@ class AdtFeatureToggle {
431
441
  }
432
442
  this.connection.setSessionType('stateful');
433
443
  const lockHandle = await (0, lock_1.lockFeatureToggle)(this.connection, config.featureToggleName, this.logger);
444
+ this.lockTracker.track(config.featureToggleName, lockHandle);
434
445
  return lockHandle;
435
446
  }
436
447
  /**
@@ -443,6 +454,7 @@ class AdtFeatureToggle {
443
454
  this.connection.setSessionType('stateful');
444
455
  await (0, unlock_1.unlockFeatureToggle)(this.connection, config.featureToggleName, lockHandle);
445
456
  this.connection.setSessionType('stateless');
457
+ this.lockTracker.untrack(config.featureToggleName);
446
458
  return { errors: [] };
447
459
  }
448
460
  // ---------------------------------------------------------------------------
@@ -23,6 +23,7 @@
23
23
  import type { IAbapConnection, IAdtObject, IAdtOperationOptions, ILogger, IObjectVersion } from '@mcp-abap-adt/interfaces';
24
24
  import type { IAdtSystemContext } from '../../clients/AdtClient';
25
25
  import type { IAdtContentTypes } from '../shared/contentTypes';
26
+ import { type LockRegistry } from '../shared/LockRegistry';
26
27
  import type { IReadOptions } from '../shared/types';
27
28
  import type { IFunctionGroupConfig, IFunctionGroupState } from './types';
28
29
  export declare class AdtFunctionGroup implements IAdtObject<IFunctionGroupConfig, IFunctionGroupState> {
@@ -30,8 +31,9 @@ export declare class AdtFunctionGroup implements IAdtObject<IFunctionGroupConfig
30
31
  protected readonly logger?: ILogger;
31
32
  protected readonly systemContext: IAdtSystemContext;
32
33
  protected readonly contentTypes?: IAdtContentTypes;
34
+ private readonly lockTracker;
33
35
  readonly objectType: string;
34
- constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes);
36
+ constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes, lockRegistry?: LockRegistry);
35
37
  /**
36
38
  * Validate function group configuration before creation
37
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AdtFunctionGroup.d.ts","sourceRoot":"","sources":["../../../src/core/functionGroup/AdtFunctionGroup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdtFunctionGroup.d.ts","sourceRoot":"","sources":["../../../src/core/functionGroup/AdtFunctionGroup.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.AdtFunctionGroup = void 0;
26
26
  const internalUtils_1 = require("../../utils/internalUtils");
27
+ const LockRegistry_1 = require("../shared/LockRegistry");
27
28
  const versions_1 = require("../shared/versions");
28
29
  const activation_1 = require("./activation");
29
30
  const check_1 = require("./check");
@@ -38,12 +39,14 @@ class AdtFunctionGroup {
38
39
  logger;
39
40
  systemContext;
40
41
  contentTypes;
42
+ lockTracker;
41
43
  objectType = 'FunctionGroup';
42
- constructor(connection, logger, systemContext, contentTypes) {
44
+ constructor(connection, logger, systemContext, contentTypes, lockRegistry) {
43
45
  this.connection = connection;
44
46
  this.logger = logger;
45
47
  this.systemContext = systemContext ?? {};
46
48
  this.contentTypes = contentTypes;
49
+ this.lockTracker = (0, LockRegistry_1.createLockTracker)(lockRegistry, this.objectType, (functionGroupName, lockHandle) => (0, lock_1.unlockFunctionGroup)(this.connection, functionGroupName, lockHandle));
47
50
  }
48
51
  /**
49
52
  * Validate function group configuration before creation
@@ -345,6 +348,7 @@ class AdtFunctionGroup {
345
348
  this.logger?.info?.('Step 1: Locking function group');
346
349
  this.connection.setSessionType('stateful');
347
350
  lockHandle = await (0, lock_1.lockFunctionGroup)(this.connection, config.functionGroupName, sessionId);
351
+ this.lockTracker.track(config.functionGroupName, lockHandle);
348
352
  this.logger?.info?.('Function group locked, handle:', lockHandle);
349
353
  // 2. Update metadata (description)
350
354
  this.logger?.info?.('Step 2: Updating function group metadata');
@@ -371,6 +375,7 @@ class AdtFunctionGroup {
371
375
  this.connection.setSessionType('stateful');
372
376
  await (0, lock_1.unlockFunctionGroup)(this.connection, config.functionGroupName, lockHandle, sessionId);
373
377
  this.connection.setSessionType('stateless');
378
+ this.lockTracker.untrack(config.functionGroupName);
374
379
  lockHandle = undefined;
375
380
  this.logger?.info?.('Function group unlocked');
376
381
  }
@@ -420,6 +425,7 @@ class AdtFunctionGroup {
420
425
  this.connection.setSessionType('stateful');
421
426
  await (0, lock_1.unlockFunctionGroup)(this.connection, config.functionGroupName, lockHandle, sessionId);
422
427
  this.connection.setSessionType('stateless');
428
+ this.lockTracker.untrack(config.functionGroupName);
423
429
  }
424
430
  catch (unlockError) {
425
431
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
@@ -515,6 +521,7 @@ class AdtFunctionGroup {
515
521
  }
516
522
  this.connection.setSessionType('stateful');
517
523
  const lockHandle = await (0, lock_1.lockFunctionGroup)(this.connection, config.functionGroupName);
524
+ this.lockTracker.track(config.functionGroupName, lockHandle);
518
525
  return lockHandle;
519
526
  }
520
527
  /**
@@ -527,6 +534,7 @@ class AdtFunctionGroup {
527
534
  this.connection.setSessionType('stateful');
528
535
  const result = await (0, lock_1.unlockFunctionGroup)(this.connection, config.functionGroupName, lockHandle);
529
536
  this.connection.setSessionType('stateless');
537
+ this.lockTracker.untrack(config.functionGroupName);
530
538
  return {
531
539
  unlockResult: result,
532
540
  errors: [],
@@ -17,6 +17,7 @@
17
17
  import type { IAbapConnection, IAdtObject, IAdtOperationOptions, ILogger } from '@mcp-abap-adt/interfaces';
18
18
  import type { IAdtSystemContext } from '../../clients/AdtClient';
19
19
  import type { IAdtContentTypes } from '../shared/contentTypes';
20
+ import type { LockRegistry } from '../shared/LockRegistry';
20
21
  import { type IReadOptions } from './read';
21
22
  import type { IFunctionIncludeConfig, IFunctionIncludeState } from './types';
22
23
  export declare class AdtFunctionInclude implements IAdtObject<IFunctionIncludeConfig, IFunctionIncludeState> {
@@ -24,8 +25,15 @@ export declare class AdtFunctionInclude implements IAdtObject<IFunctionIncludeCo
24
25
  protected readonly logger?: ILogger;
25
26
  protected readonly systemContext: IAdtSystemContext;
26
27
  protected readonly contentTypes?: IAdtContentTypes;
28
+ private readonly lockRegistry?;
27
29
  readonly objectType: string;
28
- constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes);
30
+ constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes, lockRegistry?: LockRegistry);
31
+ /** Registry key for a held lock (nested: group + include). */
32
+ private lockKey;
33
+ /** Record a held lock; the unlock thunk needs the parent function group. */
34
+ private trackLock;
35
+ /** Drop a lock from the registry after a clean unlock. */
36
+ private untrackLock;
29
37
  /**
30
38
  * Map camelCase config to the snake_case low-level params.
31
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AdtFunctionInclude.d.ts","sourceRoot":"","sources":["../../../src/core/functionInclude/AdtFunctionInclude.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdtFunctionInclude.d.ts","sourceRoot":"","sources":["../../../src/core/functionInclude/AdtFunctionInclude.ts"],"names":[],"mappings":"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"}
@@ -35,12 +35,31 @@ class AdtFunctionInclude {
35
35
  logger;
36
36
  systemContext;
37
37
  contentTypes;
38
+ lockRegistry;
38
39
  objectType = 'FunctionInclude';
39
- constructor(connection, logger, systemContext, contentTypes) {
40
+ constructor(connection, logger, systemContext, contentTypes, lockRegistry) {
40
41
  this.connection = connection;
41
42
  this.logger = logger;
42
43
  this.systemContext = systemContext ?? {};
43
44
  this.contentTypes = contentTypes;
45
+ this.lockRegistry = lockRegistry;
46
+ }
47
+ /** Registry key for a held lock (nested: group + include). */
48
+ lockKey(group, includeName) {
49
+ return `${this.objectType}/${group.toUpperCase()}/${includeName.toUpperCase()}`;
50
+ }
51
+ /** Record a held lock; the unlock thunk needs the parent function group. */
52
+ trackLock(group, includeName, lockHandle) {
53
+ if (!group || !includeName)
54
+ return;
55
+ // Raw unlock — LockRegistry.unlockAll() manages the session for the batch.
56
+ this.lockRegistry?.track(this.lockKey(group, includeName), () => (0, unlock_1.unlockFunctionInclude)(this.connection, group, includeName, lockHandle));
57
+ }
58
+ /** Drop a lock from the registry after a clean unlock. */
59
+ untrackLock(group, includeName) {
60
+ if (!group || !includeName)
61
+ return;
62
+ this.lockRegistry?.untrack(this.lockKey(group, includeName));
44
63
  }
45
64
  /**
46
65
  * Map camelCase config to the snake_case low-level params.
@@ -121,6 +140,7 @@ class AdtFunctionInclude {
121
140
  this.logger?.info?.('Step 2: Locking function include for source upload');
122
141
  this.connection.setSessionType('stateful');
123
142
  lockHandle = await (0, lock_1.lockFunctionInclude)(this.connection, config.functionGroupName, config.includeName, this.logger);
143
+ this.trackLock(config.functionGroupName, config.includeName, lockHandle);
124
144
  state.lockHandle = lockHandle;
125
145
  config.onLock?.(lockHandle);
126
146
  this.logger?.info?.('Step 3: Uploading function include source');
@@ -129,6 +149,7 @@ class AdtFunctionInclude {
129
149
  this.connection.setSessionType('stateful');
130
150
  await (0, unlock_1.unlockFunctionInclude)(this.connection, config.functionGroupName, config.includeName, lockHandle);
131
151
  this.connection.setSessionType('stateless');
152
+ this.untrackLock(config.functionGroupName, config.includeName);
132
153
  lockHandle = undefined;
133
154
  this.logger?.info?.('Step 5: Activating function include');
134
155
  const activateResponse = await (0, activation_1.activateFunctionInclude)(this.connection, config.functionGroupName, config.includeName);
@@ -144,6 +165,7 @@ class AdtFunctionInclude {
144
165
  this.connection.setSessionType('stateful');
145
166
  await (0, unlock_1.unlockFunctionInclude)(this.connection, config.functionGroupName, config.includeName, lockHandle);
146
167
  this.connection.setSessionType('stateless');
168
+ this.untrackLock(config.functionGroupName, config.includeName);
147
169
  }
148
170
  catch (unlockError) {
149
171
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
@@ -310,6 +332,7 @@ class AdtFunctionInclude {
310
332
  this.connection.setSessionType('stateful');
311
333
  lockHandle = await (0, lock_1.lockFunctionInclude)(this.connection, fullConfig.functionGroupName, fullConfig.includeName, this.logger);
312
334
  state.lockHandle = lockHandle;
335
+ this.trackLock(fullConfig.functionGroupName, fullConfig.includeName, lockHandle);
313
336
  fullConfig.onLock?.(lockHandle);
314
337
  this.logger?.info?.('Function include locked, handle:', lockHandle);
315
338
  // 2. Check inactive with source code for update (if provided)
@@ -327,13 +350,14 @@ class AdtFunctionInclude {
327
350
  if (codeToCheck) {
328
351
  this.logger?.info?.('Step 3b: Uploading function include source');
329
352
  await (0, updateSource_1.uploadFunctionIncludeSource)(this.connection, fullConfig.functionGroupName, fullConfig.includeName, codeToCheck, lockHandle, this.isUnicode(), fullConfig.transportRequest);
353
+ // Poll the inactive version: the write above produced it; the active version may not exist yet.
330
354
  // Wait for object to be ready after update
331
355
  this.logger?.info?.('read (wait for object ready after update)');
332
356
  try {
333
357
  await this.readMetadataRaw({
334
358
  functionGroupName: fullConfig.functionGroupName,
335
359
  includeName: fullConfig.includeName,
336
- }, 'active', { withLongPolling: true });
360
+ }, 'inactive', { withLongPolling: true });
337
361
  this.logger?.info?.('object is ready after update');
338
362
  }
339
363
  catch (readError) {
@@ -345,6 +369,7 @@ class AdtFunctionInclude {
345
369
  this.connection.setSessionType('stateful');
346
370
  await (0, unlock_1.unlockFunctionInclude)(this.connection, fullConfig.functionGroupName, fullConfig.includeName, lockHandle);
347
371
  this.connection.setSessionType('stateless');
372
+ this.untrackLock(fullConfig.functionGroupName, fullConfig.includeName);
348
373
  lockHandle = undefined;
349
374
  // 5. Final check
350
375
  this.logger?.info?.('Step 5: Final check');
@@ -369,7 +394,9 @@ class AdtFunctionInclude {
369
394
  }
370
395
  }
371
396
  else {
372
- const readResponse = await (0, read_1.readFunctionInclude)(this.connection, fullConfig.functionGroupName, fullConfig.includeName, 'active');
397
+ // No activation happened: return the version just written (inactive),
398
+ // not the stale active one.
399
+ const readResponse = await (0, read_1.readFunctionInclude)(this.connection, fullConfig.functionGroupName, fullConfig.includeName, 'inactive');
373
400
  state.readResult = readResponse;
374
401
  }
375
402
  return state;
@@ -381,6 +408,7 @@ class AdtFunctionInclude {
381
408
  this.connection.setSessionType('stateful');
382
409
  await (0, unlock_1.unlockFunctionInclude)(this.connection, fullConfig.functionGroupName, fullConfig.includeName, lockHandle);
383
410
  this.connection.setSessionType('stateless');
411
+ this.untrackLock(fullConfig.functionGroupName, fullConfig.includeName);
384
412
  }
385
413
  catch (unlockError) {
386
414
  this.logger?.warn?.('Failed to unlock during cleanup:', (0, internalUtils_1.safeErrorMessage)(unlockError));
@@ -482,6 +510,7 @@ class AdtFunctionInclude {
482
510
  }
483
511
  this.connection.setSessionType('stateful');
484
512
  const lockHandle = await (0, lock_1.lockFunctionInclude)(this.connection, config.functionGroupName, config.includeName, this.logger);
513
+ this.trackLock(config.functionGroupName, config.includeName, lockHandle);
485
514
  return lockHandle;
486
515
  }
487
516
  /**
@@ -494,6 +523,7 @@ class AdtFunctionInclude {
494
523
  this.connection.setSessionType('stateful');
495
524
  await (0, unlock_1.unlockFunctionInclude)(this.connection, config.functionGroupName, config.includeName, lockHandle);
496
525
  this.connection.setSessionType('stateless');
526
+ this.untrackLock(config.functionGroupName, config.includeName);
497
527
  return { errors: [] };
498
528
  }
499
529
  getVersions(config) {
@@ -20,6 +20,7 @@
20
20
  import type { IAbapConnection, IAdtObject, IAdtOperationOptions, ILogger } from '@mcp-abap-adt/interfaces';
21
21
  import type { IAdtSystemContext } from '../../clients/AdtClient';
22
22
  import type { IAdtContentTypes } from '../shared/contentTypes';
23
+ import type { LockRegistry } from '../shared/LockRegistry';
23
24
  import type { IReadOptions } from '../shared/types';
24
25
  import type { IFunctionModuleConfig, IFunctionModuleState } from './types';
25
26
  export declare class AdtFunctionModule implements IAdtObject<IFunctionModuleConfig, IFunctionModuleState> {
@@ -27,8 +28,15 @@ export declare class AdtFunctionModule implements IAdtObject<IFunctionModuleConf
27
28
  protected readonly logger?: ILogger;
28
29
  protected readonly systemContext: IAdtSystemContext;
29
30
  protected readonly contentTypes?: IAdtContentTypes;
31
+ private readonly lockRegistry?;
30
32
  readonly objectType: string;
31
- constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes);
33
+ constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes, lockRegistry?: LockRegistry);
34
+ /** Registry key for a held lock (nested: group + module). */
35
+ private lockKey;
36
+ /** Record a held lock; the unlock thunk needs the parent function group. */
37
+ private trackLock;
38
+ /** Drop a lock from the registry after a clean unlock. */
39
+ private untrackLock;
32
40
  /**
33
41
  * Validate function module configuration before creation
34
42
  */