@mcp-abap-adt/auth-stores 0.2.1 → 0.2.5
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 +46 -0
- package/README.md +52 -0
- package/dist/errors/StoreErrors.d.ts +41 -0
- package/dist/errors/StoreErrors.js +76 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -1
- package/dist/storage/abap/envLoader.d.ts +4 -1
- package/dist/storage/abap/envLoader.js +32 -6
- package/dist/storage/abap/tokenStorage.d.ts +6 -3
- package/dist/storage/abap/tokenStorage.js +25 -5
- package/dist/stores/abap/AbapServiceKeyStore.js +2 -1
- package/dist/stores/abap/AbapSessionStore.js +82 -11
- package/dist/stores/abap/SafeAbapSessionStore.js +38 -5
- package/dist/stores/btp/BtpServiceKeyStore.js +2 -1
- package/dist/stores/xsuaa/XsuaaServiceKeyStore.js +3 -2
- package/dist/utils/constants.d.ts +4 -0
- package/dist/utils/constants.js +4 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.5] - 2025-12-19
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **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.
|
|
14
|
+
|
|
15
|
+
## [0.2.4] - 2025-12-19
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Typed Error Classes**: Added typed error classes for better error handling in auth-broker
|
|
19
|
+
- `StoreError` - Base error class with error code
|
|
20
|
+
- `FileNotFoundError` - File not found errors (includes filePath)
|
|
21
|
+
- `ParseError` - JSON/YAML parsing errors (includes filePath and cause)
|
|
22
|
+
- `InvalidConfigError` - Missing required config fields (includes missingFields array)
|
|
23
|
+
- `StorageError` - File write/permission errors (includes operation and cause)
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- **Service Key Stores**: Now throw typed errors instead of generic Error
|
|
27
|
+
- `FileNotFoundError` when service key file not found (returns null)
|
|
28
|
+
- `ParseError` when JSON parsing fails or format is invalid
|
|
29
|
+
- `InvalidConfigError` when required UAA fields are missing (returns null)
|
|
30
|
+
- **Dependency**: Updated `@mcp-abap-adt/interfaces` to `^0.2.3` for STORE_ERROR_CODES
|
|
31
|
+
|
|
32
|
+
## [0.2.3] - 2025-12-16
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- Dependency bump: `@mcp-abap-adt/interfaces` to `^0.1.17` for basic auth support
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- **Basic Authentication Support for On-Premise Systems**: Added support for basic auth (username/password) in addition to JWT tokens
|
|
39
|
+
- **envLoader.ts**: Now loads `SAP_USERNAME` and `SAP_PASSWORD` from `.env` files
|
|
40
|
+
- Automatically detects auth type: if username/password present and no JWT token, uses basic auth
|
|
41
|
+
- If JWT token present, uses JWT auth
|
|
42
|
+
- **AbapSessionStore.getConnectionConfig()**: Returns basic auth config when username/password are present
|
|
43
|
+
- Returns `IConnectionConfig` with `username`, `password`, and `authType: 'basic'` for on-premise systems
|
|
44
|
+
- Returns `IConnectionConfig` with `authorizationToken` and `authType: 'jwt'` for cloud systems
|
|
45
|
+
- **tokenStorage.ts**: Now saves `SAP_USERNAME` and `SAP_PASSWORD` to `.env` files
|
|
46
|
+
- Handles both JWT and basic auth configurations
|
|
47
|
+
- Clears username/password when JWT auth is used, and vice versa
|
|
48
|
+
- **constants.ts**: Added `USERNAME: 'SAP_USERNAME'` and `PASSWORD: 'SAP_PASSWORD'` to `ABAP_CONNECTION_VARS`
|
|
49
|
+
- This enables on-premise systems to use `--mcp` parameter with basic auth instead of requiring JWT tokens
|
|
50
|
+
|
|
51
|
+
## [0.2.2] - 2025-12-13
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
- Dependency bump: `@mcp-abap-adt/interfaces` to `^0.1.16` for alignment with latest interfaces docs
|
|
55
|
+
|
|
10
56
|
## [0.2.1] - 2025-12-12
|
|
11
57
|
|
|
12
58
|
### Changed
|
package/README.md
CHANGED
|
@@ -198,6 +198,58 @@ The `defaultServiceUrl` is used when creating new sessions via `setConnectionCon
|
|
|
198
198
|
|
|
199
199
|
## File Handlers
|
|
200
200
|
|
|
201
|
+
This package provides utility classes for safe file operations:
|
|
202
|
+
|
|
203
|
+
### Error Handling
|
|
204
|
+
|
|
205
|
+
All service key stores throw typed errors for better error handling:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import {
|
|
209
|
+
BtpServiceKeyStore,
|
|
210
|
+
FileNotFoundError,
|
|
211
|
+
ParseError,
|
|
212
|
+
InvalidConfigError
|
|
213
|
+
} from '@mcp-abap-adt/auth-stores';
|
|
214
|
+
import { STORE_ERROR_CODES } from '@mcp-abap-adt/interfaces';
|
|
215
|
+
|
|
216
|
+
const serviceKeyStore = new BtpServiceKeyStore('/path/to/keys');
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const authConfig = await serviceKeyStore.getAuthorizationConfig('TRIAL');
|
|
220
|
+
console.log('Auth config loaded:', authConfig);
|
|
221
|
+
} catch (error: any) {
|
|
222
|
+
if (error.code === STORE_ERROR_CODES.FILE_NOT_FOUND) {
|
|
223
|
+
// File not found - returns null instead of throwing
|
|
224
|
+
console.error('Service key file not found:', error.filePath);
|
|
225
|
+
} else if (error.code === STORE_ERROR_CODES.PARSE_ERROR) {
|
|
226
|
+
// JSON parsing failed or invalid format
|
|
227
|
+
console.error('Failed to parse service key:', error.filePath);
|
|
228
|
+
console.error('Cause:', error.cause);
|
|
229
|
+
} else if (error.code === STORE_ERROR_CODES.INVALID_CONFIG) {
|
|
230
|
+
// Required UAA fields missing - returns null instead of throwing
|
|
231
|
+
console.error('Invalid config:', error.missingFields);
|
|
232
|
+
} else if (error.code === STORE_ERROR_CODES.STORAGE_ERROR) {
|
|
233
|
+
// File write/permission error
|
|
234
|
+
console.error('Storage operation failed:', error.operation);
|
|
235
|
+
console.error('Cause:', error.cause);
|
|
236
|
+
} else {
|
|
237
|
+
// Generic error
|
|
238
|
+
console.error('Unexpected error:', error.message);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Error Types:**
|
|
244
|
+
- **`FileNotFoundError`** - Service key file not found (includes `filePath`)
|
|
245
|
+
- **`ParseError`** - JSON parsing failed or invalid format (includes `filePath` and `cause`)
|
|
246
|
+
- **`InvalidConfigError`** - Required configuration fields missing (includes `missingFields` array)
|
|
247
|
+
- **`StorageError`** - File write or permission error (includes `operation` and `cause`)
|
|
248
|
+
|
|
249
|
+
**Note**: Most errors result in `null` return values rather than exceptions. Only fatal errors (like JSON parsing failures) throw exceptions.
|
|
250
|
+
|
|
251
|
+
## File Handlers
|
|
252
|
+
|
|
201
253
|
Utility classes for working with files:
|
|
202
254
|
|
|
203
255
|
### 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,7 @@ 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 { StoreError, FileNotFoundError, ParseError, InvalidConfigError, StorageError } from './errors/StoreErrors';
|
|
16
17
|
export { resolveSearchPaths, findFileInPaths } from './utils/pathResolver';
|
|
17
18
|
export { JsonFileHandler } from './utils/JsonFileHandler';
|
|
18
19
|
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.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,13 @@ 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
|
+
// Error classes
|
|
32
|
+
var StoreErrors_1 = require("./errors/StoreErrors");
|
|
33
|
+
Object.defineProperty(exports, "StoreError", { enumerable: true, get: function () { return StoreErrors_1.StoreError; } });
|
|
34
|
+
Object.defineProperty(exports, "FileNotFoundError", { enumerable: true, get: function () { return StoreErrors_1.FileNotFoundError; } });
|
|
35
|
+
Object.defineProperty(exports, "ParseError", { enumerable: true, get: function () { return StoreErrors_1.ParseError; } });
|
|
36
|
+
Object.defineProperty(exports, "InvalidConfigError", { enumerable: true, get: function () { return StoreErrors_1.InvalidConfigError; } });
|
|
37
|
+
Object.defineProperty(exports, "StorageError", { enumerable: true, get: function () { return StoreErrors_1.StorageError; } });
|
|
31
38
|
// Utils
|
|
32
39
|
var pathResolver_1 = require("./utils/pathResolver");
|
|
33
40
|
Object.defineProperty(exports, "resolveSearchPaths", { enumerable: true, get: function () { return pathResolver_1.resolveSearchPaths; } });
|
|
@@ -5,7 +5,10 @@ import type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
|
5
5
|
interface EnvConfig {
|
|
6
6
|
sapUrl: string;
|
|
7
7
|
sapClient?: string;
|
|
8
|
-
jwtToken
|
|
8
|
+
jwtToken?: string;
|
|
9
|
+
username?: string;
|
|
10
|
+
password?: string;
|
|
11
|
+
authType?: 'basic' | 'jwt';
|
|
9
12
|
refreshToken?: string;
|
|
10
13
|
uaaUrl?: string;
|
|
11
14
|
uaaClientId?: string;
|
|
@@ -65,16 +65,38 @@ async function loadEnvFile(destination, directory, log) {
|
|
|
65
65
|
// Extract required fields
|
|
66
66
|
const sapUrl = parsed[constants_1.ABAP_CONNECTION_VARS.SERVICE_URL];
|
|
67
67
|
const jwtToken = parsed[constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN];
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
const username = parsed[constants_1.ABAP_CONNECTION_VARS.USERNAME];
|
|
69
|
+
const password = parsed[constants_1.ABAP_CONNECTION_VARS.PASSWORD];
|
|
70
|
+
log?.debug(`Extracted fields: hasSapUrl(${!!sapUrl}), hasJwtToken(${jwtToken !== undefined && jwtToken !== null}), hasUsername(${!!username}), hasPassword(${!!password})`);
|
|
71
|
+
// sapUrl is always required
|
|
72
|
+
if (!sapUrl) {
|
|
73
|
+
log?.warn(`Env file missing required field: sapUrl`);
|
|
72
74
|
return null;
|
|
73
75
|
}
|
|
76
|
+
// Determine auth type: if username/password present and no jwtToken, use basic auth
|
|
77
|
+
// If jwtToken present, use JWT auth
|
|
78
|
+
// If neither is present, it's OK - auth can be set later (e.g., via setAuthorizationConfig)
|
|
79
|
+
const isBasicAuth = !!(username && password) && (!jwtToken || jwtToken.trim() === '');
|
|
80
|
+
const isJwtAuth = !!(jwtToken && jwtToken.trim() !== '');
|
|
81
|
+
const hasNoAuth = !isBasicAuth && !isJwtAuth;
|
|
74
82
|
const config = {
|
|
75
83
|
sapUrl: sapUrl.trim(),
|
|
76
|
-
jwtToken: jwtToken.trim(), // Can be empty string for authorization-only sessions
|
|
77
84
|
};
|
|
85
|
+
// Set authentication fields based on type
|
|
86
|
+
if (isBasicAuth) {
|
|
87
|
+
config.username = username.trim();
|
|
88
|
+
config.password = password.trim();
|
|
89
|
+
config.authType = 'basic';
|
|
90
|
+
}
|
|
91
|
+
else if (isJwtAuth) {
|
|
92
|
+
config.jwtToken = jwtToken.trim();
|
|
93
|
+
config.authType = 'jwt';
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// No auth yet - will be set later (e.g., via setAuthorizationConfig)
|
|
97
|
+
config.jwtToken = jwtToken || '';
|
|
98
|
+
config.authType = undefined;
|
|
99
|
+
}
|
|
78
100
|
// Optional fields
|
|
79
101
|
if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT]) {
|
|
80
102
|
config.sapClient = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT].trim();
|
|
@@ -94,7 +116,11 @@ async function loadEnvFile(destination, directory, log) {
|
|
|
94
116
|
if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE]) {
|
|
95
117
|
config.language = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE].trim();
|
|
96
118
|
}
|
|
97
|
-
|
|
119
|
+
const tokenLength = config.jwtToken?.length || 0;
|
|
120
|
+
const authInfo = config.authType === 'basic'
|
|
121
|
+
? `basic auth (username: ${config.username})`
|
|
122
|
+
: `JWT token(${tokenLength} chars)`;
|
|
123
|
+
log?.info(`Env config loaded from ${envFilePath}: sapUrl(${config.sapUrl.substring(0, 50)}...), ${authInfo}, hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
98
124
|
return config;
|
|
99
125
|
}
|
|
100
126
|
catch (error) {
|
|
@@ -5,7 +5,10 @@ import type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
|
5
5
|
interface EnvConfig {
|
|
6
6
|
sapUrl: string;
|
|
7
7
|
sapClient?: string;
|
|
8
|
-
jwtToken
|
|
8
|
+
jwtToken?: string;
|
|
9
|
+
username?: string;
|
|
10
|
+
password?: string;
|
|
11
|
+
authType?: 'basic' | 'jwt';
|
|
9
12
|
refreshToken?: string;
|
|
10
13
|
uaaUrl?: string;
|
|
11
14
|
uaaClientId?: string;
|
|
@@ -20,7 +23,7 @@ interface EnvConfig {
|
|
|
20
23
|
* @param log Optional logger for logging operations
|
|
21
24
|
*/
|
|
22
25
|
export declare function saveTokenToEnv(destination: string, savePath: string, config: Partial<EnvConfig> & {
|
|
23
|
-
sapUrl
|
|
24
|
-
jwtToken
|
|
26
|
+
sapUrl: string;
|
|
27
|
+
jwtToken?: string;
|
|
25
28
|
}, log?: ILogger): Promise<void>;
|
|
26
29
|
export {};
|
|
@@ -51,7 +51,9 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
51
51
|
const envFilePath = path.join(savePath, `${destination}.env`);
|
|
52
52
|
const tempFilePath = `${envFilePath}.tmp`;
|
|
53
53
|
log?.debug(`Saving token to env file: ${envFilePath}`);
|
|
54
|
-
|
|
54
|
+
const tokenLength = config.jwtToken?.length || 0;
|
|
55
|
+
const hasBasicAuth = !!(config.username && config.password);
|
|
56
|
+
log?.debug(`Config to save: hasSapUrl(${!!config.sapUrl}), token(${tokenLength} chars), hasBasicAuth(${hasBasicAuth}), hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
55
57
|
// Ensure directory exists
|
|
56
58
|
if (!fs.existsSync(savePath)) {
|
|
57
59
|
log?.debug(`Creating directory: ${savePath}`);
|
|
@@ -83,10 +85,25 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
83
85
|
}
|
|
84
86
|
log?.debug(`Preserved ${existingVars.size} existing variables from env file`);
|
|
85
87
|
// Update with new values
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
// sapUrl is required - always save it
|
|
89
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SERVICE_URL, config.sapUrl);
|
|
90
|
+
// Handle authentication: JWT or basic auth
|
|
91
|
+
if (config.username && config.password) {
|
|
92
|
+
// Basic auth - save username/password
|
|
93
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.USERNAME, config.username);
|
|
94
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.PASSWORD, config.password);
|
|
95
|
+
// Clear JWT token if basic auth is used
|
|
96
|
+
if (config.jwtToken) {
|
|
97
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, '');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (config.jwtToken) {
|
|
101
|
+
// JWT auth - save token
|
|
102
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, config.jwtToken);
|
|
103
|
+
// Clear username/password if JWT auth is used
|
|
104
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.USERNAME);
|
|
105
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.PASSWORD);
|
|
88
106
|
}
|
|
89
|
-
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, config.jwtToken);
|
|
90
107
|
if (config.sapClient) {
|
|
91
108
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT, config.sapClient);
|
|
92
109
|
}
|
|
@@ -120,5 +137,8 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
120
137
|
fs.writeFileSync(tempFilePath, envContent, 'utf8');
|
|
121
138
|
// Atomic rename
|
|
122
139
|
fs.renameSync(tempFilePath, envFilePath);
|
|
123
|
-
|
|
140
|
+
const authInfo = hasBasicAuth
|
|
141
|
+
? `basic auth (username: ${config.username})`
|
|
142
|
+
: `JWT token(${tokenLength} chars)`;
|
|
143
|
+
log?.info(`Token saved to ${envFilePath}: ${authInfo}, sapUrl(${config.sapUrl ? config.sapUrl.substring(0, 50) + '...' : 'none'}), variables(${envLines.length})`);
|
|
124
144
|
}
|
|
@@ -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
|
/**
|
|
@@ -94,9 +94,8 @@ class AbapSessionStore {
|
|
|
94
94
|
convertToInternalFormat(config) {
|
|
95
95
|
const obj = config;
|
|
96
96
|
// Convert IConfig format (serviceUrl, authorizationToken) to internal format (sapUrl, jwtToken)
|
|
97
|
-
|
|
97
|
+
const result = {
|
|
98
98
|
sapUrl: (obj.serviceUrl || obj.sapUrl),
|
|
99
|
-
jwtToken: (obj.authorizationToken || obj.jwtToken || ''), // Ensure jwtToken is always a string
|
|
100
99
|
refreshToken: obj.refreshToken,
|
|
101
100
|
uaaUrl: obj.uaaUrl,
|
|
102
101
|
uaaClientId: obj.uaaClientId,
|
|
@@ -104,6 +103,20 @@ class AbapSessionStore {
|
|
|
104
103
|
sapClient: obj.sapClient,
|
|
105
104
|
language: obj.language,
|
|
106
105
|
};
|
|
106
|
+
// Handle authentication: JWT or basic auth
|
|
107
|
+
if (obj.username && obj.password) {
|
|
108
|
+
// Basic auth
|
|
109
|
+
result.username = obj.username;
|
|
110
|
+
result.password = obj.password;
|
|
111
|
+
result.authType = 'basic';
|
|
112
|
+
result.jwtToken = obj.authorizationToken || obj.jwtToken || '';
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// JWT auth
|
|
116
|
+
result.jwtToken = (obj.authorizationToken || obj.jwtToken || '');
|
|
117
|
+
result.authType = 'jwt';
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
107
120
|
}
|
|
108
121
|
/**
|
|
109
122
|
* Save session to ENV file
|
|
@@ -125,6 +138,9 @@ class AbapSessionStore {
|
|
|
125
138
|
await (0, tokenStorage_1.saveTokenToEnv)(destination, savePath, {
|
|
126
139
|
sapUrl: abapConfig.sapUrl,
|
|
127
140
|
jwtToken: abapConfig.jwtToken,
|
|
141
|
+
username: abapConfig.username,
|
|
142
|
+
password: abapConfig.password,
|
|
143
|
+
authType: abapConfig.authType,
|
|
128
144
|
refreshToken: abapConfig.refreshToken,
|
|
129
145
|
uaaUrl: abapConfig.uaaUrl,
|
|
130
146
|
uaaClientId: abapConfig.uaaClientId,
|
|
@@ -193,6 +209,16 @@ class AbapSessionStore {
|
|
|
193
209
|
if (rawSession.jwtToken !== undefined) {
|
|
194
210
|
result.authorizationToken = rawSession.jwtToken;
|
|
195
211
|
}
|
|
212
|
+
// Basic auth fields (if present)
|
|
213
|
+
if (rawSession.username) {
|
|
214
|
+
result.username = rawSession.username;
|
|
215
|
+
}
|
|
216
|
+
if (rawSession.password) {
|
|
217
|
+
result.password = rawSession.password;
|
|
218
|
+
}
|
|
219
|
+
if (rawSession.authType) {
|
|
220
|
+
result.authType = rawSession.authType;
|
|
221
|
+
}
|
|
196
222
|
if (rawSession.sapClient) {
|
|
197
223
|
result.sapClient = rawSession.sapClient;
|
|
198
224
|
}
|
|
@@ -230,7 +256,7 @@ class AbapSessionStore {
|
|
|
230
256
|
try {
|
|
231
257
|
const raw = await this.loadFromFile(sessionPath);
|
|
232
258
|
if (!raw || !isEnvConfig(raw)) {
|
|
233
|
-
this.log?.debug(`Invalid session format for ${destination}: missing required
|
|
259
|
+
this.log?.debug(`Invalid session format for ${destination}: missing required field (sapUrl)`);
|
|
234
260
|
return null;
|
|
235
261
|
}
|
|
236
262
|
return raw;
|
|
@@ -276,14 +302,38 @@ class AbapSessionStore {
|
|
|
276
302
|
this.log?.debug(`Connection config not found for ${destination}`);
|
|
277
303
|
return null;
|
|
278
304
|
}
|
|
279
|
-
if (!sessionConfig.
|
|
280
|
-
this.log?.warn(`Connection config for ${destination} missing required
|
|
305
|
+
if (!sessionConfig.sapUrl) {
|
|
306
|
+
this.log?.warn(`Connection config for ${destination} missing required field: sapUrl`);
|
|
281
307
|
return null;
|
|
282
308
|
}
|
|
283
|
-
|
|
309
|
+
// Check for basic auth: if username/password present and no jwtToken, use basic auth
|
|
310
|
+
const isBasicAuth = sessionConfig.authType === 'basic' ||
|
|
311
|
+
(!sessionConfig.jwtToken && sessionConfig.username && sessionConfig.password);
|
|
312
|
+
if (isBasicAuth) {
|
|
313
|
+
if (!sessionConfig.username || !sessionConfig.password) {
|
|
314
|
+
this.log?.warn(`Connection config for ${destination} missing required fields for basic auth: username(${!!sessionConfig.username}), password(${!!sessionConfig.password})`);
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
this.log?.debug(`Connection config loaded for ${destination} (basic auth): username(${sessionConfig.username}), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
318
|
+
return {
|
|
319
|
+
serviceUrl: sessionConfig.sapUrl,
|
|
320
|
+
username: sessionConfig.username,
|
|
321
|
+
password: sessionConfig.password,
|
|
322
|
+
authType: 'basic',
|
|
323
|
+
sapClient: sessionConfig.sapClient,
|
|
324
|
+
language: sessionConfig.language,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
// JWT auth: check jwtToken
|
|
328
|
+
if (!sessionConfig.jwtToken) {
|
|
329
|
+
this.log?.warn(`Connection config for ${destination} missing required field for JWT auth: jwtToken`);
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
this.log?.debug(`Connection config loaded for ${destination} (JWT auth): token(${sessionConfig.jwtToken.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
284
333
|
return {
|
|
285
334
|
serviceUrl: sessionConfig.sapUrl,
|
|
286
335
|
authorizationToken: sessionConfig.jwtToken,
|
|
336
|
+
authType: 'jwt',
|
|
287
337
|
sapClient: sessionConfig.sapClient,
|
|
288
338
|
language: sessionConfig.language,
|
|
289
339
|
};
|
|
@@ -298,10 +348,27 @@ class AbapSessionStore {
|
|
|
298
348
|
async setAuthorizationConfig(destination, config) {
|
|
299
349
|
const current = await this.loadRawSession(destination);
|
|
300
350
|
if (!current) {
|
|
301
|
-
// Session doesn't exist - try to get serviceUrl from
|
|
351
|
+
// Session doesn't exist - try to get serviceUrl from existing session file or use defaultServiceUrl
|
|
302
352
|
// For ABAP, we need sapUrl to create session
|
|
303
|
-
|
|
304
|
-
|
|
353
|
+
let sapUrl = this.defaultServiceUrl;
|
|
354
|
+
let existingAuthToken = '';
|
|
355
|
+
let existingUsername;
|
|
356
|
+
let existingPassword;
|
|
357
|
+
let existingAuthType;
|
|
358
|
+
// Try to load existing session file to get serviceUrl and auth info
|
|
359
|
+
try {
|
|
360
|
+
const existingSession = await this.loadSession(destination);
|
|
361
|
+
if (existingSession?.serviceUrl) {
|
|
362
|
+
sapUrl = existingSession.serviceUrl;
|
|
363
|
+
existingAuthToken = existingSession.authorizationToken || '';
|
|
364
|
+
existingUsername = existingSession?.username;
|
|
365
|
+
existingPassword = existingSession?.password;
|
|
366
|
+
existingAuthType = existingSession?.authType;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// Ignore errors when loading session - will use defaultServiceUrl
|
|
371
|
+
}
|
|
305
372
|
if (!sapUrl) {
|
|
306
373
|
this.log?.error(`Cannot set authorization config for ${destination}: session does not exist and serviceUrl is required. Missing defaultServiceUrl in constructor.`);
|
|
307
374
|
throw new Error(`Cannot set authorization config for destination "${destination}": session does not exist and serviceUrl is required for ABAP sessions. Call setConnectionConfig first or provide defaultServiceUrl in constructor.`);
|
|
@@ -309,7 +376,10 @@ class AbapSessionStore {
|
|
|
309
376
|
this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: sapUrl(${sapUrl.substring(0, 40)}...)`);
|
|
310
377
|
const newSession = {
|
|
311
378
|
serviceUrl: sapUrl,
|
|
312
|
-
authorizationToken:
|
|
379
|
+
authorizationToken: existingAuthToken,
|
|
380
|
+
username: existingUsername,
|
|
381
|
+
password: existingPassword,
|
|
382
|
+
authType: existingAuthType,
|
|
313
383
|
uaaUrl: config.uaaUrl,
|
|
314
384
|
uaaClientId: config.uaaClientId,
|
|
315
385
|
uaaClientSecret: config.uaaClientSecret,
|
|
@@ -387,5 +457,6 @@ function isEnvConfig(config) {
|
|
|
387
457
|
if (!config || typeof config !== 'object')
|
|
388
458
|
return false;
|
|
389
459
|
const obj = config;
|
|
390
|
-
|
|
460
|
+
// Must have sapUrl (authentication fields are optional - can be set later)
|
|
461
|
+
return 'sapUrl' in obj;
|
|
391
462
|
}
|
|
@@ -55,6 +55,9 @@ class SafeAbapSessionStore {
|
|
|
55
55
|
const internal = {
|
|
56
56
|
sapUrl: (obj.serviceUrl || obj.sapUrl),
|
|
57
57
|
jwtToken: (obj.authorizationToken || obj.jwtToken),
|
|
58
|
+
username: obj.username,
|
|
59
|
+
password: obj.password,
|
|
60
|
+
authType: obj.authType,
|
|
58
61
|
refreshToken: obj.refreshToken,
|
|
59
62
|
uaaUrl: obj.uaaUrl,
|
|
60
63
|
uaaClientId: obj.uaaClientId,
|
|
@@ -130,14 +133,38 @@ class SafeAbapSessionStore {
|
|
|
130
133
|
this.log?.debug(`Connection config not found for ${destination}`);
|
|
131
134
|
return null;
|
|
132
135
|
}
|
|
133
|
-
if (!sessionConfig.
|
|
134
|
-
this.log?.warn(`Connection config for ${destination} missing required
|
|
136
|
+
if (!sessionConfig.sapUrl) {
|
|
137
|
+
this.log?.warn(`Connection config for ${destination} missing required field: sapUrl`);
|
|
135
138
|
return null;
|
|
136
139
|
}
|
|
137
|
-
|
|
140
|
+
// Check for basic auth: if username/password present and no jwtToken, use basic auth
|
|
141
|
+
const isBasicAuth = sessionConfig.authType === 'basic' ||
|
|
142
|
+
(!sessionConfig.jwtToken && sessionConfig.username && sessionConfig.password);
|
|
143
|
+
if (isBasicAuth) {
|
|
144
|
+
if (!sessionConfig.username || !sessionConfig.password) {
|
|
145
|
+
this.log?.warn(`Connection config for ${destination} missing required fields for basic auth: username(${!!sessionConfig.username}), password(${!!sessionConfig.password})`);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
this.log?.debug(`Connection config loaded for ${destination} (basic auth): username(${sessionConfig.username}), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
149
|
+
return {
|
|
150
|
+
serviceUrl: sessionConfig.sapUrl,
|
|
151
|
+
username: sessionConfig.username,
|
|
152
|
+
password: sessionConfig.password,
|
|
153
|
+
authType: 'basic',
|
|
154
|
+
sapClient: sessionConfig.sapClient,
|
|
155
|
+
language: sessionConfig.language,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// JWT auth: check jwtToken
|
|
159
|
+
if (!sessionConfig.jwtToken) {
|
|
160
|
+
this.log?.warn(`Connection config for ${destination} missing required field for JWT auth: jwtToken`);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
this.log?.debug(`Connection config loaded for ${destination} (JWT auth): token(${sessionConfig.jwtToken.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
138
164
|
return {
|
|
139
165
|
serviceUrl: sessionConfig.sapUrl,
|
|
140
166
|
authorizationToken: sessionConfig.jwtToken,
|
|
167
|
+
authType: 'jwt',
|
|
141
168
|
sapClient: sessionConfig.sapClient,
|
|
142
169
|
language: sessionConfig.language,
|
|
143
170
|
};
|
|
@@ -155,7 +182,10 @@ class SafeAbapSessionStore {
|
|
|
155
182
|
this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: serviceUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
|
|
156
183
|
const newSession = {
|
|
157
184
|
sapUrl: serviceUrl,
|
|
158
|
-
jwtToken: config.authorizationToken
|
|
185
|
+
jwtToken: config.authorizationToken,
|
|
186
|
+
username: config.username,
|
|
187
|
+
password: config.password,
|
|
188
|
+
authType: config.authType,
|
|
159
189
|
sapClient: config.sapClient,
|
|
160
190
|
language: config.language,
|
|
161
191
|
};
|
|
@@ -168,7 +198,10 @@ class SafeAbapSessionStore {
|
|
|
168
198
|
const updated = {
|
|
169
199
|
...current,
|
|
170
200
|
sapUrl: config.serviceUrl || current.sapUrl,
|
|
171
|
-
jwtToken: config.authorizationToken,
|
|
201
|
+
jwtToken: config.authorizationToken || current.jwtToken || '',
|
|
202
|
+
username: config.username !== undefined ? config.username : current.username,
|
|
203
|
+
password: config.password !== undefined ? config.password : current.password,
|
|
204
|
+
authType: config.authType !== undefined ? config.authType : current.authType,
|
|
172
205
|
sapClient: config.sapClient !== undefined ? config.sapClient : current.sapClient,
|
|
173
206
|
language: config.language !== undefined ? config.language : current.language,
|
|
174
207
|
};
|
|
@@ -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
|
/**
|
|
@@ -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
|
}
|
|
@@ -48,6 +48,10 @@ export declare const ABAP_CONNECTION_VARS: {
|
|
|
48
48
|
readonly SERVICE_URL: "SAP_URL";
|
|
49
49
|
/** Authorization token (JWT token) */
|
|
50
50
|
readonly AUTHORIZATION_TOKEN: "SAP_JWT_TOKEN";
|
|
51
|
+
/** Username for basic authentication (on-premise systems) */
|
|
52
|
+
readonly USERNAME: "SAP_USERNAME";
|
|
53
|
+
/** Password for basic authentication (on-premise systems) */
|
|
54
|
+
readonly PASSWORD: "SAP_PASSWORD";
|
|
51
55
|
/** SAP client number (optional) */
|
|
52
56
|
readonly SAP_CLIENT: "SAP_CLIENT";
|
|
53
57
|
/** Language (optional) */
|
package/dist/utils/constants.js
CHANGED
|
@@ -51,6 +51,10 @@ exports.ABAP_CONNECTION_VARS = {
|
|
|
51
51
|
SERVICE_URL: 'SAP_URL',
|
|
52
52
|
/** Authorization token (JWT token) */
|
|
53
53
|
AUTHORIZATION_TOKEN: 'SAP_JWT_TOKEN',
|
|
54
|
+
/** Username for basic authentication (on-premise systems) */
|
|
55
|
+
USERNAME: 'SAP_USERNAME',
|
|
56
|
+
/** Password for basic authentication (on-premise systems) */
|
|
57
|
+
PASSWORD: 'SAP_PASSWORD',
|
|
54
58
|
/** SAP client number (optional) */
|
|
55
59
|
SAP_CLIENT: 'SAP_CLIENT',
|
|
56
60
|
/** Language (optional) */
|
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.5",
|
|
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": {
|