@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.
- package/dist/clients/AdtClient.d.ts +32 -0
- package/dist/clients/AdtClient.d.ts.map +1 -1
- package/dist/clients/AdtClient.js +75 -30
- package/dist/core/accessControl/AdtAccessControl.d.ts +3 -1
- package/dist/core/accessControl/AdtAccessControl.d.ts.map +1 -1
- package/dist/core/accessControl/AdtAccessControl.js +11 -2
- package/dist/core/appendStructure/AdtAppendStructure.d.ts +3 -1
- package/dist/core/appendStructure/AdtAppendStructure.d.ts.map +1 -1
- package/dist/core/appendStructure/AdtAppendStructure.js +11 -2
- package/dist/core/authorizationField/AdtAuthorizationField.d.ts +3 -1
- package/dist/core/authorizationField/AdtAuthorizationField.d.ts.map +1 -1
- package/dist/core/authorizationField/AdtAuthorizationField.js +14 -3
- package/dist/core/behaviorDefinition/AdtBehaviorDefinition.d.ts +3 -1
- package/dist/core/behaviorDefinition/AdtBehaviorDefinition.d.ts.map +1 -1
- package/dist/core/behaviorDefinition/AdtBehaviorDefinition.js +11 -2
- package/dist/core/behaviorImplementation/AdtBehaviorImplementation.d.ts +2 -1
- package/dist/core/behaviorImplementation/AdtBehaviorImplementation.d.ts.map +1 -1
- package/dist/core/behaviorImplementation/AdtBehaviorImplementation.js +6 -3
- package/dist/core/class/AdtClass.d.ts +3 -1
- package/dist/core/class/AdtClass.d.ts.map +1 -1
- package/dist/core/class/AdtClass.js +16 -3
- package/dist/core/dataElement/AdtDataElement.d.ts +3 -1
- package/dist/core/dataElement/AdtDataElement.d.ts.map +1 -1
- package/dist/core/dataElement/AdtDataElement.js +9 -1
- package/dist/core/ddl/AdtDdl.d.ts +3 -1
- package/dist/core/ddl/AdtDdl.d.ts.map +1 -1
- package/dist/core/ddl/AdtDdl.js +11 -2
- package/dist/core/domain/AdtDomain.d.ts +3 -1
- package/dist/core/domain/AdtDomain.d.ts.map +1 -1
- package/dist/core/domain/AdtDomain.js +11 -1
- package/dist/core/enhancement/AdtEnhancement.d.ts +12 -1
- package/dist/core/enhancement/AdtEnhancement.d.ts.map +1 -1
- package/dist/core/enhancement/AdtEnhancement.js +35 -4
- package/dist/core/featureToggle/AdtFeatureToggle.d.ts +3 -1
- package/dist/core/featureToggle/AdtFeatureToggle.d.ts.map +1 -1
- package/dist/core/featureToggle/AdtFeatureToggle.js +14 -2
- package/dist/core/functionGroup/AdtFunctionGroup.d.ts +3 -1
- package/dist/core/functionGroup/AdtFunctionGroup.d.ts.map +1 -1
- package/dist/core/functionGroup/AdtFunctionGroup.js +9 -1
- package/dist/core/functionInclude/AdtFunctionInclude.d.ts +9 -1
- package/dist/core/functionInclude/AdtFunctionInclude.d.ts.map +1 -1
- package/dist/core/functionInclude/AdtFunctionInclude.js +33 -3
- package/dist/core/functionModule/AdtFunctionModule.d.ts +9 -1
- package/dist/core/functionModule/AdtFunctionModule.d.ts.map +1 -1
- package/dist/core/functionModule/AdtFunctionModule.js +27 -2
- package/dist/core/interface/AdtInterface.d.ts +3 -1
- package/dist/core/interface/AdtInterface.d.ts.map +1 -1
- package/dist/core/interface/AdtInterface.js +11 -2
- package/dist/core/messageClass/AdtMessageClass.d.ts +3 -1
- package/dist/core/messageClass/AdtMessageClass.d.ts.map +1 -1
- package/dist/core/messageClass/AdtMessageClass.js +11 -2
- package/dist/core/metadataExtension/AdtMetadataExtension.d.ts +3 -1
- package/dist/core/metadataExtension/AdtMetadataExtension.d.ts.map +1 -1
- package/dist/core/metadataExtension/AdtMetadataExtension.js +9 -1
- package/dist/core/package/AdtPackage.d.ts +3 -1
- package/dist/core/package/AdtPackage.d.ts.map +1 -1
- package/dist/core/package/AdtPackage.js +11 -2
- package/dist/core/program/AdtProgram.d.ts +3 -1
- package/dist/core/program/AdtProgram.d.ts.map +1 -1
- package/dist/core/program/AdtProgram.js +11 -2
- package/dist/core/scalarFunction/AdtScalarFunction.d.ts +3 -1
- package/dist/core/scalarFunction/AdtScalarFunction.d.ts.map +1 -1
- package/dist/core/scalarFunction/AdtScalarFunction.js +11 -2
- package/dist/core/scalarFunctionImplementation/AdtScalarFunctionImplementation.d.ts +3 -1
- package/dist/core/scalarFunctionImplementation/AdtScalarFunctionImplementation.d.ts.map +1 -1
- package/dist/core/scalarFunctionImplementation/AdtScalarFunctionImplementation.js +14 -2
- package/dist/core/serviceDefinition/AdtServiceDefinition.d.ts +6 -3
- package/dist/core/serviceDefinition/AdtServiceDefinition.d.ts.map +1 -1
- package/dist/core/serviceDefinition/AdtServiceDefinition.js +14 -4
- package/dist/core/shared/LockRegistry.d.ts +77 -0
- package/dist/core/shared/LockRegistry.d.ts.map +1 -0
- package/dist/core/shared/LockRegistry.js +91 -0
- package/dist/core/structure/AdtStructure.d.ts +3 -1
- package/dist/core/structure/AdtStructure.d.ts.map +1 -1
- package/dist/core/structure/AdtStructure.js +11 -2
- package/dist/core/table/AdtTable.d.ts +3 -1
- package/dist/core/table/AdtTable.d.ts.map +1 -1
- package/dist/core/table/AdtTable.js +11 -2
- package/dist/core/tabletype/AdtDdicTableType.d.ts +3 -1
- package/dist/core/tabletype/AdtDdicTableType.d.ts.map +1 -1
- package/dist/core/tabletype/AdtDdicTableType.js +9 -1
- package/dist/core/transformation/AdtTransformation.d.ts +3 -1
- package/dist/core/transformation/AdtTransformation.d.ts.map +1 -1
- package/dist/core/transformation/AdtTransformation.js +11 -2
- 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,
|
|
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
|
-
}, '
|
|
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
|
-
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,oBAAoB,EACpB,OAAO,EACP,cAAc,EACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;
|
|
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 }, '
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,OAAO,EACP,cAAc,EACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAQpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGzE,qBAAa,gBACX,YAAW,UAAU,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IAEhE,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IAC/C,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IACpC,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IACpD,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACnD,SAAgB,UAAU,EAAE,MAAM,CAAmB;gBAGnD,UAAU,EAAE,eAAe,EAC3B,MAAM,CAAC,EAAE,OAAO,EAChB,aAAa,CAAC,EAAE,iBAAiB,EACjC,YAAY,CAAC,EAAE,gBAAgB;
|
|
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":"AAAA;;;;;;;;;;;;;;;GAeG;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,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;
|
|
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
|
-
}, '
|
|
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
|
-
|
|
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
|
*/
|