@mcp-abap-adt/adt-clients 7.5.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/class/AdtClass.d.ts +3 -0
- package/dist/core/class/AdtClass.d.ts.map +1 -1
- package/dist/core/class/AdtClass.js +38 -25
- package/dist/core/domain/AdtDomain.d.ts +2 -0
- package/dist/core/domain/AdtDomain.d.ts.map +1 -1
- package/dist/core/domain/AdtDomain.js +27 -17
- package/dist/core/serviceDefinition/AdtServiceDefinition.d.ts +3 -0
- package/dist/core/serviceDefinition/AdtServiceDefinition.d.ts.map +1 -1
- package/dist/core/serviceDefinition/AdtServiceDefinition.js +41 -17
- package/dist/core/shared/capabilities/LockCapability.d.ts +37 -0
- package/dist/core/shared/capabilities/LockCapability.d.ts.map +1 -0
- package/dist/core/shared/capabilities/LockCapability.js +59 -0
- package/dist/core/shared/capabilities/VersionsCapability.d.ts +15 -0
- package/dist/core/shared/capabilities/VersionsCapability.d.ts.map +1 -0
- package/dist/core/shared/capabilities/VersionsCapability.js +26 -0
- package/dist/core/shared/capabilities/index.d.ts +4 -0
- package/dist/core/shared/capabilities/index.d.ts.map +1 -0
- package/dist/core/shared/capabilities/index.js +22 -0
- package/dist/core/shared/capabilities/types.d.ts +41 -0
- package/dist/core/shared/capabilities/types.d.ts.map +1 -0
- package/dist/core/shared/capabilities/types.js +2 -0
- package/dist/utils/activationUtils.d.ts.map +1 -1
- package/dist/utils/activationUtils.js +82 -1
- package/package.json +2 -2
|
@@ -30,6 +30,9 @@ export declare class AdtClass implements IAdtObject<IClassConfig, IClassState> {
|
|
|
30
30
|
protected readonly contentTypes?: IAdtContentTypes;
|
|
31
31
|
private readonly lockTracker;
|
|
32
32
|
readonly objectType: string;
|
|
33
|
+
private readonly capCtx;
|
|
34
|
+
private readonly lockCap;
|
|
35
|
+
private readonly versionsCap;
|
|
33
36
|
constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, contentTypes?: IAdtContentTypes, lockRegistry?: LockRegistry);
|
|
34
37
|
/**
|
|
35
38
|
* Validate class configuration before creation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdtClass.d.ts","sourceRoot":"","sources":["../../../src/core/class/AdtClass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAGL,KAAK,YAAY,IAAI,aAAa,EAElC,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,oBAAoB,EACzB,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"AdtClass.d.ts","sourceRoot":"","sources":["../../../src/core/class/AdtClass.ts"],"names":[],"mappings":"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"}
|
|
@@ -54,6 +54,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
54
54
|
exports.AdtClass = void 0;
|
|
55
55
|
const interfaces_1 = require("@mcp-abap-adt/interfaces");
|
|
56
56
|
const internalUtils_1 = require("../../utils/internalUtils");
|
|
57
|
+
const capabilities_1 = require("../shared/capabilities");
|
|
57
58
|
const LockRegistry_1 = require("../shared/LockRegistry");
|
|
58
59
|
const activation_1 = require("./activation");
|
|
59
60
|
const check_1 = require("./check");
|
|
@@ -73,6 +74,36 @@ class AdtClass {
|
|
|
73
74
|
contentTypes;
|
|
74
75
|
lockTracker;
|
|
75
76
|
objectType = 'Class';
|
|
77
|
+
// LAZY thunk (not a getter that snapshots): captures `this` but reads
|
|
78
|
+
// this.connection/this.logger only when invoked, after the constructor has
|
|
79
|
+
// run — so building the capabilities below as class fields is safe.
|
|
80
|
+
capCtx = () => ({
|
|
81
|
+
connection: this.connection,
|
|
82
|
+
logger: this.logger,
|
|
83
|
+
});
|
|
84
|
+
lockCap = new capabilities_1.LockCapability(this.capCtx, {
|
|
85
|
+
nameOf: (c) => {
|
|
86
|
+
if (!c.className)
|
|
87
|
+
throw new Error('Class name is required');
|
|
88
|
+
return c.className;
|
|
89
|
+
},
|
|
90
|
+
acquire: async (ctx, name) => ({
|
|
91
|
+
lockHandle: await (0, lock_1.lockClass)(ctx.connection, name),
|
|
92
|
+
}),
|
|
93
|
+
release: async (ctx, name, handle) => {
|
|
94
|
+
const result = await (0, unlock_1.unlockClass)(ctx.connection, name, handle);
|
|
95
|
+
return { unlockResult: result, errors: [] };
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
versionsCap = new capabilities_1.VersionsCapability(this.capCtx, {
|
|
99
|
+
nameOf: (c) => {
|
|
100
|
+
if (!c.className)
|
|
101
|
+
throw new Error('className is required');
|
|
102
|
+
return c.className;
|
|
103
|
+
},
|
|
104
|
+
list: (ctx, name) => (0, versions_1.getClassIncludeVersions)(ctx.connection, name, 'main'),
|
|
105
|
+
source: (ctx, uri) => (0, versions_1.getClassVersionSource)(ctx.connection, uri),
|
|
106
|
+
});
|
|
76
107
|
constructor(connection, logger, systemContext, contentTypes, lockRegistry) {
|
|
77
108
|
this.connection = connection;
|
|
78
109
|
this.logger = logger;
|
|
@@ -537,33 +568,17 @@ class AdtClass {
|
|
|
537
568
|
* Lock class
|
|
538
569
|
*/
|
|
539
570
|
async lock(config) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
// Stay stateful while the lock is held — the caller must release it via
|
|
544
|
-
// unlock(), which restores stateless. On older BASIS (#106) the lock handle
|
|
545
|
-
// is only valid inside stateful requests, so a stateless write between lock
|
|
546
|
-
// and unlock fails with 423.
|
|
547
|
-
this.connection.setSessionType('stateful');
|
|
548
|
-
const lockHandle = await (0, lock_1.lockClass)(this.connection, config.className);
|
|
549
|
-
this.lockTracker.track(config.className, lockHandle);
|
|
550
|
-
return lockHandle;
|
|
571
|
+
const handle = await this.lockCap.lock(config);
|
|
572
|
+
this.lockTracker.track(config.className, handle);
|
|
573
|
+
return handle;
|
|
551
574
|
}
|
|
552
575
|
/**
|
|
553
576
|
* Unlock class
|
|
554
577
|
*/
|
|
555
578
|
async unlock(config, lockHandle) {
|
|
556
|
-
|
|
557
|
-
throw new Error('Class name is required');
|
|
558
|
-
}
|
|
559
|
-
this.connection.setSessionType('stateful');
|
|
560
|
-
const result = await (0, unlock_1.unlockClass)(this.connection, config.className, lockHandle);
|
|
561
|
-
this.connection.setSessionType('stateless');
|
|
579
|
+
const state = await this.lockCap.unlock(config, lockHandle);
|
|
562
580
|
this.lockTracker.untrack(config.className);
|
|
563
|
-
return
|
|
564
|
-
unlockResult: result,
|
|
565
|
-
errors: [],
|
|
566
|
-
};
|
|
581
|
+
return state;
|
|
567
582
|
}
|
|
568
583
|
/**
|
|
569
584
|
* Lock test classes (local classes) for modification
|
|
@@ -698,12 +713,10 @@ class AdtClass {
|
|
|
698
713
|
}
|
|
699
714
|
}
|
|
700
715
|
getVersions(config) {
|
|
701
|
-
|
|
702
|
-
throw new Error('className is required');
|
|
703
|
-
return (0, versions_1.getClassIncludeVersions)(this.connection, config.className, 'main');
|
|
716
|
+
return this.versionsCap.getVersions(config);
|
|
704
717
|
}
|
|
705
718
|
getVersionSource(contentUri) {
|
|
706
|
-
return
|
|
719
|
+
return this.versionsCap.getVersionSource(contentUri);
|
|
707
720
|
}
|
|
708
721
|
/** Shared by local-include subclasses to target their own include. */
|
|
709
722
|
getIncludeVersions(className, includeType) {
|
|
@@ -28,6 +28,8 @@ export declare class AdtDomain implements IAdtObject<IDomainConfig, IDomainState
|
|
|
28
28
|
private readonly systemContext;
|
|
29
29
|
private readonly lockTracker;
|
|
30
30
|
readonly objectType: string;
|
|
31
|
+
private readonly capCtx;
|
|
32
|
+
private readonly lockCap;
|
|
31
33
|
constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, lockRegistry?: LockRegistry);
|
|
32
34
|
/**
|
|
33
35
|
* Validate domain configuration before creation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdtDomain.d.ts","sourceRoot":"","sources":["../../../src/core/domain/AdtDomain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;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;
|
|
1
|
+
{"version":3,"file":"AdtDomain.d.ts","sourceRoot":"","sources":["../../../src/core/domain/AdtDomain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;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;AAMjE,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAQpD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI3D,qBAAa,SAAU,YAAW,UAAU,CAAC,aAAa,EAAE,YAAY,CAAC;IACvE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,SAAgB,UAAU,EAAE,MAAM,CAAY;IAK9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGpB;IAEH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAetB;gBAGA,UAAU,EAAE,eAAe,EAC3B,MAAM,CAAC,EAAE,OAAO,EAChB,aAAa,CAAC,EAAE,iBAAiB,EACjC,YAAY,CAAC,EAAE,YAAY;IAa7B;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBrE;;OAEG;IACG,MAAM,CACV,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,YAAY,CAAC;IAmExB;;OAEG;IACG,IAAI,CACR,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,EAC9B,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,EAChC,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAyBpC;;;OAGG;IACG,YAAY,CAChB,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,EAC9B,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,YAAY,CAAC;IA4CxB;;;OAGG;IACG,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,EAC9B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,YAAY,CAAC;IA8NxB;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAmCnE;;;OAGG;IACG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAsBrE;;OAEG;IACG,KAAK,CACT,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,EAC9B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC;IAuBxB;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,EAC9B,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,YAAY,CAAC;IAoCxB;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAM3D;;OAEG;IACG,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,EAC9B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC;IAMlB,WAAW,CACf,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAC9B,OAAO,CAAC,cAAc,EAAE,CAAC;IAItB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAG7D"}
|
|
@@ -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 capabilities_1 = require("../shared/capabilities");
|
|
24
25
|
const LockRegistry_1 = require("../shared/LockRegistry");
|
|
25
26
|
const versions_1 = require("../shared/versions");
|
|
26
27
|
const activation_1 = require("./activation");
|
|
@@ -38,6 +39,27 @@ class AdtDomain {
|
|
|
38
39
|
systemContext;
|
|
39
40
|
lockTracker;
|
|
40
41
|
objectType = 'Domain';
|
|
42
|
+
// LAZY thunk (not a getter that snapshots): captures `this` but reads
|
|
43
|
+
// this.connection/this.logger only when invoked, after the constructor has
|
|
44
|
+
// run — so building the capability below as a class field is safe.
|
|
45
|
+
capCtx = () => ({
|
|
46
|
+
connection: this.connection,
|
|
47
|
+
logger: this.logger,
|
|
48
|
+
});
|
|
49
|
+
lockCap = new capabilities_1.LockCapability(this.capCtx, {
|
|
50
|
+
nameOf: (c) => {
|
|
51
|
+
if (!c.domainName)
|
|
52
|
+
throw new Error('Domain name is required');
|
|
53
|
+
return c.domainName;
|
|
54
|
+
},
|
|
55
|
+
acquire: async (ctx, name) => ({
|
|
56
|
+
lockHandle: await (0, lock_1.lockDomain)(ctx.connection, name),
|
|
57
|
+
}),
|
|
58
|
+
release: async (ctx, name, handle) => {
|
|
59
|
+
const result = await (0, unlock_1.unlockDomain)(ctx.connection, name, handle);
|
|
60
|
+
return { unlockResult: result, errors: [] };
|
|
61
|
+
},
|
|
62
|
+
});
|
|
41
63
|
constructor(connection, logger, systemContext, lockRegistry) {
|
|
42
64
|
this.connection = connection;
|
|
43
65
|
this.logger = logger;
|
|
@@ -465,29 +487,17 @@ class AdtDomain {
|
|
|
465
487
|
* Lock domain for modification
|
|
466
488
|
*/
|
|
467
489
|
async lock(config) {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
this.connection.setSessionType('stateful');
|
|
472
|
-
const lockHandle = await (0, lock_1.lockDomain)(this.connection, config.domainName);
|
|
473
|
-
this.lockTracker.track(config.domainName, lockHandle);
|
|
474
|
-
return lockHandle;
|
|
490
|
+
const handle = await this.lockCap.lock(config);
|
|
491
|
+
this.lockTracker.track(config.domainName, handle);
|
|
492
|
+
return handle;
|
|
475
493
|
}
|
|
476
494
|
/**
|
|
477
495
|
* Unlock domain
|
|
478
496
|
*/
|
|
479
497
|
async unlock(config, lockHandle) {
|
|
480
|
-
|
|
481
|
-
throw new Error('Domain name is required');
|
|
482
|
-
}
|
|
483
|
-
this.connection.setSessionType('stateful');
|
|
484
|
-
const result = await (0, unlock_1.unlockDomain)(this.connection, config.domainName, lockHandle);
|
|
485
|
-
this.connection.setSessionType('stateless');
|
|
498
|
+
const state = await this.lockCap.unlock(config, lockHandle);
|
|
486
499
|
this.lockTracker.untrack(config.domainName);
|
|
487
|
-
return
|
|
488
|
-
unlockResult: result,
|
|
489
|
-
errors: [],
|
|
490
|
-
};
|
|
500
|
+
return state;
|
|
491
501
|
}
|
|
492
502
|
async getVersions(_config) {
|
|
493
503
|
(0, versions_1.throwUnsupportedVersions)('domain');
|
|
@@ -29,6 +29,9 @@ export declare class AdtServiceDefinition implements IAdtObject<IServiceDefiniti
|
|
|
29
29
|
private readonly systemContext;
|
|
30
30
|
private readonly lockTracker;
|
|
31
31
|
readonly objectType: string;
|
|
32
|
+
private readonly capCtx;
|
|
33
|
+
private readonly lockCap;
|
|
34
|
+
private readonly versionsCap;
|
|
32
35
|
constructor(connection: IAbapConnection, logger?: ILogger, systemContext?: IAdtSystemContext, lockRegistry?: LockRegistry);
|
|
33
36
|
/**
|
|
34
37
|
* Validate service definition configuration before creation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdtServiceDefinition.d.ts","sourceRoot":"","sources":["../../../src/core/serviceDefinition/AdtServiceDefinition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,OAAO,EACR,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"AdtServiceDefinition.d.ts","sourceRoot":"","sources":["../../../src/core/serviceDefinition/AdtServiceDefinition.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
23
|
exports.AdtServiceDefinition = void 0;
|
|
24
24
|
const internalUtils_1 = require("../../utils/internalUtils");
|
|
25
|
+
const capabilities_1 = require("../shared/capabilities");
|
|
25
26
|
const LockRegistry_1 = require("../shared/LockRegistry");
|
|
26
27
|
const activation_1 = require("./activation");
|
|
27
28
|
const check_1 = require("./check");
|
|
@@ -39,6 +40,41 @@ class AdtServiceDefinition {
|
|
|
39
40
|
systemContext;
|
|
40
41
|
lockTracker;
|
|
41
42
|
objectType = 'ServiceDefinition';
|
|
43
|
+
// LAZY thunk (not a getter that snapshots): captures `this` but reads
|
|
44
|
+
// this.connection/this.logger only when invoked, after the constructor has
|
|
45
|
+
// run — so building the capabilities below as class fields is safe.
|
|
46
|
+
capCtx = () => ({
|
|
47
|
+
connection: this.connection,
|
|
48
|
+
logger: this.logger,
|
|
49
|
+
});
|
|
50
|
+
lockCap = new capabilities_1.LockCapability(this.capCtx, {
|
|
51
|
+
nameOf: (c) => {
|
|
52
|
+
if (!c.serviceDefinitionName)
|
|
53
|
+
throw new Error('Service definition name is required');
|
|
54
|
+
return c.serviceDefinitionName;
|
|
55
|
+
},
|
|
56
|
+
acquire: async (ctx, name) => ({
|
|
57
|
+
lockHandle: await (0, lock_1.lockServiceDefinition)(ctx.connection, name),
|
|
58
|
+
}),
|
|
59
|
+
release: async (ctx, name, handle) => {
|
|
60
|
+
const result = await (0, unlock_1.unlockServiceDefinition)(ctx.connection, name, handle);
|
|
61
|
+
return { unlockResult: result, errors: [] };
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
versionsCap = new capabilities_1.VersionsCapability(this.capCtx, {
|
|
65
|
+
nameOf: (c) => {
|
|
66
|
+
if (!c.serviceDefinitionName)
|
|
67
|
+
throw new Error('serviceDefinitionName is required');
|
|
68
|
+
return c.serviceDefinitionName;
|
|
69
|
+
},
|
|
70
|
+
// NOTE: getServiceDefinitionVersions takes a config, not a bare name —
|
|
71
|
+
// the strategy re-wraps. (getClassIncludeVersions, by contrast, takes a
|
|
72
|
+
// name; the two low-level shapes differ and the strategy absorbs that.)
|
|
73
|
+
list: (ctx, name) => (0, versions_1.getServiceDefinitionVersions)(ctx.connection, {
|
|
74
|
+
serviceDefinitionName: name,
|
|
75
|
+
}),
|
|
76
|
+
source: (ctx, uri) => (0, versions_1.getServiceDefinitionVersionSource)(ctx.connection, uri),
|
|
77
|
+
});
|
|
42
78
|
constructor(connection, logger, systemContext, lockRegistry) {
|
|
43
79
|
this.connection = connection;
|
|
44
80
|
this.logger = logger;
|
|
@@ -415,11 +451,7 @@ class AdtServiceDefinition {
|
|
|
415
451
|
* Lock service definition for modification
|
|
416
452
|
*/
|
|
417
453
|
async lock(config) {
|
|
418
|
-
|
|
419
|
-
throw new Error('Service definition name is required');
|
|
420
|
-
}
|
|
421
|
-
this.connection.setSessionType('stateful');
|
|
422
|
-
const lockHandle = await (0, lock_1.lockServiceDefinition)(this.connection, config.serviceDefinitionName);
|
|
454
|
+
const lockHandle = await this.lockCap.lock(config);
|
|
423
455
|
this.lockTracker.track(config.serviceDefinitionName, lockHandle);
|
|
424
456
|
return lockHandle;
|
|
425
457
|
}
|
|
@@ -427,23 +459,15 @@ class AdtServiceDefinition {
|
|
|
427
459
|
* Unlock service definition
|
|
428
460
|
*/
|
|
429
461
|
async unlock(config, lockHandle) {
|
|
430
|
-
|
|
431
|
-
throw new Error('Service definition name is required');
|
|
432
|
-
}
|
|
433
|
-
this.connection.setSessionType('stateful');
|
|
434
|
-
const result = await (0, unlock_1.unlockServiceDefinition)(this.connection, config.serviceDefinitionName, lockHandle);
|
|
435
|
-
this.connection.setSessionType('stateless');
|
|
462
|
+
const state = await this.lockCap.unlock(config, lockHandle);
|
|
436
463
|
this.lockTracker.untrack(config.serviceDefinitionName);
|
|
437
|
-
return
|
|
438
|
-
unlockResult: result,
|
|
439
|
-
errors: [],
|
|
440
|
-
};
|
|
464
|
+
return state;
|
|
441
465
|
}
|
|
442
466
|
getVersions(config) {
|
|
443
|
-
return
|
|
467
|
+
return this.versionsCap.getVersions(config);
|
|
444
468
|
}
|
|
445
469
|
getVersionSource(contentUri) {
|
|
446
|
-
return
|
|
470
|
+
return this.versionsCap.getVersionSource(contentUri);
|
|
447
471
|
}
|
|
448
472
|
}
|
|
449
473
|
exports.AdtServiceDefinition = AdtServiceDefinition;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IAdtLockable } from '@mcp-abap-adt/interfaces';
|
|
2
|
+
import type { ICapabilityContext, ILockStrategy } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Shared lock/unlock for handlers whose lock differs only by endpoint and
|
|
5
|
+
* name field. `lock` leaves the session stateful (the caller must unlock).
|
|
6
|
+
* `unlock` runs the release inside a stateful request — older BASIS (#106)
|
|
7
|
+
* only accepts UNLOCK while stateful — then restores stateless. The handler's
|
|
8
|
+
* state shape (including the ADT `unlockResult`) is built by `strategy.release`
|
|
9
|
+
* and returned unchanged. See the spec's IAdtLockable obligations — idempotent
|
|
10
|
+
* unlock is a TARGET, not implemented here, and is left to the per-endpoint
|
|
11
|
+
* probe + adaptation rule of the full-migration plan.
|
|
12
|
+
*
|
|
13
|
+
* DELIBERATELY byte-identical to the current handlers, including the failure
|
|
14
|
+
* path: if `acquire`/`release` throws, the session is left as-is (stateful) and
|
|
15
|
+
* the error propagates — exactly as today. Failure/abandonment handling is
|
|
16
|
+
* DISTRIBUTED and this capability owns none of it:
|
|
17
|
+
* - the consumer largely owns lock/unlock atomicity (it decides when to lock
|
|
18
|
+
* and unlock);
|
|
19
|
+
* - adt-clients' `LockRegistry.unlockAll()` is a disposal safety net that
|
|
20
|
+
* raw-releases abandoned locks — deliberately WITHOUT toggling the session,
|
|
21
|
+
* because `unlockAll()` manages the session once for the whole batch;
|
|
22
|
+
* - the operation chain's create/update catch blocks also call
|
|
23
|
+
* setSessionType('stateless').
|
|
24
|
+
* Adding a try/finally here would change behaviour and relocate responsibility
|
|
25
|
+
* across those layers, so the atom-level "restore stateless on failure"
|
|
26
|
+
* contract is deferred to the behavioural-conformance work (same bucket as
|
|
27
|
+
* activate/check error unification), where all three layers are reconciled
|
|
28
|
+
* rather than double-cleaned.
|
|
29
|
+
*/
|
|
30
|
+
export declare class LockCapability<TConfig, TReadResult> implements IAdtLockable<TConfig, TReadResult> {
|
|
31
|
+
private readonly getCtx;
|
|
32
|
+
private readonly strategy;
|
|
33
|
+
constructor(getCtx: () => ICapabilityContext, strategy: ILockStrategy<TConfig, TReadResult>);
|
|
34
|
+
lock(config: Partial<TConfig>): Promise<string>;
|
|
35
|
+
unlock(config: Partial<TConfig>, lockHandle: string): Promise<TReadResult>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=LockCapability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LockCapability.d.ts","sourceRoot":"","sources":["../../../../src/core/shared/capabilities/LockCapability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,cAAc,CAAC,OAAO,EAAE,WAAW,CAC9C,YAAW,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC;IAK3C,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,MAAM,EAAE,MAAM,kBAAkB,EAChC,QAAQ,EAAE,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC;IAG1D,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAS/C,MAAM,CACV,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC;CASxB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LockCapability = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Shared lock/unlock for handlers whose lock differs only by endpoint and
|
|
6
|
+
* name field. `lock` leaves the session stateful (the caller must unlock).
|
|
7
|
+
* `unlock` runs the release inside a stateful request — older BASIS (#106)
|
|
8
|
+
* only accepts UNLOCK while stateful — then restores stateless. The handler's
|
|
9
|
+
* state shape (including the ADT `unlockResult`) is built by `strategy.release`
|
|
10
|
+
* and returned unchanged. See the spec's IAdtLockable obligations — idempotent
|
|
11
|
+
* unlock is a TARGET, not implemented here, and is left to the per-endpoint
|
|
12
|
+
* probe + adaptation rule of the full-migration plan.
|
|
13
|
+
*
|
|
14
|
+
* DELIBERATELY byte-identical to the current handlers, including the failure
|
|
15
|
+
* path: if `acquire`/`release` throws, the session is left as-is (stateful) and
|
|
16
|
+
* the error propagates — exactly as today. Failure/abandonment handling is
|
|
17
|
+
* DISTRIBUTED and this capability owns none of it:
|
|
18
|
+
* - the consumer largely owns lock/unlock atomicity (it decides when to lock
|
|
19
|
+
* and unlock);
|
|
20
|
+
* - adt-clients' `LockRegistry.unlockAll()` is a disposal safety net that
|
|
21
|
+
* raw-releases abandoned locks — deliberately WITHOUT toggling the session,
|
|
22
|
+
* because `unlockAll()` manages the session once for the whole batch;
|
|
23
|
+
* - the operation chain's create/update catch blocks also call
|
|
24
|
+
* setSessionType('stateless').
|
|
25
|
+
* Adding a try/finally here would change behaviour and relocate responsibility
|
|
26
|
+
* across those layers, so the atom-level "restore stateless on failure"
|
|
27
|
+
* contract is deferred to the behavioural-conformance work (same bucket as
|
|
28
|
+
* activate/check error unification), where all three layers are reconciled
|
|
29
|
+
* rather than double-cleaned.
|
|
30
|
+
*/
|
|
31
|
+
class LockCapability {
|
|
32
|
+
getCtx;
|
|
33
|
+
strategy;
|
|
34
|
+
constructor(
|
|
35
|
+
// LAZY: read at method-call time, so the handler can build this capability
|
|
36
|
+
// as a class field before its constructor assigns this.connection.
|
|
37
|
+
getCtx, strategy) {
|
|
38
|
+
this.getCtx = getCtx;
|
|
39
|
+
this.strategy = strategy;
|
|
40
|
+
}
|
|
41
|
+
async lock(config) {
|
|
42
|
+
const ctx = this.getCtx();
|
|
43
|
+
const name = this.strategy.nameOf(config);
|
|
44
|
+
// Stay stateful while the lock is held; the caller releases via unlock().
|
|
45
|
+
ctx.connection.setSessionType('stateful');
|
|
46
|
+
const { lockHandle } = await this.strategy.acquire(ctx, name);
|
|
47
|
+
return lockHandle;
|
|
48
|
+
}
|
|
49
|
+
async unlock(config, lockHandle) {
|
|
50
|
+
const ctx = this.getCtx();
|
|
51
|
+
const name = this.strategy.nameOf(config);
|
|
52
|
+
// UNLOCK must run stateful (older BASIS #106); restore stateless after.
|
|
53
|
+
ctx.connection.setSessionType('stateful');
|
|
54
|
+
const state = await this.strategy.release(ctx, name, lockHandle);
|
|
55
|
+
ctx.connection.setSessionType('stateless');
|
|
56
|
+
return state;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.LockCapability = LockCapability;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IAdtVersionable, IObjectVersion } from '@mcp-abap-adt/interfaces';
|
|
2
|
+
import type { ICapabilityContext, IVersionsStrategy } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Shared version history for source-backed objects. Types without a
|
|
5
|
+
* /source/main resource do NOT compose this capability and do not implement
|
|
6
|
+
* IAdtVersionable — absence is expressed structurally, not by throwing.
|
|
7
|
+
*/
|
|
8
|
+
export declare class VersionsCapability<TConfig> implements IAdtVersionable<TConfig> {
|
|
9
|
+
private readonly getCtx;
|
|
10
|
+
private readonly strategy;
|
|
11
|
+
constructor(getCtx: () => ICapabilityContext, strategy: IVersionsStrategy<TConfig>);
|
|
12
|
+
getVersions(config: Partial<TConfig>): Promise<IObjectVersion[]>;
|
|
13
|
+
getVersionSource(contentUri: string): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=VersionsCapability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VersionsCapability.d.ts","sourceRoot":"","sources":["../../../../src/core/shared/capabilities/VersionsCapability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAErE;;;;GAIG;AACH,qBAAa,kBAAkB,CAAC,OAAO,CAAE,YAAW,eAAe,CAAC,OAAO,CAAC;IAGxE,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,MAAM,EAAE,MAAM,kBAAkB,EAChC,QAAQ,EAAE,iBAAiB,CAAC,OAAO,CAAC;IAGvD,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAKhE,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAGtD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VersionsCapability = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Shared version history for source-backed objects. Types without a
|
|
6
|
+
* /source/main resource do NOT compose this capability and do not implement
|
|
7
|
+
* IAdtVersionable — absence is expressed structurally, not by throwing.
|
|
8
|
+
*/
|
|
9
|
+
class VersionsCapability {
|
|
10
|
+
getCtx;
|
|
11
|
+
strategy;
|
|
12
|
+
constructor(
|
|
13
|
+
// LAZY: see LockCapability — read at call time so it can be a class field.
|
|
14
|
+
getCtx, strategy) {
|
|
15
|
+
this.getCtx = getCtx;
|
|
16
|
+
this.strategy = strategy;
|
|
17
|
+
}
|
|
18
|
+
getVersions(config) {
|
|
19
|
+
const name = this.strategy.nameOf(config);
|
|
20
|
+
return this.strategy.list(this.getCtx(), name);
|
|
21
|
+
}
|
|
22
|
+
getVersionSource(contentUri) {
|
|
23
|
+
return this.strategy.source(this.getCtx(), contentUri);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.VersionsCapability = VersionsCapability;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/shared/capabilities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.VersionsCapability = exports.LockCapability = void 0;
|
|
18
|
+
var LockCapability_1 = require("./LockCapability");
|
|
19
|
+
Object.defineProperty(exports, "LockCapability", { enumerable: true, get: function () { return LockCapability_1.LockCapability; } });
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
var VersionsCapability_1 = require("./VersionsCapability");
|
|
22
|
+
Object.defineProperty(exports, "VersionsCapability", { enumerable: true, get: function () { return VersionsCapability_1.VersionsCapability; } });
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { IAbapConnection, ILogger, IObjectVersion } from '@mcp-abap-adt/interfaces';
|
|
2
|
+
/** The connection + logger every capability implementation needs. */
|
|
3
|
+
export interface ICapabilityContext {
|
|
4
|
+
readonly connection: IAbapConnection;
|
|
5
|
+
readonly logger?: ILogger;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Normalized lock result. The per-type helpers return different shapes
|
|
9
|
+
* (bare string vs { lockHandle, corrNr }); the capability normalizes up to
|
|
10
|
+
* this superset. See the spec's "lock normalization contract".
|
|
11
|
+
*/
|
|
12
|
+
export interface INormalizedLock {
|
|
13
|
+
lockHandle: string;
|
|
14
|
+
corrNr?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Per-handler strategy for LockCapability. The handler supplies its own
|
|
18
|
+
* endpoint knowledge — there is no centralized lifecycle-URI resolver
|
|
19
|
+
* (buildObjectUri is for group operations only).
|
|
20
|
+
*
|
|
21
|
+
* `release` returns the handler's OWN state shape (e.g. `{ unlockResult,
|
|
22
|
+
* errors: [] }`), not void — the current handlers put the ADT unlock response
|
|
23
|
+
* into `state.unlockResult`, and dropping it would change observable behaviour.
|
|
24
|
+
* The capability owns only the session toggling around it.
|
|
25
|
+
*/
|
|
26
|
+
export interface ILockStrategy<TConfig, TReadResult> {
|
|
27
|
+
/** Extract the object name from config, or throw if missing. */
|
|
28
|
+
nameOf(config: Partial<TConfig>): string;
|
|
29
|
+
/** POST _action=LOCK, return the normalized handle. */
|
|
30
|
+
acquire(ctx: ICapabilityContext, name: string): Promise<INormalizedLock>;
|
|
31
|
+
/** POST _action=UNLOCK with the handle; build and return the handler state. */
|
|
32
|
+
release(ctx: ICapabilityContext, name: string, lockHandle: string): Promise<TReadResult>;
|
|
33
|
+
}
|
|
34
|
+
/** Per-handler strategy for VersionsCapability. */
|
|
35
|
+
export interface IVersionsStrategy<TConfig> {
|
|
36
|
+
nameOf(config: Partial<TConfig>): string;
|
|
37
|
+
list(ctx: ICapabilityContext, name: string): Promise<IObjectVersion[]>;
|
|
38
|
+
/** GET the content URI, return the source text. */
|
|
39
|
+
source(ctx: ICapabilityContext, contentUri: string): Promise<string>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/shared/capabilities/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,OAAO,EACP,cAAc,EACf,MAAM,0BAA0B,CAAC;AAElC,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa,CAAC,OAAO,EAAE,WAAW;IACjD,gEAAgE;IAChE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;IACzC,uDAAuD;IACvD,OAAO,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACzE,+EAA+E;IAC/E,OAAO,CACL,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB;AAED,mDAAmD;AACnD,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;IACzC,IAAI,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACvE,mDAAmD;IACnD,MAAM,CAAC,GAAG,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activationUtils.d.ts","sourceRoot":"","sources":["../../src/utils/activationUtils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,YAAY,IAAI,aAAa,EAC7B,eAAe,EAChB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"activationUtils.d.ts","sourceRoot":"","sources":["../../src/utils/activationUtils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,YAAY,IAAI,aAAa,EAC7B,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAmGlC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAyGR;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,aAAa,CAAC,CA8BxB"}
|
|
@@ -9,9 +9,82 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.buildObjectUri = buildObjectUri;
|
|
11
11
|
exports.activateObjectInSession = activateObjectInSession;
|
|
12
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
12
13
|
const contentTypes_1 = require("../constants/contentTypes");
|
|
13
14
|
const internalUtils_1 = require("./internalUtils");
|
|
14
15
|
const timeouts_1 = require("./timeouts");
|
|
16
|
+
/**
|
|
17
|
+
* Extract a human-readable text from a single ADT `<msg>` node.
|
|
18
|
+
*/
|
|
19
|
+
function extractActivationMsgText(msg) {
|
|
20
|
+
const shortText = msg?.shortText;
|
|
21
|
+
if (shortText && typeof shortText === 'object' && 'txt' in shortText) {
|
|
22
|
+
const txt = shortText.txt;
|
|
23
|
+
if (typeof txt === 'string' && txt.trim()) {
|
|
24
|
+
return txt.trim();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (typeof shortText === 'string' && shortText.trim()) {
|
|
28
|
+
return shortText.trim();
|
|
29
|
+
}
|
|
30
|
+
if (typeof msg?.objDescr === 'string' && msg.objDescr.trim()) {
|
|
31
|
+
return msg.objDescr.trim();
|
|
32
|
+
}
|
|
33
|
+
return 'activation error';
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Inspect an ADT activation response body for an **explicit failure signal**.
|
|
37
|
+
*
|
|
38
|
+
* ADT's `/sap/bc/adt/activation` endpoint returns HTTP 200 even when activation
|
|
39
|
+
* fails (object locked by another session, syntax errors), carrying a
|
|
40
|
+
* `<chkl:messages>` body with `chkl:properties activationExecuted="false"` and/or
|
|
41
|
+
* `<msg type="E">` entries. Treating "no HTTP error" as success masks these
|
|
42
|
+
* failures (issue #78).
|
|
43
|
+
*
|
|
44
|
+
* Conservative by design: returns a failure detail string ONLY on a positive
|
|
45
|
+
* error signal. Empty, unparseable, or unrecognized bodies return `null`
|
|
46
|
+
* (success) so the many object types whose success-body shape differs are never
|
|
47
|
+
* regressed into false failures.
|
|
48
|
+
*
|
|
49
|
+
* @returns failure detail text, or `null` when no failure signal is present
|
|
50
|
+
*/
|
|
51
|
+
function detectActivationFailure(responseData) {
|
|
52
|
+
if (typeof responseData !== 'string' || responseData.trim() === '') {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
const parser = new fast_xml_parser_1.XMLParser({
|
|
58
|
+
ignoreAttributes: false,
|
|
59
|
+
attributeNamePrefix: '',
|
|
60
|
+
});
|
|
61
|
+
parsed = parser.parse(responseData);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const messages = parsed?.['chkl:messages'];
|
|
67
|
+
if (!messages) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const activationExecuted = messages['chkl:properties']?.activationExecuted;
|
|
71
|
+
const executedFalse = activationExecuted === 'false' || activationExecuted === false;
|
|
72
|
+
const rawMsg = messages.msg;
|
|
73
|
+
const msgList = Array.isArray(rawMsg) ? rawMsg : rawMsg ? [rawMsg] : [];
|
|
74
|
+
const errorTexts = msgList
|
|
75
|
+
.filter((m) => {
|
|
76
|
+
const severity = m?.type ??
|
|
77
|
+
m?.severity;
|
|
78
|
+
return typeof severity === 'string' && severity.toUpperCase() === 'E';
|
|
79
|
+
})
|
|
80
|
+
.map((m) => extractActivationMsgText(m));
|
|
81
|
+
if (executedFalse || errorTexts.length > 0) {
|
|
82
|
+
return errorTexts.length > 0
|
|
83
|
+
? errorTexts.join('; ')
|
|
84
|
+
: 'activationExecuted=false';
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
15
88
|
/**
|
|
16
89
|
* Build object URI from name and type
|
|
17
90
|
* Used by both individual and group activation
|
|
@@ -127,11 +200,19 @@ async function activateObjectInSession(connection, objectUri, objectName, preaud
|
|
|
127
200
|
'Content-Type': contentTypes_1.CT_ACTIVATION,
|
|
128
201
|
Accept: 'application/xml',
|
|
129
202
|
};
|
|
130
|
-
|
|
203
|
+
const response = await connection.makeAdtRequest({
|
|
131
204
|
url,
|
|
132
205
|
method: 'POST',
|
|
133
206
|
timeout: (0, timeouts_1.getTimeout)('default'),
|
|
134
207
|
data: activationXml,
|
|
135
208
|
headers,
|
|
136
209
|
});
|
|
210
|
+
// ADT returns HTTP 200 even on failed activation (locked object, syntax
|
|
211
|
+
// errors). Surface an explicit failure signal as a thrown error instead of
|
|
212
|
+
// letting callers report a false success (issue #78).
|
|
213
|
+
const failure = detectActivationFailure(response.data);
|
|
214
|
+
if (failure) {
|
|
215
|
+
throw new Error(`Activation of ${objectName} failed: ${failure}`);
|
|
216
|
+
}
|
|
217
|
+
return response;
|
|
137
218
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/adt-clients",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.0",
|
|
4
4
|
"description": "ADT clients for SAP ABAP systems - AdtClient and AdtRuntimeClient",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"node": ">=18.0.0"
|
|
114
114
|
},
|
|
115
115
|
"dependencies": {
|
|
116
|
-
"@mcp-abap-adt/interfaces": "^11.
|
|
116
|
+
"@mcp-abap-adt/interfaces": "^11.2.0",
|
|
117
117
|
"@mcp-abap-adt/logger": "^0.1.3",
|
|
118
118
|
"axios": "^1.18.1",
|
|
119
119
|
"fast-xml-parser": "^5.9.3"
|