@mcp-abap-adt/connection 1.0.0 → 1.1.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/README.md +15 -1
- package/dist/connection/GenericWebSocketTransport.d.ts +46 -0
- package/dist/connection/GenericWebSocketTransport.d.ts.map +1 -0
- package/dist/connection/GenericWebSocketTransport.js +135 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ ABAP connection layer for MCP ABAP ADT server. Provides a unified interface for
|
|
|
7
7
|
- 🔐 **Multiple Authentication Methods**:
|
|
8
8
|
- Basic Auth for on-premise SAP systems
|
|
9
9
|
- JWT/OAuth2 for SAP BTP ABAP Environment
|
|
10
|
+
- SAML session cookies for pre-authenticated enterprise flows
|
|
10
11
|
- 🔄 **Token Management**:
|
|
11
12
|
- Token refresh is handled by `@mcp-abap-adt/auth-broker` package
|
|
12
13
|
- Connection package focuses on HTTP communication only
|
|
@@ -15,8 +16,11 @@ ABAP connection layer for MCP ABAP ADT server. Provides a unified interface for
|
|
|
15
16
|
- Session state persistence is handled by `@mcp-abap-adt/auth-broker` package
|
|
16
17
|
- 🏗️ **Clean Architecture**:
|
|
17
18
|
- Abstract base class for common HTTP/session logic
|
|
18
|
-
- Auth-type specific implementations (BaseAbapConnection, JwtAbapConnection)
|
|
19
|
+
- Auth-type specific implementations (BaseAbapConnection, JwtAbapConnection, SamlAbapConnection)
|
|
19
20
|
- Proper separation of concerns - no JWT logic in base class
|
|
21
|
+
- 🔌 **Realtime Transport Scaffold**:
|
|
22
|
+
- Generic `GenericWebSocketTransport` with pluggable WS factory
|
|
23
|
+
- Reusable for debugger/traces and other event-driven flows
|
|
20
24
|
- 📝 **Custom Logging**: Pluggable logger interface for integration with any logging system
|
|
21
25
|
- 🛠️ **CLI Tool**: See [JWT Auth Tools](./docs/JWT_AUTH_TOOLS.md) for obtaining SAP BTP tokens
|
|
22
26
|
- 📦 **TypeScript**: Full TypeScript support with type definitions included
|
|
@@ -43,6 +47,16 @@ The package uses a clean separation of concerns:
|
|
|
43
47
|
- Suitable for SAP BTP ABAP Environment
|
|
44
48
|
- Token refresh handled by auth-broker package
|
|
45
49
|
|
|
50
|
+
- **`SamlAbapConnection`** (concrete, exported):
|
|
51
|
+
- Session-cookie-based authentication (`authType: "saml"`)
|
|
52
|
+
- Uses existing SSO/SAML session cookies
|
|
53
|
+
- Fetches CSRF token and executes ADT requests in same HTTP model
|
|
54
|
+
|
|
55
|
+
- **`GenericWebSocketTransport`** (concrete, exported):
|
|
56
|
+
- Transport abstraction for realtime WS message flows
|
|
57
|
+
- Pluggable factory, envelope-based send/receive
|
|
58
|
+
- Intended for higher-level debugger/trace session orchestration
|
|
59
|
+
|
|
46
60
|
## Responsibilities and Design Principles
|
|
47
61
|
|
|
48
62
|
### Core Development Principle
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { IWebSocketCloseInfo, IWebSocketConnectOptions, IWebSocketMessageEnvelope, IWebSocketMessageHandler, IWebSocketTransport } from '@mcp-abap-adt/interfaces';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal WS-like instance contract to avoid hard dependency on a specific WS library.
|
|
4
|
+
*/
|
|
5
|
+
interface IWebSocketLike {
|
|
6
|
+
readyState: number;
|
|
7
|
+
send(data: string): void;
|
|
8
|
+
close(code?: number, reason?: string): void;
|
|
9
|
+
onopen: ((event: unknown) => void) | null;
|
|
10
|
+
onmessage: ((event: {
|
|
11
|
+
data: unknown;
|
|
12
|
+
}) => void) | null;
|
|
13
|
+
onerror: ((event: unknown) => void) | null;
|
|
14
|
+
onclose: ((event: {
|
|
15
|
+
code?: number;
|
|
16
|
+
reason?: string;
|
|
17
|
+
wasClean?: boolean;
|
|
18
|
+
}) => void) | null;
|
|
19
|
+
}
|
|
20
|
+
interface IWebSocketFactory {
|
|
21
|
+
create(url: string, protocols?: string | string[], options?: IWebSocketConnectOptions): IWebSocketLike;
|
|
22
|
+
}
|
|
23
|
+
export declare class GenericWebSocketTransport implements IWebSocketTransport {
|
|
24
|
+
private readonly factory;
|
|
25
|
+
private socket;
|
|
26
|
+
private messageHandlers;
|
|
27
|
+
private openHandlers;
|
|
28
|
+
private errorHandlers;
|
|
29
|
+
private closeHandlers;
|
|
30
|
+
constructor(factory: IWebSocketFactory);
|
|
31
|
+
connect(url: string, options?: IWebSocketConnectOptions): Promise<void>;
|
|
32
|
+
disconnect(code?: number, reason?: string): Promise<void>;
|
|
33
|
+
send<T = unknown>(message: IWebSocketMessageEnvelope<T>): Promise<void>;
|
|
34
|
+
onMessage<T = unknown>(handler: IWebSocketMessageHandler<T>): void;
|
|
35
|
+
onOpen(handler: () => void | Promise<void>): void;
|
|
36
|
+
onError(handler: (error: Error) => void | Promise<void>): void;
|
|
37
|
+
onClose(handler: (info: IWebSocketCloseInfo) => void | Promise<void>): void;
|
|
38
|
+
isConnected(): boolean;
|
|
39
|
+
private handleIncomingMessage;
|
|
40
|
+
private normalizeError;
|
|
41
|
+
private emitOpen;
|
|
42
|
+
private emitError;
|
|
43
|
+
private emitClose;
|
|
44
|
+
}
|
|
45
|
+
export type { IWebSocketFactory, IWebSocketLike };
|
|
46
|
+
//# sourceMappingURL=GenericWebSocketTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenericWebSocketTransport.d.ts","sourceRoot":"","sources":["../../src/connection/GenericWebSocketTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,UAAU,cAAc;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACvD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3C,OAAO,EACH,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC,GACzE,IAAI,CAAC;CACV;AAED,UAAU,iBAAiB;IACzB,MAAM,CACJ,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAC7B,OAAO,CAAC,EAAE,wBAAwB,GACjC,cAAc,CAAC;CACnB;AAID,qBAAa,yBAA0B,YAAW,mBAAmB;IASvD,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,eAAe,CAAgD;IACvE,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,aAAa,CAAqD;IAC1E,OAAO,CAAC,aAAa,CAEd;gBAEsB,OAAO,EAAE,iBAAiB;IAEjD,OAAO,CACX,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,IAAI,CAAC;IAqDV,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBzD,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,OAAO,EAAE,yBAAyB,CAAC,CAAC,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC;IAQhB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,IAAI;IAIlE,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIjD,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI9D,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI3E,WAAW,IAAI,OAAO;YAIR,qBAAqB;IAoBnC,OAAO,CAAC,cAAc;YAUR,QAAQ;YAMR,SAAS;YAMT,SAAS;CAKxB;AAED,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GenericWebSocketTransport = void 0;
|
|
4
|
+
const WS_OPEN = 1;
|
|
5
|
+
class GenericWebSocketTransport {
|
|
6
|
+
factory;
|
|
7
|
+
socket = null;
|
|
8
|
+
messageHandlers = [];
|
|
9
|
+
openHandlers = [];
|
|
10
|
+
errorHandlers = [];
|
|
11
|
+
closeHandlers = [];
|
|
12
|
+
constructor(factory) {
|
|
13
|
+
this.factory = factory;
|
|
14
|
+
}
|
|
15
|
+
async connect(url, options) {
|
|
16
|
+
if (this.socket && this.isConnected()) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const connectTimeoutMs = options?.connectTimeoutMs ?? 15000;
|
|
20
|
+
const socket = this.factory.create(url, options?.protocols, options);
|
|
21
|
+
this.socket = socket;
|
|
22
|
+
await new Promise((resolve, reject) => {
|
|
23
|
+
const timeoutId = setTimeout(() => {
|
|
24
|
+
reject(new Error(`WebSocket connect timeout after ${connectTimeoutMs}ms`));
|
|
25
|
+
}, connectTimeoutMs);
|
|
26
|
+
socket.onopen = () => {
|
|
27
|
+
clearTimeout(timeoutId);
|
|
28
|
+
this.emitOpen().catch(() => {
|
|
29
|
+
// no-op
|
|
30
|
+
});
|
|
31
|
+
resolve();
|
|
32
|
+
};
|
|
33
|
+
socket.onerror = (event) => {
|
|
34
|
+
clearTimeout(timeoutId);
|
|
35
|
+
const err = this.normalizeError(event, 'WebSocket connection error');
|
|
36
|
+
this.emitError(err).catch(() => {
|
|
37
|
+
// no-op
|
|
38
|
+
});
|
|
39
|
+
reject(err);
|
|
40
|
+
};
|
|
41
|
+
socket.onclose = (event) => {
|
|
42
|
+
clearTimeout(timeoutId);
|
|
43
|
+
const info = {
|
|
44
|
+
code: typeof event?.code === 'number' ? event.code : 1006,
|
|
45
|
+
reason: event?.reason,
|
|
46
|
+
wasClean: event?.wasClean,
|
|
47
|
+
};
|
|
48
|
+
this.emitClose(info).catch(() => {
|
|
49
|
+
// no-op
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
socket.onmessage = (event) => {
|
|
53
|
+
this.handleIncomingMessage(event?.data).catch(() => {
|
|
54
|
+
// no-op
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async disconnect(code, reason) {
|
|
60
|
+
if (!this.socket) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const socket = this.socket;
|
|
64
|
+
this.socket = null;
|
|
65
|
+
try {
|
|
66
|
+
socket.close(code, reason);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const err = this.normalizeError(error, 'WebSocket close failed');
|
|
70
|
+
await this.emitError(err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async send(message) {
|
|
74
|
+
if (!this.socket || this.socket.readyState !== WS_OPEN) {
|
|
75
|
+
throw new Error('WebSocket is not connected');
|
|
76
|
+
}
|
|
77
|
+
this.socket.send(JSON.stringify(message));
|
|
78
|
+
}
|
|
79
|
+
onMessage(handler) {
|
|
80
|
+
this.messageHandlers.push(handler);
|
|
81
|
+
}
|
|
82
|
+
onOpen(handler) {
|
|
83
|
+
this.openHandlers.push(handler);
|
|
84
|
+
}
|
|
85
|
+
onError(handler) {
|
|
86
|
+
this.errorHandlers.push(handler);
|
|
87
|
+
}
|
|
88
|
+
onClose(handler) {
|
|
89
|
+
this.closeHandlers.push(handler);
|
|
90
|
+
}
|
|
91
|
+
isConnected() {
|
|
92
|
+
return !!this.socket && this.socket.readyState === WS_OPEN;
|
|
93
|
+
}
|
|
94
|
+
async handleIncomingMessage(rawData) {
|
|
95
|
+
try {
|
|
96
|
+
const text = typeof rawData === 'string'
|
|
97
|
+
? rawData
|
|
98
|
+
: rawData instanceof Buffer
|
|
99
|
+
? rawData.toString('utf8')
|
|
100
|
+
: String(rawData ?? '');
|
|
101
|
+
const parsed = JSON.parse(text);
|
|
102
|
+
for (const handler of this.messageHandlers) {
|
|
103
|
+
await handler(parsed);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
await this.emitError(this.normalizeError(error, 'Failed to process WS message'));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
normalizeError(error, fallback) {
|
|
111
|
+
if (error instanceof Error) {
|
|
112
|
+
return error;
|
|
113
|
+
}
|
|
114
|
+
if (typeof error === 'string' && error.trim()) {
|
|
115
|
+
return new Error(error.trim());
|
|
116
|
+
}
|
|
117
|
+
return new Error(fallback);
|
|
118
|
+
}
|
|
119
|
+
async emitOpen() {
|
|
120
|
+
for (const handler of this.openHandlers) {
|
|
121
|
+
await handler();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async emitError(error) {
|
|
125
|
+
for (const handler of this.errorHandlers) {
|
|
126
|
+
await handler(error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async emitClose(info) {
|
|
130
|
+
for (const handler of this.closeHandlers) {
|
|
131
|
+
await handler(info);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.GenericWebSocketTransport = GenericWebSocketTransport;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
export type { IWebSocketCloseInfo, IWebSocketConnectOptions, IWebSocketMessageEnvelope, IWebSocketMessageHandler, IWebSocketTransport, } from '@mcp-abap-adt/interfaces';
|
|
1
2
|
export type { SapAuthType, SapConfig, } from './config/sapConfig.js';
|
|
2
3
|
export { sapConfigSignature } from './config/sapConfig.js';
|
|
3
4
|
export type { AbapConnection, AbapRequestOptions, } from './connection/AbapConnection.js';
|
|
4
5
|
export { BaseAbapConnection, BaseAbapConnection as OnPremAbapConnection, } from './connection/BaseAbapConnection.js';
|
|
5
6
|
export { createAbapConnection } from './connection/connectionFactory.js';
|
|
6
7
|
export { CSRF_CONFIG, CSRF_ERROR_MESSAGES } from './connection/csrfConfig.js';
|
|
8
|
+
export { GenericWebSocketTransport, type IWebSocketFactory, type IWebSocketLike, } from './connection/GenericWebSocketTransport.js';
|
|
7
9
|
export { JwtAbapConnection, JwtAbapConnection as CloudAbapConnection, } from './connection/JwtAbapConnection.js';
|
|
8
10
|
export { SamlAbapConnection } from './connection/SamlAbapConnection.js';
|
|
9
11
|
export type { ILogger } from './logger.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,WAAW,EACX,SAAS,GACV,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,YAAY,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,IAAI,oBAAoB,GAC3C,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,IAAI,mBAAmB,GACzC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// Types - re-exported from interfaces package with backward compatibility aliases
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTimeoutConfig = exports.getTimeout = exports.SamlAbapConnection = exports.CloudAbapConnection = exports.JwtAbapConnection = exports.CSRF_ERROR_MESSAGES = exports.CSRF_CONFIG = exports.createAbapConnection = exports.OnPremAbapConnection = exports.BaseAbapConnection = exports.sapConfigSignature = void 0;
|
|
4
|
+
exports.getTimeoutConfig = exports.getTimeout = exports.SamlAbapConnection = exports.CloudAbapConnection = exports.JwtAbapConnection = exports.GenericWebSocketTransport = exports.CSRF_ERROR_MESSAGES = exports.CSRF_CONFIG = exports.createAbapConnection = exports.OnPremAbapConnection = exports.BaseAbapConnection = exports.sapConfigSignature = void 0;
|
|
4
5
|
// Config utilities
|
|
5
6
|
var sapConfig_js_1 = require("./config/sapConfig.js");
|
|
6
7
|
Object.defineProperty(exports, "sapConfigSignature", { enumerable: true, get: function () { return sapConfig_js_1.sapConfigSignature; } });
|
|
@@ -16,6 +17,8 @@ Object.defineProperty(exports, "createAbapConnection", { enumerable: true, get:
|
|
|
16
17
|
var csrfConfig_js_1 = require("./connection/csrfConfig.js");
|
|
17
18
|
Object.defineProperty(exports, "CSRF_CONFIG", { enumerable: true, get: function () { return csrfConfig_js_1.CSRF_CONFIG; } });
|
|
18
19
|
Object.defineProperty(exports, "CSRF_ERROR_MESSAGES", { enumerable: true, get: function () { return csrfConfig_js_1.CSRF_ERROR_MESSAGES; } });
|
|
20
|
+
var GenericWebSocketTransport_js_1 = require("./connection/GenericWebSocketTransport.js");
|
|
21
|
+
Object.defineProperty(exports, "GenericWebSocketTransport", { enumerable: true, get: function () { return GenericWebSocketTransport_js_1.GenericWebSocketTransport; } });
|
|
19
22
|
var JwtAbapConnection_js_1 = require("./connection/JwtAbapConnection.js");
|
|
20
23
|
Object.defineProperty(exports, "JwtAbapConnection", { enumerable: true, get: function () { return JwtAbapConnection_js_1.JwtAbapConnection; } });
|
|
21
24
|
Object.defineProperty(exports, "CloudAbapConnection", { enumerable: true, get: function () { return JwtAbapConnection_js_1.JwtAbapConnection; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/connection",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "ABAP connection layer for MCP ABAP ADT server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,16 +46,16 @@
|
|
|
46
46
|
"node": ">=18.0.0"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@mcp-abap-adt/interfaces": "^2.
|
|
50
|
-
"axios": "^1.
|
|
51
|
-
"commander": "^14.0.
|
|
49
|
+
"@mcp-abap-adt/interfaces": "^2.4.0",
|
|
50
|
+
"axios": "^1.13.5",
|
|
51
|
+
"commander": "^14.0.3",
|
|
52
52
|
"express": "^5.1.0",
|
|
53
53
|
"open": "^11.0.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@biomejs/biome": "^2.3.
|
|
56
|
+
"@biomejs/biome": "^2.3.14",
|
|
57
57
|
"@types/jest": "^30.0.0",
|
|
58
|
-
"@types/node": "^
|
|
58
|
+
"@types/node": "^25.2.3",
|
|
59
59
|
"jest": "^30.2.0",
|
|
60
60
|
"jest-util": "^30.2.0",
|
|
61
61
|
"ts-jest": "^29.2.5",
|