@mcp-abap-adt/auth-stores 0.2.3 → 0.2.6
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/CHANGELOG.md +32 -0
- package/README.md +103 -0
- package/dist/errors/StoreErrors.d.ts +41 -0
- package/dist/errors/StoreErrors.js +76 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -1
- package/dist/stores/abap/AbapServiceKeyStore.js +2 -1
- package/dist/stores/btp/BtpServiceKeyStore.js +2 -1
- package/dist/stores/env/EnvFileSessionStore.d.ts +57 -0
- package/dist/stores/env/EnvFileSessionStore.js +338 -0
- package/dist/stores/xsuaa/XsuaaServiceKeyStore.js +3 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.6] - 2025-12-21
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **EnvFileSessionStore**: New session store that reads from a specific `.env` file path
|
|
14
|
+
- Use case: `mcp-abap-adt --env /path/to/.env` CLI option
|
|
15
|
+
- Supports both basic auth (SAP_USERNAME/SAP_PASSWORD) and JWT auth (SAP_JWT_TOKEN)
|
|
16
|
+
- `getAuthType()` method to determine auth type from the file
|
|
17
|
+
- Read-only for file content; token updates stored in memory only
|
|
18
|
+
- Automatic detection of auth type based on file content
|
|
19
|
+
|
|
20
|
+
## [0.2.5] - 2025-12-19
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **Version Correction**: This release corrects the version numbering issue. The typed error classes and service key store updates that were documented in 0.2.4 were released after 0.2.4 was already published. This version properly documents those changes.
|
|
24
|
+
|
|
25
|
+
## [0.2.4] - 2025-12-19
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- **Typed Error Classes**: Added typed error classes for better error handling in auth-broker
|
|
29
|
+
- `StoreError` - Base error class with error code
|
|
30
|
+
- `FileNotFoundError` - File not found errors (includes filePath)
|
|
31
|
+
- `ParseError` - JSON/YAML parsing errors (includes filePath and cause)
|
|
32
|
+
- `InvalidConfigError` - Missing required config fields (includes missingFields array)
|
|
33
|
+
- `StorageError` - File write/permission errors (includes operation and cause)
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
- **Service Key Stores**: Now throw typed errors instead of generic Error
|
|
37
|
+
- `FileNotFoundError` when service key file not found (returns null)
|
|
38
|
+
- `ParseError` when JSON parsing fails or format is invalid
|
|
39
|
+
- `InvalidConfigError` when required UAA fields are missing (returns null)
|
|
40
|
+
- **Dependency**: Updated `@mcp-abap-adt/interfaces` to `^0.2.3` for STORE_ERROR_CODES
|
|
41
|
+
|
|
10
42
|
## [0.2.3] - 2025-12-16
|
|
11
43
|
|
|
12
44
|
### Changed
|
package/README.md
CHANGED
|
@@ -90,6 +90,9 @@ Session stores manage authentication tokens and configuration:
|
|
|
90
90
|
- **`SafeAbapSessionStore`** - In-memory store for ABAP sessions
|
|
91
91
|
- **`SafeXsuaaSessionStore`** - In-memory store for XSUAA sessions
|
|
92
92
|
|
|
93
|
+
**File-based single-file stores**:
|
|
94
|
+
- **`EnvFileSessionStore`** - Reads from a specific `.env` file path (e.g., `--env /path/to/.env`)
|
|
95
|
+
|
|
93
96
|
## Usage
|
|
94
97
|
|
|
95
98
|
### BTP Stores (base BTP without sapUrl)
|
|
@@ -141,6 +144,54 @@ const sessionStore = new XsuaaSessionStore('/path/to/sessions', 'https://default
|
|
|
141
144
|
const safeSessionStore = new SafeXsuaaSessionStore('https://default.mcp.com', logger);
|
|
142
145
|
```
|
|
143
146
|
|
|
147
|
+
### EnvFileSessionStore (Single File)
|
|
148
|
+
|
|
149
|
+
`EnvFileSessionStore` reads connection configuration from a specific `.env` file path rather than a directory. This is useful for the `--env` CLI option.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { EnvFileSessionStore } from '@mcp-abap-adt/auth-stores';
|
|
153
|
+
|
|
154
|
+
// Create store pointing to specific .env file
|
|
155
|
+
const store = new EnvFileSessionStore('/path/to/.env', logger);
|
|
156
|
+
|
|
157
|
+
// Check the auth type from the file
|
|
158
|
+
const authType = store.getAuthType(); // 'basic' | 'jwt' | null
|
|
159
|
+
|
|
160
|
+
// Load session (works like other session stores)
|
|
161
|
+
const config = await store.loadSession('default');
|
|
162
|
+
console.log(config?.serviceUrl, config?.authType);
|
|
163
|
+
|
|
164
|
+
// For basic auth
|
|
165
|
+
console.log(config?.username, config?.password);
|
|
166
|
+
|
|
167
|
+
// For JWT auth
|
|
168
|
+
console.log(config?.authorizationToken, config?.refreshToken);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Env file format:**
|
|
172
|
+
```bash
|
|
173
|
+
# Connection
|
|
174
|
+
SAP_URL=https://your-sap-system.com
|
|
175
|
+
SAP_CLIENT=100
|
|
176
|
+
|
|
177
|
+
# Auth type: 'basic' or 'jwt' (defaults to 'basic')
|
|
178
|
+
SAP_AUTH_TYPE=basic
|
|
179
|
+
|
|
180
|
+
# Basic auth credentials
|
|
181
|
+
SAP_USERNAME=your-username
|
|
182
|
+
SAP_PASSWORD=your-password
|
|
183
|
+
|
|
184
|
+
# OR JWT auth
|
|
185
|
+
# SAP_AUTH_TYPE=jwt
|
|
186
|
+
# SAP_JWT_TOKEN=your-jwt-token
|
|
187
|
+
# SAP_REFRESH_TOKEN=your-refresh-token
|
|
188
|
+
# SAP_UAA_URL=https://uaa.example.com
|
|
189
|
+
# SAP_UAA_CLIENT_ID=client-id
|
|
190
|
+
# SAP_UAA_CLIENT_SECRET=client-secret
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Important**: This store is **read-only** for the file. Token updates (e.g., refreshed JWT tokens) are stored in memory only and do not modify the original `.env` file.
|
|
194
|
+
|
|
144
195
|
### Directory Configuration
|
|
145
196
|
|
|
146
197
|
All stores accept a single directory path in the constructor:
|
|
@@ -198,6 +249,58 @@ The `defaultServiceUrl` is used when creating new sessions via `setConnectionCon
|
|
|
198
249
|
|
|
199
250
|
## File Handlers
|
|
200
251
|
|
|
252
|
+
This package provides utility classes for safe file operations:
|
|
253
|
+
|
|
254
|
+
### Error Handling
|
|
255
|
+
|
|
256
|
+
All service key stores throw typed errors for better error handling:
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import {
|
|
260
|
+
BtpServiceKeyStore,
|
|
261
|
+
FileNotFoundError,
|
|
262
|
+
ParseError,
|
|
263
|
+
InvalidConfigError
|
|
264
|
+
} from '@mcp-abap-adt/auth-stores';
|
|
265
|
+
import { STORE_ERROR_CODES } from '@mcp-abap-adt/interfaces';
|
|
266
|
+
|
|
267
|
+
const serviceKeyStore = new BtpServiceKeyStore('/path/to/keys');
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const authConfig = await serviceKeyStore.getAuthorizationConfig('TRIAL');
|
|
271
|
+
console.log('Auth config loaded:', authConfig);
|
|
272
|
+
} catch (error: any) {
|
|
273
|
+
if (error.code === STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
274
|
+
// File not found - returns null instead of throwing
|
|
275
|
+
console.error('Service key file not found:', error.filePath);
|
|
276
|
+
} else if (error.code === STORE_ERROR_CODES.PARSE_ERROR) {
|
|
277
|
+
// JSON parsing failed or invalid format
|
|
278
|
+
console.error('Failed to parse service key:', error.filePath);
|
|
279
|
+
console.error('Cause:', error.cause);
|
|
280
|
+
} else if (error.code === STORE_ERROR_CODES.INVALID_CONFIG) {
|
|
281
|
+
// Required UAA fields missing - returns null instead of throwing
|
|
282
|
+
console.error('Invalid config:', error.missingFields);
|
|
283
|
+
} else if (error.code === STORE_ERROR_CODES.STORAGE_ERROR) {
|
|
284
|
+
// File write/permission error
|
|
285
|
+
console.error('Storage operation failed:', error.operation);
|
|
286
|
+
console.error('Cause:', error.cause);
|
|
287
|
+
} else {
|
|
288
|
+
// Generic error
|
|
289
|
+
console.error('Unexpected error:', error.message);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Error Types:**
|
|
295
|
+
- **`FileNotFoundError`** - Service key file not found (includes `filePath`)
|
|
296
|
+
- **`ParseError`** - JSON parsing failed or invalid format (includes `filePath` and `cause`)
|
|
297
|
+
- **`InvalidConfigError`** - Required configuration fields missing (includes `missingFields` array)
|
|
298
|
+
- **`StorageError`** - File write or permission error (includes `operation` and `cause`)
|
|
299
|
+
|
|
300
|
+
**Note**: Most errors result in `null` return values rather than exceptions. Only fatal errors (like JSON parsing failures) throw exceptions.
|
|
301
|
+
|
|
302
|
+
## File Handlers
|
|
303
|
+
|
|
201
304
|
Utility classes for working with files:
|
|
202
305
|
|
|
203
306
|
### JsonFileHandler
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store error codes and typed error classes
|
|
3
|
+
*/
|
|
4
|
+
import { type StoreErrorCode } from '@mcp-abap-adt/interfaces';
|
|
5
|
+
/**
|
|
6
|
+
* Base error class for all store errors
|
|
7
|
+
*/
|
|
8
|
+
export declare class StoreError extends Error {
|
|
9
|
+
readonly code: StoreErrorCode;
|
|
10
|
+
constructor(message: string, code: StoreErrorCode);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when a file is not found
|
|
14
|
+
*/
|
|
15
|
+
export declare class FileNotFoundError extends StoreError {
|
|
16
|
+
readonly filePath: string;
|
|
17
|
+
constructor(filePath: string, message?: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when a file cannot be parsed (invalid JSON, YAML, etc.)
|
|
21
|
+
*/
|
|
22
|
+
export declare class ParseError extends StoreError {
|
|
23
|
+
readonly filePath?: string;
|
|
24
|
+
readonly cause?: Error;
|
|
25
|
+
constructor(message: string, filePath?: string, cause?: Error);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown when required configuration fields are missing
|
|
29
|
+
*/
|
|
30
|
+
export declare class InvalidConfigError extends StoreError {
|
|
31
|
+
readonly missingFields: string[];
|
|
32
|
+
constructor(message: string, missingFields?: string[]);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Error thrown when storage operations fail (file write, permission denied, etc.)
|
|
36
|
+
*/
|
|
37
|
+
export declare class StorageError extends StoreError {
|
|
38
|
+
readonly operation: string;
|
|
39
|
+
readonly cause?: Error;
|
|
40
|
+
constructor(operation: string, message: string, cause?: Error);
|
|
41
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Store error codes and typed error classes
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StorageError = exports.InvalidConfigError = exports.ParseError = exports.FileNotFoundError = exports.StoreError = void 0;
|
|
7
|
+
const interfaces_1 = require("@mcp-abap-adt/interfaces");
|
|
8
|
+
/**
|
|
9
|
+
* Base error class for all store errors
|
|
10
|
+
*/
|
|
11
|
+
class StoreError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
constructor(message, code) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'StoreError';
|
|
16
|
+
this.code = code;
|
|
17
|
+
Object.setPrototypeOf(this, StoreError.prototype);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.StoreError = StoreError;
|
|
21
|
+
/**
|
|
22
|
+
* Error thrown when a file is not found
|
|
23
|
+
*/
|
|
24
|
+
class FileNotFoundError extends StoreError {
|
|
25
|
+
filePath;
|
|
26
|
+
constructor(filePath, message) {
|
|
27
|
+
super(message || `File not found: ${filePath}`, interfaces_1.STORE_ERROR_CODES.FILE_NOT_FOUND);
|
|
28
|
+
this.name = 'FileNotFoundError';
|
|
29
|
+
this.filePath = filePath;
|
|
30
|
+
Object.setPrototypeOf(this, FileNotFoundError.prototype);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.FileNotFoundError = FileNotFoundError;
|
|
34
|
+
/**
|
|
35
|
+
* Error thrown when a file cannot be parsed (invalid JSON, YAML, etc.)
|
|
36
|
+
*/
|
|
37
|
+
class ParseError extends StoreError {
|
|
38
|
+
filePath;
|
|
39
|
+
cause;
|
|
40
|
+
constructor(message, filePath, cause) {
|
|
41
|
+
super(message, interfaces_1.STORE_ERROR_CODES.PARSE_ERROR);
|
|
42
|
+
this.name = 'ParseError';
|
|
43
|
+
this.filePath = filePath;
|
|
44
|
+
this.cause = cause;
|
|
45
|
+
Object.setPrototypeOf(this, ParseError.prototype);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ParseError = ParseError;
|
|
49
|
+
/**
|
|
50
|
+
* Error thrown when required configuration fields are missing
|
|
51
|
+
*/
|
|
52
|
+
class InvalidConfigError extends StoreError {
|
|
53
|
+
missingFields;
|
|
54
|
+
constructor(message, missingFields = []) {
|
|
55
|
+
super(message, interfaces_1.STORE_ERROR_CODES.INVALID_CONFIG);
|
|
56
|
+
this.name = 'InvalidConfigError';
|
|
57
|
+
this.missingFields = missingFields;
|
|
58
|
+
Object.setPrototypeOf(this, InvalidConfigError.prototype);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.InvalidConfigError = InvalidConfigError;
|
|
62
|
+
/**
|
|
63
|
+
* Error thrown when storage operations fail (file write, permission denied, etc.)
|
|
64
|
+
*/
|
|
65
|
+
class StorageError extends StoreError {
|
|
66
|
+
operation;
|
|
67
|
+
cause;
|
|
68
|
+
constructor(operation, message, cause) {
|
|
69
|
+
super(message, interfaces_1.STORE_ERROR_CODES.STORAGE_ERROR);
|
|
70
|
+
this.name = 'StorageError';
|
|
71
|
+
this.operation = operation;
|
|
72
|
+
this.cause = cause;
|
|
73
|
+
Object.setPrototypeOf(this, StorageError.prototype);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.StorageError = StorageError;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export { AbapServiceKeyStore } from './stores/abap/AbapServiceKeyStore';
|
|
|
13
13
|
export { XsuaaSessionStore } from './stores/xsuaa/XsuaaSessionStore';
|
|
14
14
|
export { SafeXsuaaSessionStore } from './stores/xsuaa/SafeXsuaaSessionStore';
|
|
15
15
|
export { XsuaaServiceKeyStore } from './stores/xsuaa/XsuaaServiceKeyStore';
|
|
16
|
+
export { EnvFileSessionStore } from './stores/env/EnvFileSessionStore';
|
|
17
|
+
export { StoreError, FileNotFoundError, ParseError, InvalidConfigError, StorageError } from './errors/StoreErrors';
|
|
16
18
|
export { resolveSearchPaths, findFileInPaths } from './utils/pathResolver';
|
|
17
19
|
export { JsonFileHandler } from './utils/JsonFileHandler';
|
|
18
20
|
export { EnvFileHandler } from './utils/EnvFileHandler';
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Provides BTP, ABAP, and XSUAA store implementations
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.loadXSUAAServiceKey = exports.loadServiceKey = exports.XSUAA_CONNECTION_VARS = exports.XSUAA_AUTHORIZATION_VARS = exports.BTP_CONNECTION_VARS = exports.BTP_AUTHORIZATION_VARS = exports.ABAP_CONNECTION_VARS = exports.ABAP_AUTHORIZATION_VARS = exports.EnvFileHandler = exports.JsonFileHandler = exports.findFileInPaths = exports.resolveSearchPaths = exports.XsuaaServiceKeyStore = exports.SafeXsuaaSessionStore = exports.XsuaaSessionStore = exports.AbapServiceKeyStore = exports.SafeAbapSessionStore = exports.AbapSessionStore = exports.BtpServiceKeyStore = exports.SafeBtpSessionStore = exports.BtpSessionStore = void 0;
|
|
9
|
+
exports.loadXSUAAServiceKey = exports.loadServiceKey = exports.XSUAA_CONNECTION_VARS = exports.XSUAA_AUTHORIZATION_VARS = exports.BTP_CONNECTION_VARS = exports.BTP_AUTHORIZATION_VARS = exports.ABAP_CONNECTION_VARS = exports.ABAP_AUTHORIZATION_VARS = exports.EnvFileHandler = exports.JsonFileHandler = exports.findFileInPaths = exports.resolveSearchPaths = exports.StorageError = exports.InvalidConfigError = exports.ParseError = exports.FileNotFoundError = exports.StoreError = exports.EnvFileSessionStore = exports.XsuaaServiceKeyStore = exports.SafeXsuaaSessionStore = exports.XsuaaSessionStore = exports.AbapServiceKeyStore = exports.SafeAbapSessionStore = exports.AbapSessionStore = exports.BtpServiceKeyStore = exports.SafeBtpSessionStore = exports.BtpSessionStore = void 0;
|
|
10
10
|
// BTP stores (base BTP without sapUrl)
|
|
11
11
|
var BtpSessionStore_1 = require("./stores/btp/BtpSessionStore");
|
|
12
12
|
Object.defineProperty(exports, "BtpSessionStore", { enumerable: true, get: function () { return BtpSessionStore_1.BtpSessionStore; } });
|
|
@@ -28,6 +28,16 @@ var SafeXsuaaSessionStore_1 = require("./stores/xsuaa/SafeXsuaaSessionStore");
|
|
|
28
28
|
Object.defineProperty(exports, "SafeXsuaaSessionStore", { enumerable: true, get: function () { return SafeXsuaaSessionStore_1.SafeXsuaaSessionStore; } });
|
|
29
29
|
var XsuaaServiceKeyStore_1 = require("./stores/xsuaa/XsuaaServiceKeyStore");
|
|
30
30
|
Object.defineProperty(exports, "XsuaaServiceKeyStore", { enumerable: true, get: function () { return XsuaaServiceKeyStore_1.XsuaaServiceKeyStore; } });
|
|
31
|
+
// Env file stores (for --env=path scenarios)
|
|
32
|
+
var EnvFileSessionStore_1 = require("./stores/env/EnvFileSessionStore");
|
|
33
|
+
Object.defineProperty(exports, "EnvFileSessionStore", { enumerable: true, get: function () { return EnvFileSessionStore_1.EnvFileSessionStore; } });
|
|
34
|
+
// Error classes
|
|
35
|
+
var StoreErrors_1 = require("./errors/StoreErrors");
|
|
36
|
+
Object.defineProperty(exports, "StoreError", { enumerable: true, get: function () { return StoreErrors_1.StoreError; } });
|
|
37
|
+
Object.defineProperty(exports, "FileNotFoundError", { enumerable: true, get: function () { return StoreErrors_1.FileNotFoundError; } });
|
|
38
|
+
Object.defineProperty(exports, "ParseError", { enumerable: true, get: function () { return StoreErrors_1.ParseError; } });
|
|
39
|
+
Object.defineProperty(exports, "InvalidConfigError", { enumerable: true, get: function () { return StoreErrors_1.InvalidConfigError; } });
|
|
40
|
+
Object.defineProperty(exports, "StorageError", { enumerable: true, get: function () { return StoreErrors_1.StorageError; } });
|
|
31
41
|
// Utils
|
|
32
42
|
var pathResolver_1 = require("./utils/pathResolver");
|
|
33
43
|
Object.defineProperty(exports, "resolveSearchPaths", { enumerable: true, get: function () { return pathResolver_1.resolveSearchPaths; } });
|
|
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.AbapServiceKeyStore = void 0;
|
|
40
40
|
const JsonFileHandler_1 = require("../../utils/JsonFileHandler");
|
|
41
41
|
const AbapServiceKeyParser_1 = require("../../parsers/abap/AbapServiceKeyParser");
|
|
42
|
+
const StoreErrors_1 = require("../../errors/StoreErrors");
|
|
42
43
|
const path = __importStar(require("path"));
|
|
43
44
|
/**
|
|
44
45
|
* ABAP Service key store implementation
|
|
@@ -112,7 +113,7 @@ class AbapServiceKeyStore {
|
|
|
112
113
|
}
|
|
113
114
|
catch (error) {
|
|
114
115
|
this.log?.error(`Failed to parse service key from ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
115
|
-
throw new
|
|
116
|
+
throw new StoreErrors_1.ParseError(`Failed to parse service key for destination "${destination}"`, filePath, error instanceof Error ? error : undefined);
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
/**
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.BtpServiceKeyStore = void 0;
|
|
7
7
|
const JsonFileHandler_1 = require("../../utils/JsonFileHandler");
|
|
8
8
|
const XsuaaServiceKeyParser_1 = require("../../parsers/xsuaa/XsuaaServiceKeyParser");
|
|
9
|
+
const StoreErrors_1 = require("../../errors/StoreErrors");
|
|
9
10
|
/**
|
|
10
11
|
* Base BTP Service key store implementation
|
|
11
12
|
*
|
|
@@ -73,7 +74,7 @@ class BtpServiceKeyStore {
|
|
|
73
74
|
}
|
|
74
75
|
catch (error) {
|
|
75
76
|
this.log?.error(`Failed to parse service key for ${destination}: ${error instanceof Error ? error.message : String(error)}`);
|
|
76
|
-
throw new
|
|
77
|
+
throw new StoreErrors_1.ParseError(`Failed to parse service key for destination "${destination}"`, `${destination}.json`, error instanceof Error ? error : undefined);
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env File Session Store - reads session from a specific .env file
|
|
3
|
+
*
|
|
4
|
+
* This store reads connection configuration from a .env file at a specified path.
|
|
5
|
+
* Unlike other stores that work with directories, this one works with a single file.
|
|
6
|
+
*
|
|
7
|
+
* Use case: `mcp-abap-adt --env=/path/to/.env`
|
|
8
|
+
*
|
|
9
|
+
* The store is READ-ONLY for connection config (writes only update in-memory state).
|
|
10
|
+
* For token refresh scenarios (JWT), the in-memory state is used.
|
|
11
|
+
*/
|
|
12
|
+
import type { ISessionStore, IConnectionConfig, IAuthorizationConfig, IConfig, ILogger } from '@mcp-abap-adt/interfaces';
|
|
13
|
+
/**
|
|
14
|
+
* Session store that reads from a specific .env file
|
|
15
|
+
*/
|
|
16
|
+
export declare class EnvFileSessionStore implements ISessionStore {
|
|
17
|
+
private envFilePath;
|
|
18
|
+
private log?;
|
|
19
|
+
private loadedData;
|
|
20
|
+
private inMemoryUpdates;
|
|
21
|
+
/**
|
|
22
|
+
* Create a new EnvFileSessionStore
|
|
23
|
+
* @param envFilePath Absolute path to the .env file
|
|
24
|
+
* @param log Optional logger
|
|
25
|
+
*/
|
|
26
|
+
constructor(envFilePath: string, log?: ILogger);
|
|
27
|
+
/**
|
|
28
|
+
* Get the auth type from the loaded .env file
|
|
29
|
+
*/
|
|
30
|
+
getAuthType(): 'basic' | 'jwt' | null;
|
|
31
|
+
/**
|
|
32
|
+
* Parse .env file content into key-value pairs
|
|
33
|
+
*/
|
|
34
|
+
private parseEnvContent;
|
|
35
|
+
/**
|
|
36
|
+
* Load and parse the .env file
|
|
37
|
+
*/
|
|
38
|
+
private loadEnvFile;
|
|
39
|
+
/**
|
|
40
|
+
* Convert internal format to IConfig
|
|
41
|
+
*/
|
|
42
|
+
private toIConfig;
|
|
43
|
+
loadSession(destination: string): Promise<IConfig | null>;
|
|
44
|
+
saveSession(destination: string, config: IConfig): Promise<void>;
|
|
45
|
+
getConnectionConfig(destination: string): Promise<IConnectionConfig | null>;
|
|
46
|
+
setConnectionConfig(destination: string, config: IConnectionConfig): Promise<void>;
|
|
47
|
+
getAuthorizationConfig(destination: string): Promise<IAuthorizationConfig | null>;
|
|
48
|
+
setAuthorizationConfig(destination: string, config: IAuthorizationConfig): Promise<void>;
|
|
49
|
+
getToken(destination: string): Promise<string | undefined>;
|
|
50
|
+
setToken(destination: string, token: string): Promise<void>;
|
|
51
|
+
getRefreshToken(destination: string): Promise<string | undefined>;
|
|
52
|
+
setRefreshToken(destination: string, refreshToken: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Clear in-memory updates (useful for testing)
|
|
55
|
+
*/
|
|
56
|
+
clear(): void;
|
|
57
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Env File Session Store - reads session from a specific .env file
|
|
4
|
+
*
|
|
5
|
+
* This store reads connection configuration from a .env file at a specified path.
|
|
6
|
+
* Unlike other stores that work with directories, this one works with a single file.
|
|
7
|
+
*
|
|
8
|
+
* Use case: `mcp-abap-adt --env=/path/to/.env`
|
|
9
|
+
*
|
|
10
|
+
* The store is READ-ONLY for connection config (writes only update in-memory state).
|
|
11
|
+
* For token refresh scenarios (JWT), the in-memory state is used.
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.EnvFileSessionStore = void 0;
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
/**
|
|
51
|
+
* Session store that reads from a specific .env file
|
|
52
|
+
*/
|
|
53
|
+
class EnvFileSessionStore {
|
|
54
|
+
envFilePath;
|
|
55
|
+
log;
|
|
56
|
+
loadedData = null;
|
|
57
|
+
inMemoryUpdates = new Map();
|
|
58
|
+
/**
|
|
59
|
+
* Create a new EnvFileSessionStore
|
|
60
|
+
* @param envFilePath Absolute path to the .env file
|
|
61
|
+
* @param log Optional logger
|
|
62
|
+
*/
|
|
63
|
+
constructor(envFilePath, log) {
|
|
64
|
+
this.envFilePath = path.resolve(envFilePath);
|
|
65
|
+
this.log = log;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get the auth type from the loaded .env file
|
|
69
|
+
*/
|
|
70
|
+
getAuthType() {
|
|
71
|
+
if (!this.loadedData) {
|
|
72
|
+
this.loadEnvFile();
|
|
73
|
+
}
|
|
74
|
+
return this.loadedData?.authType || null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Parse .env file content into key-value pairs
|
|
78
|
+
*/
|
|
79
|
+
parseEnvContent(content) {
|
|
80
|
+
const envVars = {};
|
|
81
|
+
for (const line of content.split(/\r?\n/)) {
|
|
82
|
+
const trimmed = line.trim();
|
|
83
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
84
|
+
continue;
|
|
85
|
+
const eqIndex = trimmed.indexOf('=');
|
|
86
|
+
if (eqIndex === -1)
|
|
87
|
+
continue;
|
|
88
|
+
const key = trimmed.substring(0, eqIndex).trim();
|
|
89
|
+
let value = trimmed.substring(eqIndex + 1);
|
|
90
|
+
// Remove inline comments (but be careful with URLs containing #)
|
|
91
|
+
// Only remove # comments that are preceded by whitespace
|
|
92
|
+
const commentMatch = value.match(/\s+#/);
|
|
93
|
+
if (commentMatch) {
|
|
94
|
+
value = value.substring(0, commentMatch.index).trim();
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
value = value.trim();
|
|
98
|
+
}
|
|
99
|
+
// Remove surrounding quotes
|
|
100
|
+
value = value.replace(/^["']+|["']+$/g, '').trim();
|
|
101
|
+
if (key) {
|
|
102
|
+
envVars[key] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return envVars;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Load and parse the .env file
|
|
109
|
+
*/
|
|
110
|
+
loadEnvFile() {
|
|
111
|
+
if (this.loadedData) {
|
|
112
|
+
return this.loadedData;
|
|
113
|
+
}
|
|
114
|
+
if (!fs.existsSync(this.envFilePath)) {
|
|
115
|
+
this.log?.error(`EnvFileSessionStore: .env file not found: ${this.envFilePath}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const content = fs.readFileSync(this.envFilePath, 'utf8');
|
|
120
|
+
const envVars = this.parseEnvContent(content);
|
|
121
|
+
// Validate required fields
|
|
122
|
+
if (!envVars.SAP_URL) {
|
|
123
|
+
this.log?.error(`EnvFileSessionStore: .env file missing SAP_URL`);
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const authType = (envVars.SAP_AUTH_TYPE || 'basic');
|
|
127
|
+
const data = {
|
|
128
|
+
serviceUrl: envVars.SAP_URL,
|
|
129
|
+
sapClient: envVars.SAP_CLIENT,
|
|
130
|
+
authType,
|
|
131
|
+
};
|
|
132
|
+
if (authType === 'basic') {
|
|
133
|
+
if (!envVars.SAP_USERNAME || !envVars.SAP_PASSWORD) {
|
|
134
|
+
this.log?.error(`EnvFileSessionStore: .env file missing SAP_USERNAME or SAP_PASSWORD for basic auth`);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
data.username = envVars.SAP_USERNAME;
|
|
138
|
+
data.password = envVars.SAP_PASSWORD;
|
|
139
|
+
}
|
|
140
|
+
else if (authType === 'jwt') {
|
|
141
|
+
if (!envVars.SAP_JWT_TOKEN) {
|
|
142
|
+
this.log?.error(`EnvFileSessionStore: .env file missing SAP_JWT_TOKEN for JWT auth`);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
data.jwtToken = envVars.SAP_JWT_TOKEN;
|
|
146
|
+
data.refreshToken = envVars.SAP_REFRESH_TOKEN;
|
|
147
|
+
data.uaaUrl = envVars.SAP_UAA_URL;
|
|
148
|
+
data.uaaClientId = envVars.SAP_UAA_CLIENT_ID;
|
|
149
|
+
data.uaaClientSecret = envVars.SAP_UAA_CLIENT_SECRET;
|
|
150
|
+
}
|
|
151
|
+
this.loadedData = data;
|
|
152
|
+
this.log?.debug(`EnvFileSessionStore: loaded .env file`, {
|
|
153
|
+
serviceUrl: data.serviceUrl,
|
|
154
|
+
authType: data.authType
|
|
155
|
+
});
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
this.log?.error(`EnvFileSessionStore: failed to read .env file`, {
|
|
160
|
+
error: error instanceof Error ? error.message : String(error)
|
|
161
|
+
});
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Convert internal format to IConfig
|
|
167
|
+
*/
|
|
168
|
+
toIConfig(data) {
|
|
169
|
+
const config = {
|
|
170
|
+
serviceUrl: data.serviceUrl,
|
|
171
|
+
sapClient: data.sapClient,
|
|
172
|
+
authType: data.authType,
|
|
173
|
+
};
|
|
174
|
+
if (data.authType === 'basic') {
|
|
175
|
+
config.username = data.username;
|
|
176
|
+
config.password = data.password;
|
|
177
|
+
}
|
|
178
|
+
else if (data.authType === 'jwt') {
|
|
179
|
+
config.authorizationToken = data.jwtToken;
|
|
180
|
+
config.refreshToken = data.refreshToken;
|
|
181
|
+
config.uaaUrl = data.uaaUrl;
|
|
182
|
+
config.uaaClientId = data.uaaClientId;
|
|
183
|
+
config.uaaClientSecret = data.uaaClientSecret;
|
|
184
|
+
}
|
|
185
|
+
return config;
|
|
186
|
+
}
|
|
187
|
+
// ============================================================================
|
|
188
|
+
// ISessionStore implementation
|
|
189
|
+
// ============================================================================
|
|
190
|
+
async loadSession(destination) {
|
|
191
|
+
// Check in-memory updates first (for token refresh)
|
|
192
|
+
const updated = this.inMemoryUpdates.get(destination);
|
|
193
|
+
if (updated) {
|
|
194
|
+
return this.toIConfig(updated);
|
|
195
|
+
}
|
|
196
|
+
// Load from .env file
|
|
197
|
+
const data = this.loadEnvFile();
|
|
198
|
+
if (!data)
|
|
199
|
+
return null;
|
|
200
|
+
return this.toIConfig(data);
|
|
201
|
+
}
|
|
202
|
+
async saveSession(destination, config) {
|
|
203
|
+
// Save to in-memory only (don't overwrite .env file)
|
|
204
|
+
const data = {
|
|
205
|
+
serviceUrl: config.serviceUrl || this.loadedData?.serviceUrl || '',
|
|
206
|
+
sapClient: config.sapClient || this.loadedData?.sapClient,
|
|
207
|
+
authType: config.authType || this.loadedData?.authType || 'basic',
|
|
208
|
+
username: config.username,
|
|
209
|
+
password: config.password,
|
|
210
|
+
jwtToken: config.authorizationToken,
|
|
211
|
+
refreshToken: config.refreshToken,
|
|
212
|
+
uaaUrl: config.uaaUrl,
|
|
213
|
+
uaaClientId: config.uaaClientId,
|
|
214
|
+
uaaClientSecret: config.uaaClientSecret,
|
|
215
|
+
};
|
|
216
|
+
this.inMemoryUpdates.set(destination, data);
|
|
217
|
+
this.log?.debug(`EnvFileSessionStore: saved session to memory`, { destination });
|
|
218
|
+
}
|
|
219
|
+
async getConnectionConfig(destination) {
|
|
220
|
+
// Check in-memory updates first
|
|
221
|
+
const updated = this.inMemoryUpdates.get(destination);
|
|
222
|
+
if (updated) {
|
|
223
|
+
return {
|
|
224
|
+
serviceUrl: updated.serviceUrl,
|
|
225
|
+
sapClient: updated.sapClient,
|
|
226
|
+
authType: updated.authType,
|
|
227
|
+
username: updated.username,
|
|
228
|
+
password: updated.password,
|
|
229
|
+
authorizationToken: updated.jwtToken,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const data = this.loadEnvFile();
|
|
233
|
+
if (!data)
|
|
234
|
+
return null;
|
|
235
|
+
return {
|
|
236
|
+
serviceUrl: data.serviceUrl,
|
|
237
|
+
sapClient: data.sapClient,
|
|
238
|
+
authType: data.authType,
|
|
239
|
+
username: data.username,
|
|
240
|
+
password: data.password,
|
|
241
|
+
authorizationToken: data.jwtToken,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async setConnectionConfig(destination, config) {
|
|
245
|
+
// Store in memory (merge with existing data)
|
|
246
|
+
const existing = this.inMemoryUpdates.get(destination) || this.loadEnvFile() || {};
|
|
247
|
+
const data = {
|
|
248
|
+
...existing,
|
|
249
|
+
serviceUrl: config.serviceUrl || existing.serviceUrl,
|
|
250
|
+
sapClient: config.sapClient || existing.sapClient,
|
|
251
|
+
authType: config.authType || existing.authType || 'basic',
|
|
252
|
+
username: config.username || existing.username,
|
|
253
|
+
password: config.password || existing.password,
|
|
254
|
+
jwtToken: config.authorizationToken || existing.jwtToken,
|
|
255
|
+
};
|
|
256
|
+
this.inMemoryUpdates.set(destination, data);
|
|
257
|
+
this.log?.debug(`EnvFileSessionStore: set connection config`, { destination, serviceUrl: data.serviceUrl });
|
|
258
|
+
}
|
|
259
|
+
async getAuthorizationConfig(destination) {
|
|
260
|
+
// Check in-memory updates first
|
|
261
|
+
const updated = this.inMemoryUpdates.get(destination);
|
|
262
|
+
if (updated && updated.authType === 'jwt') {
|
|
263
|
+
return {
|
|
264
|
+
uaaUrl: updated.uaaUrl || '',
|
|
265
|
+
uaaClientId: updated.uaaClientId || '',
|
|
266
|
+
uaaClientSecret: updated.uaaClientSecret || '',
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const data = this.loadEnvFile();
|
|
270
|
+
if (!data || data.authType !== 'jwt')
|
|
271
|
+
return null;
|
|
272
|
+
return {
|
|
273
|
+
uaaUrl: data.uaaUrl || '',
|
|
274
|
+
uaaClientId: data.uaaClientId || '',
|
|
275
|
+
uaaClientSecret: data.uaaClientSecret || '',
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
async setAuthorizationConfig(destination, config) {
|
|
279
|
+
const existing = this.inMemoryUpdates.get(destination) || this.loadEnvFile() || {};
|
|
280
|
+
const data = {
|
|
281
|
+
...existing,
|
|
282
|
+
serviceUrl: existing.serviceUrl || '',
|
|
283
|
+
authType: existing.authType || 'jwt',
|
|
284
|
+
uaaUrl: config.uaaUrl,
|
|
285
|
+
uaaClientId: config.uaaClientId,
|
|
286
|
+
uaaClientSecret: config.uaaClientSecret,
|
|
287
|
+
};
|
|
288
|
+
this.inMemoryUpdates.set(destination, data);
|
|
289
|
+
this.log?.debug(`EnvFileSessionStore: set authorization config`, { destination });
|
|
290
|
+
}
|
|
291
|
+
async getToken(destination) {
|
|
292
|
+
// Check in-memory updates first (refreshed token)
|
|
293
|
+
const updated = this.inMemoryUpdates.get(destination);
|
|
294
|
+
if (updated?.jwtToken) {
|
|
295
|
+
return updated.jwtToken;
|
|
296
|
+
}
|
|
297
|
+
const data = this.loadEnvFile();
|
|
298
|
+
return data?.jwtToken;
|
|
299
|
+
}
|
|
300
|
+
async setToken(destination, token) {
|
|
301
|
+
const existing = this.inMemoryUpdates.get(destination) || this.loadEnvFile() || {};
|
|
302
|
+
const data = {
|
|
303
|
+
...existing,
|
|
304
|
+
serviceUrl: existing.serviceUrl || '',
|
|
305
|
+
authType: 'jwt',
|
|
306
|
+
jwtToken: token,
|
|
307
|
+
};
|
|
308
|
+
this.inMemoryUpdates.set(destination, data);
|
|
309
|
+
this.log?.debug(`EnvFileSessionStore: set token`, { destination });
|
|
310
|
+
}
|
|
311
|
+
async getRefreshToken(destination) {
|
|
312
|
+
const updated = this.inMemoryUpdates.get(destination);
|
|
313
|
+
if (updated?.refreshToken) {
|
|
314
|
+
return updated.refreshToken;
|
|
315
|
+
}
|
|
316
|
+
const data = this.loadEnvFile();
|
|
317
|
+
return data?.refreshToken;
|
|
318
|
+
}
|
|
319
|
+
async setRefreshToken(destination, refreshToken) {
|
|
320
|
+
const existing = this.inMemoryUpdates.get(destination) || this.loadEnvFile() || {};
|
|
321
|
+
const data = {
|
|
322
|
+
...existing,
|
|
323
|
+
serviceUrl: existing.serviceUrl || '',
|
|
324
|
+
authType: 'jwt',
|
|
325
|
+
refreshToken,
|
|
326
|
+
};
|
|
327
|
+
this.inMemoryUpdates.set(destination, data);
|
|
328
|
+
this.log?.debug(`EnvFileSessionStore: set refresh token`, { destination });
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Clear in-memory updates (useful for testing)
|
|
332
|
+
*/
|
|
333
|
+
clear() {
|
|
334
|
+
this.inMemoryUpdates.clear();
|
|
335
|
+
this.loadedData = null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
exports.EnvFileSessionStore = EnvFileSessionStore;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.XsuaaServiceKeyStore = void 0;
|
|
7
7
|
const JsonFileHandler_1 = require("../../utils/JsonFileHandler");
|
|
8
8
|
const XsuaaServiceKeyParser_1 = require("../../parsers/xsuaa/XsuaaServiceKeyParser");
|
|
9
|
+
const StoreErrors_1 = require("../../errors/StoreErrors");
|
|
9
10
|
/**
|
|
10
11
|
* XSUAA Service key store implementation
|
|
11
12
|
*
|
|
@@ -73,7 +74,7 @@ class XsuaaServiceKeyStore {
|
|
|
73
74
|
}
|
|
74
75
|
catch (error) {
|
|
75
76
|
this.log?.error(`Failed to parse service key for ${destination}: ${error instanceof Error ? error.message : String(error)}`);
|
|
76
|
-
throw new
|
|
77
|
+
throw new StoreErrors_1.ParseError(`Failed to parse service key for destination "${destination}"`, `${destination}.json`, error instanceof Error ? error : undefined);
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
@@ -107,7 +108,7 @@ class XsuaaServiceKeyStore {
|
|
|
107
108
|
}
|
|
108
109
|
catch (error) {
|
|
109
110
|
this.log?.error(`Failed to parse service key for ${destination}: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
|
-
throw new
|
|
111
|
+
throw new StoreErrors_1.ParseError(`Failed to parse service key for destination "${destination}"`, `${destination}.json`, error instanceof Error ? error : undefined);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/auth-stores",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Stores for MCP ABAP ADT auth-broker - BTP, ABAP, and XSUAA implementations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"node": ">=18.0.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@mcp-abap-adt/interfaces": "^0.
|
|
52
|
+
"@mcp-abap-adt/interfaces": "^0.2.3",
|
|
53
53
|
"dotenv": "^17.2.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|