@mcp-abap-adt/auth-stores 0.1.7 → 0.2.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/CHANGELOG.md CHANGED
@@ -7,6 +7,106 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2025-12-08
11
+
12
+ ### Breaking Changes
13
+
14
+ - **XsuaaSessionStore Constructor**: `defaultServiceUrl` is now a **required** parameter (second parameter)
15
+ - **Before**: `new XsuaaSessionStore(directory, log?, defaultServiceUrl?)`
16
+ - **After**: `new XsuaaSessionStore(directory, defaultServiceUrl, log?)`
17
+ - **Reason**: `serviceUrl` cannot be obtained from XSUAA service keys, so it must be provided via constructor
18
+ - **Migration**: Update all `XsuaaSessionStore` instantiations to provide `defaultServiceUrl` as second parameter
19
+
20
+ - **SafeXsuaaSessionStore Constructor**: `defaultServiceUrl` is now a **required** parameter (first parameter)
21
+ - **Before**: `new SafeXsuaaSessionStore(log?, defaultServiceUrl?)`
22
+ - **After**: `new SafeXsuaaSessionStore(defaultServiceUrl, log?)`
23
+ - **Migration**: Update all `SafeXsuaaSessionStore` instantiations to provide `defaultServiceUrl` as first parameter
24
+
25
+ - **BtpSessionStore Constructor**: `defaultServiceUrl` is now a **required** parameter (second parameter)
26
+ - **Before**: `new BtpSessionStore(directory, log?, defaultServiceUrl?)`
27
+ - **After**: `new BtpSessionStore(directory, defaultServiceUrl, log?)`
28
+ - **Reason**: `serviceUrl` cannot be obtained from BTP service keys, so it must be provided via constructor
29
+ - **Migration**: Update all `BtpSessionStore` instantiations to provide `defaultServiceUrl` as second parameter
30
+
31
+ - **SafeBtpSessionStore Constructor**: `defaultServiceUrl` is now a **required** parameter (first parameter)
32
+ - **Before**: `new SafeBtpSessionStore(log?, defaultServiceUrl?)`
33
+ - **After**: `new SafeBtpSessionStore(defaultServiceUrl, log?)`
34
+ - **Migration**: Update all `SafeBtpSessionStore` instantiations to provide `defaultServiceUrl` as first parameter
35
+
36
+ ### Changed
37
+
38
+ - **AbapSessionStore Constructor**: `defaultServiceUrl` remains **optional** (third parameter)
39
+ - **Reason**: `serviceUrl` can be obtained from ABAP service keys, so it's optional
40
+ - **Signature**: `new AbapSessionStore(directory, log?, defaultServiceUrl?)`
41
+ - No migration needed for `AbapSessionStore`
42
+
43
+ - **SafeAbapSessionStore Constructor**: `defaultServiceUrl` remains **optional** (second parameter)
44
+ - **Signature**: `new SafeAbapSessionStore(log?, defaultServiceUrl?)`
45
+ - No migration needed for `SafeAbapSessionStore`
46
+
47
+ - **Session Creation Logic**: Updated to use `defaultServiceUrl` when creating new sessions
48
+ - When `setConnectionConfig` or `setAuthorizationConfig` creates a new session, `defaultServiceUrl` is used if `config.serviceUrl` is not provided
49
+ - For XSUAA/BTP stores: `defaultServiceUrl` is always used (required parameter)
50
+ - For ABAP stores: `defaultServiceUrl` is used only if provided and `config.serviceUrl` is not provided
51
+
52
+ - **Session Update Logic**: Fixed to not use `defaultServiceUrl` when updating existing sessions
53
+ - When updating an existing session, only `config.serviceUrl` is used if explicitly provided
54
+ - `defaultServiceUrl` is never used to modify `mcpUrl`/`serviceUrl` during updates
55
+
56
+ ### Added
57
+
58
+ - **Comprehensive Logging**: Added detailed logging throughout all session stores using `ILogger` with optional chaining
59
+ - All critical operations now log via `logger?.info()`, `logger?.debug()`, `logger?.warn()`, `logger?.error()`
60
+ - Logging covers: session creation, updates, deletions, loading, validation errors, file operations
61
+ - Logging provides critical information for analysis: serviceUrl, token lengths, UAA parameters, operation results
62
+ - Logging is optional - stores work without logger (no-op when logger is not provided)
63
+
64
+ ### Fixed
65
+
66
+ - **loadEnvFile**: Fixed validation to allow empty string for `jwtToken`
67
+ - **Before**: Rejected empty string `''` as invalid (treated as falsy)
68
+ - **After**: Only rejects `undefined` or `null` - empty string is valid
69
+ - **Reason**: Sessions created via `setAuthorizationConfig` may have empty `jwtToken` initially (set later via `setConnectionConfig`)
70
+ - This fix allows loading sessions with empty tokens, which is valid for authorization-only sessions
71
+
72
+ ### Migration Guide
73
+
74
+ #### XsuaaSessionStore and SafeXsuaaSessionStore
75
+
76
+ **Before:**
77
+ ```typescript
78
+ const store = new XsuaaSessionStore('/path/to/sessions', logger, 'https://default.mcp.com');
79
+ const safeStore = new SafeXsuaaSessionStore(logger, 'https://default.mcp.com');
80
+ ```
81
+
82
+ **After:**
83
+ ```typescript
84
+ const store = new XsuaaSessionStore('/path/to/sessions', 'https://default.mcp.com', logger);
85
+ const safeStore = new SafeXsuaaSessionStore('https://default.mcp.com', logger);
86
+ ```
87
+
88
+ #### BtpSessionStore and SafeBtpSessionStore
89
+
90
+ **Before:**
91
+ ```typescript
92
+ const store = new BtpSessionStore('/path/to/sessions', logger, 'https://default.mcp.com');
93
+ const safeStore = new SafeBtpSessionStore(logger, 'https://default.mcp.com');
94
+ ```
95
+
96
+ **After:**
97
+ ```typescript
98
+ const store = new BtpSessionStore('/path/to/sessions', 'https://default.mcp.com', logger);
99
+ const safeStore = new SafeBtpSessionStore('https://default.mcp.com', logger);
100
+ ```
101
+
102
+ #### AbapSessionStore and SafeAbapSessionStore
103
+
104
+ No changes needed - `defaultServiceUrl` remains optional:
105
+ ```typescript
106
+ const store = new AbapSessionStore('/path/to/sessions', logger, 'https://default.sap.com'); // Optional
107
+ const safeStore = new SafeAbapSessionStore(logger, 'https://default.sap.com'); // Optional
108
+ ```
109
+
10
110
  ## [0.1.7] - 2025-12-08
11
111
 
12
112
  ### Added
package/README.md CHANGED
@@ -12,7 +12,7 @@ npm install @mcp-abap-adt/auth-stores
12
12
 
13
13
  ## Overview
14
14
 
15
- This package implements the `IServiceKeyStore` and `ISessionStore` interfaces from `@mcp-abap-adt/auth-broker`:
15
+ This package implements the `IServiceKeyStore` and `ISessionStore` interfaces from `@mcp-abap-adt/interfaces`:
16
16
 
17
17
  - **Service Key Stores**: Read service key JSON files from a specified directory
18
18
  - **Session Stores**: Read/write session data from/to `.env` files or in-memory storage
@@ -40,7 +40,7 @@ This principle ensures:
40
40
 
41
41
  This package is responsible for:
42
42
 
43
- 1. **Implementing storage interfaces**: Provides concrete implementations of `IServiceKeyStore` and `ISessionStore` interfaces defined in `@mcp-abap-adt/auth-broker`
43
+ 1. **Implementing storage interfaces**: Provides concrete implementations of `IServiceKeyStore` and `ISessionStore` interfaces defined in `@mcp-abap-adt/interfaces`
44
44
  2. **File I/O operations**: Handles reading and writing service key JSON files and session `.env` files
45
45
  3. **Data format conversion**: Converts between interface types (`IConfig`, `IConnectionConfig`, `IAuthorizationConfig`) and internal storage formats
46
46
  4. **Platform-specific handling**: Provides different store implementations for ABAP, BTP, and XSUAA with their specific data formats
@@ -63,7 +63,7 @@ This package is responsible for:
63
63
 
64
64
  This package interacts with external packages **ONLY through interfaces**:
65
65
 
66
- - **`@mcp-abap-adt/auth-broker`**: Uses interfaces (`IServiceKeyStore`, `ISessionStore`, `IConfig`, `IConnectionConfig`, `IAuthorizationConfig`) - does not know about `AuthBroker` implementation
66
+ - **`@mcp-abap-adt/interfaces`**: Uses interfaces (`IServiceKeyStore`, `ISessionStore`, `IConfig`, `IConnectionConfig`, `IAuthorizationConfig`, `ILogger`) - does not know about concrete implementations in other packages
67
67
  - **No direct dependencies on other packages**: All interactions happen through well-defined interfaces
68
68
 
69
69
  ## Store Types
@@ -101,10 +101,12 @@ import { BtpServiceKeyStore, BtpSessionStore, SafeBtpSessionStore } from '@mcp-a
101
101
  const serviceKeyStore = new BtpServiceKeyStore('/path/to/service-keys');
102
102
 
103
103
  // File-based session store - reads/writes {destination}.env files
104
- const sessionStore = new BtpSessionStore('/path/to/sessions');
104
+ // defaultServiceUrl is REQUIRED (cannot be obtained from service key)
105
+ const sessionStore = new BtpSessionStore('/path/to/sessions', 'https://default.mcp.com', logger);
105
106
 
106
107
  // In-memory session store (non-persistent)
107
- const safeSessionStore = new SafeBtpSessionStore();
108
+ // defaultServiceUrl is REQUIRED (cannot be obtained from service key)
109
+ const safeSessionStore = new SafeBtpSessionStore('https://default.mcp.com', logger);
108
110
  ```
109
111
 
110
112
  ### ABAP Stores (with sapUrl)
@@ -131,10 +133,12 @@ import { XsuaaServiceKeyStore, XsuaaSessionStore, SafeXsuaaSessionStore } from '
131
133
  const serviceKeyStore = new XsuaaServiceKeyStore('/path/to/service-keys');
132
134
 
133
135
  // File-based session store - stores XSUAA sessions
134
- const sessionStore = new XsuaaSessionStore('/path/to/sessions');
136
+ // defaultServiceUrl is REQUIRED (cannot be obtained from service key)
137
+ const sessionStore = new XsuaaSessionStore('/path/to/sessions', 'https://default.mcp.com', logger);
135
138
 
136
139
  // In-memory session store
137
- const safeSessionStore = new SafeXsuaaSessionStore();
140
+ // defaultServiceUrl is REQUIRED (cannot be obtained from service key)
141
+ const safeSessionStore = new SafeXsuaaSessionStore('https://default.mcp.com', logger);
138
142
  ```
139
143
 
140
144
  ### Directory Configuration
@@ -151,6 +155,20 @@ const sessionStore = new AbapSessionStore('/path/to/sessions'); // Directory cre
151
155
 
152
156
  **Note**: File-based session stores (`AbapSessionStore`, `BtpSessionStore`, `XsuaaSessionStore`) automatically create the directory in the constructor if it doesn't exist. Stores are ready to use immediately after construction.
153
157
 
158
+ ### Default Service URL Configuration
159
+
160
+ **For XSUAA and BTP stores**: `defaultServiceUrl` is **required** in the constructor because `serviceUrl` cannot be obtained from service keys:
161
+ - `XsuaaSessionStore(directory, defaultServiceUrl, log?)` - `defaultServiceUrl` is required
162
+ - `SafeXsuaaSessionStore(defaultServiceUrl, log?)` - `defaultServiceUrl` is required
163
+ - `BtpSessionStore(directory, defaultServiceUrl, log?)` - `defaultServiceUrl` is required
164
+ - `SafeBtpSessionStore(defaultServiceUrl, log?)` - `defaultServiceUrl` is required
165
+
166
+ **For ABAP stores**: `defaultServiceUrl` is **optional** because `serviceUrl` can be obtained from ABAP service keys:
167
+ - `AbapSessionStore(directory, log?, defaultServiceUrl?)` - `defaultServiceUrl` is optional
168
+ - `SafeAbapSessionStore(log?, defaultServiceUrl?)` - `defaultServiceUrl` is optional
169
+
170
+ The `defaultServiceUrl` is used when creating new sessions via `setConnectionConfig` or `setAuthorizationConfig` if `config.serviceUrl` is not provided. It is never used to modify existing sessions.
171
+
154
172
  ### Service Key Format
155
173
 
156
174
  **ABAP Service Key** (with nested `uaa` object):
@@ -354,7 +372,7 @@ Integration tests will skip if `test-config.yaml` is not configured or contains
354
372
 
355
373
  ### Store Implementation
356
374
 
357
- - All stores implement `IServiceKeyStore` or `ISessionStore` interfaces from `@mcp-abap-adt/auth-broker`
375
+ - All stores implement `IServiceKeyStore` or `ISessionStore` interfaces from `@mcp-abap-adt/interfaces`
358
376
  - Stores accept a single directory path in constructor
359
377
  - File-based session stores automatically create directories in constructor if they don't exist
360
378
  - Session stores automatically create sessions when calling `setConnectionConfig` or `setAuthorizationConfig` (no need to call `saveSession` first)
@@ -366,13 +384,14 @@ Session stores are designed to work seamlessly with `AuthBroker`:
366
384
 
367
385
  - **Ready after construction**: File-based stores create directory automatically, stores are ready to use immediately
368
386
  - **Automatic session creation**: Calling `setConnectionConfig` or `setAuthorizationConfig` on an empty store creates a new session
369
- - **ABAP stores**: Require `serviceUrl` when creating new session via `setConnectionConfig` or `setAuthorizationConfig`
370
- - **BTP/XSUAA stores**: `mcpUrl` is optional - can create session with authorization config first, then add connection config
387
+ - **ABAP stores**: Require `serviceUrl` when creating new session (from config or `defaultServiceUrl` parameter)
388
+ - **BTP/XSUAA stores**: Require `defaultServiceUrl` in constructor (cannot be obtained from service key), used when creating new sessions if `config.serviceUrl` is not provided
371
389
  - **Token updates**: `setConnectionConfig` updates token if provided, preserves existing token if not provided
390
+ - **Session updates**: When updating existing sessions, only `config.serviceUrl` is used if explicitly provided; `defaultServiceUrl` is never used to modify existing sessions
372
391
 
373
392
  ## Dependencies
374
393
 
375
- - `@mcp-abap-adt/interfaces` (^0.1.3) - Interface definitions (`IServiceKeyStore`, `ISessionStore`, `IConfig`, `IConnectionConfig`, `IAuthorizationConfig`, `ILogger`)
394
+ - `@mcp-abap-adt/interfaces` (^0.1.4) - Interface definitions (`IServiceKeyStore`, `ISessionStore`, `IConfig`, `IConnectionConfig`, `IAuthorizationConfig`, `ILogger`)
376
395
  - `dotenv` - Environment variable parsing
377
396
 
378
397
  ## License
@@ -65,14 +65,15 @@ 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
- log?.debug(`Extracted fields: hasSapUrl(${!!sapUrl}), hasJwtToken(${!!jwtToken})`);
69
- if (!sapUrl || !jwtToken) {
70
- log?.warn(`Env file missing required fields: sapUrl(${!!sapUrl}), jwtToken(${!!jwtToken})`);
68
+ log?.debug(`Extracted fields: hasSapUrl(${!!sapUrl}), hasJwtToken(${jwtToken !== undefined && jwtToken !== null})`);
69
+ // sapUrl is required, jwtToken can be empty string (for authorization-only sessions)
70
+ if (!sapUrl || jwtToken === undefined || jwtToken === null) {
71
+ log?.warn(`Env file missing required fields: sapUrl(${!!sapUrl}), jwtToken(${jwtToken !== undefined && jwtToken !== null})`);
71
72
  return null;
72
73
  }
73
74
  const config = {
74
75
  sapUrl: sapUrl.trim(),
75
- jwtToken: jwtToken.trim(),
76
+ jwtToken: jwtToken.trim(), // Can be empty string for authorization-only sessions
76
77
  };
77
78
  // Optional fields
78
79
  if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT]) {
@@ -19,12 +19,14 @@ import type { IAuthorizationConfig, IConnectionConfig, ISessionStore, IConfig, I
19
19
  export declare class AbapSessionStore implements ISessionStore {
20
20
  protected directory: string;
21
21
  private log?;
22
+ private defaultServiceUrl?;
22
23
  /**
23
24
  * Create a new AbapSessionStore instance
24
25
  * @param directory Directory where session .env files are located
25
26
  * @param log Optional logger for logging operations
27
+ * @param defaultServiceUrl Optional default service URL to use when serviceUrl is not provided in config
26
28
  */
27
- constructor(directory: string, log?: ILogger);
29
+ constructor(directory: string, log?: ILogger, defaultServiceUrl?: string);
28
30
  /**
29
31
  * Load session from file
30
32
  * @param filePath Path to session file
@@ -58,14 +58,17 @@ const path = __importStar(require("path"));
58
58
  class AbapSessionStore {
59
59
  directory;
60
60
  log;
61
+ defaultServiceUrl;
61
62
  /**
62
63
  * Create a new AbapSessionStore instance
63
64
  * @param directory Directory where session .env files are located
64
65
  * @param log Optional logger for logging operations
66
+ * @param defaultServiceUrl Optional default service URL to use when serviceUrl is not provided in config
65
67
  */
66
- constructor(directory, log) {
68
+ constructor(directory, log, defaultServiceUrl) {
67
69
  this.directory = directory;
68
70
  this.log = log;
71
+ this.defaultServiceUrl = defaultServiceUrl;
69
72
  // Ensure directory exists - create if it doesn't
70
73
  if (!fs.existsSync(directory)) {
71
74
  fs.mkdirSync(directory, { recursive: true });
@@ -93,7 +96,7 @@ class AbapSessionStore {
93
96
  // Convert IConfig format (serviceUrl, authorizationToken) to internal format (sapUrl, jwtToken)
94
97
  return {
95
98
  sapUrl: (obj.serviceUrl || obj.sapUrl),
96
- jwtToken: (obj.authorizationToken || obj.jwtToken),
99
+ jwtToken: (obj.authorizationToken || obj.jwtToken || ''), // Ensure jwtToken is always a string
97
100
  refreshToken: obj.refreshToken,
98
101
  uaaUrl: obj.uaaUrl,
99
102
  uaaClientId: obj.uaaClientId,
@@ -110,6 +113,7 @@ class AbapSessionStore {
110
113
  async saveToFile(filePath, config) {
111
114
  // Type guard - ensure it's EnvConfig (has sapUrl)
112
115
  if (!config || typeof config !== 'object' || !('sapUrl' in config)) {
116
+ this.log?.error(`Invalid config format for AbapSessionStore: missing sapUrl`);
113
117
  throw new Error('AbapSessionStore can only store ABAP sessions (with sapUrl)');
114
118
  }
115
119
  // Extract destination from file path
@@ -159,7 +163,12 @@ class AbapSessionStore {
159
163
  const fileName = `${destination}.env`;
160
164
  const filePath = path.join(this.directory, fileName);
161
165
  if (fs.existsSync(filePath)) {
166
+ this.log?.debug(`Deleting session for destination: ${destination}`);
162
167
  fs.unlinkSync(filePath);
168
+ this.log?.info(`Session deleted for destination: ${destination}`);
169
+ }
170
+ else {
171
+ this.log?.debug(`Session file not found for deletion: ${destination}`);
163
172
  }
164
173
  }
165
174
  /**
@@ -170,20 +179,43 @@ class AbapSessionStore {
170
179
  */
171
180
  async loadSession(destination) {
172
181
  this.log?.debug(`Loading session for destination: ${destination}`);
173
- const authConfig = await this.getAuthorizationConfig(destination);
174
- const connConfig = await this.getConnectionConfig(destination);
175
- // Return null if both are null, otherwise return composition (even if one is null)
176
- if (!authConfig && !connConfig) {
182
+ const rawSession = await this.loadRawSession(destination);
183
+ if (!rawSession) {
177
184
  this.log?.debug(`Session not found for destination: ${destination}`);
178
185
  return null;
179
186
  }
180
- const tokenLength = connConfig?.authorizationToken?.length || 0;
181
- const hasRefreshToken = !!authConfig?.refreshToken;
182
- this.log?.info(`Session loaded for ${destination}: token(${tokenLength} chars), hasRefreshToken(${hasRefreshToken}), sapUrl(${connConfig?.serviceUrl ? connConfig.serviceUrl.substring(0, 40) + '...' : 'none'})`);
183
- return {
184
- ...(authConfig || {}),
185
- ...(connConfig || {}),
186
- };
187
+ // Convert internal format to IConfig format
188
+ const result = {};
189
+ // Connection config fields
190
+ if (rawSession.sapUrl) {
191
+ result.serviceUrl = rawSession.sapUrl;
192
+ }
193
+ if (rawSession.jwtToken !== undefined) {
194
+ result.authorizationToken = rawSession.jwtToken;
195
+ }
196
+ if (rawSession.sapClient) {
197
+ result.sapClient = rawSession.sapClient;
198
+ }
199
+ if (rawSession.language) {
200
+ result.language = rawSession.language;
201
+ }
202
+ // Authorization config fields
203
+ if (rawSession.uaaUrl) {
204
+ result.uaaUrl = rawSession.uaaUrl;
205
+ }
206
+ if (rawSession.uaaClientId) {
207
+ result.uaaClientId = rawSession.uaaClientId;
208
+ }
209
+ if (rawSession.uaaClientSecret) {
210
+ result.uaaClientSecret = rawSession.uaaClientSecret;
211
+ }
212
+ if (rawSession.refreshToken) {
213
+ result.refreshToken = rawSession.refreshToken;
214
+ }
215
+ const tokenLength = rawSession.jwtToken?.length || 0;
216
+ const hasRefreshToken = !!rawSession.refreshToken;
217
+ this.log?.info(`Session loaded for ${destination}: token(${tokenLength} chars), hasRefreshToken(${hasRefreshToken}), sapUrl(${rawSession.sapUrl ? rawSession.sapUrl.substring(0, 40) + '...' : 'none'})`);
218
+ return result;
187
219
  }
188
220
  /**
189
221
  * Load raw session data (internal representation)
@@ -198,11 +230,13 @@ class AbapSessionStore {
198
230
  try {
199
231
  const raw = await this.loadFromFile(sessionPath);
200
232
  if (!raw || !isEnvConfig(raw)) {
233
+ this.log?.debug(`Invalid session format for ${destination}: missing required fields (sapUrl, jwtToken)`);
201
234
  return null;
202
235
  }
203
236
  return raw;
204
237
  }
205
238
  catch (error) {
239
+ this.log?.error(`Error loading session for ${destination}: ${error instanceof Error ? error.message : String(error)}`);
206
240
  return null;
207
241
  }
208
242
  }
@@ -264,34 +298,41 @@ class AbapSessionStore {
264
298
  async setAuthorizationConfig(destination, config) {
265
299
  const current = await this.loadRawSession(destination);
266
300
  if (!current) {
267
- // Session doesn't exist - try to get serviceUrl from connection config
301
+ // Session doesn't exist - try to get serviceUrl from connection config or use defaultServiceUrl
268
302
  // For ABAP, we need sapUrl to create session
269
303
  const connConfig = await this.getConnectionConfig(destination);
270
- const sapUrl = connConfig?.serviceUrl;
304
+ const sapUrl = connConfig?.serviceUrl || this.defaultServiceUrl;
271
305
  if (!sapUrl) {
272
- throw new Error(`Cannot set authorization config for destination "${destination}": session does not exist and serviceUrl is required for ABAP sessions. Call setConnectionConfig first.`);
306
+ this.log?.error(`Cannot set authorization config for ${destination}: session does not exist and serviceUrl is required. Missing defaultServiceUrl in constructor.`);
307
+ 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.`);
273
308
  }
274
309
  this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: sapUrl(${sapUrl.substring(0, 40)}...)`);
275
310
  const newSession = {
276
- sapUrl,
277
- jwtToken: connConfig?.authorizationToken || '', // Use token from connection config if available
311
+ serviceUrl: sapUrl,
312
+ authorizationToken: connConfig?.authorizationToken || '', // Use token from connection config if available
278
313
  uaaUrl: config.uaaUrl,
279
314
  uaaClientId: config.uaaClientId,
280
315
  uaaClientSecret: config.uaaClientSecret,
281
316
  refreshToken: config.refreshToken,
282
317
  };
283
318
  await this.saveSession(destination, newSession);
319
+ this.log?.info(`New session created for ${destination} via setAuthorizationConfig: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
284
320
  return;
285
321
  }
286
- // Update authorization fields
322
+ // Update authorization fields - convert internal format to IConfig
323
+ this.log?.debug(`Updating authorization config for existing session ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
287
324
  const updated = {
288
- ...current,
325
+ serviceUrl: current.sapUrl,
326
+ authorizationToken: current.jwtToken,
327
+ sapClient: current.sapClient,
328
+ language: current.language,
289
329
  uaaUrl: config.uaaUrl,
290
330
  uaaClientId: config.uaaClientId,
291
331
  uaaClientSecret: config.uaaClientSecret,
292
332
  refreshToken: config.refreshToken || current.refreshToken,
293
333
  };
294
334
  await this.saveSession(destination, updated);
335
+ this.log?.info(`Authorization config updated for ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
295
336
  }
296
337
  /**
297
338
  * Set connection configuration
@@ -304,30 +345,38 @@ class AbapSessionStore {
304
345
  const current = await this.loadRawSession(destination);
305
346
  if (!current) {
306
347
  // Session doesn't exist - create new one
307
- // For ABAP, serviceUrl is required
308
- if (!config.serviceUrl) {
309
- throw new Error(`Cannot create session for destination "${destination}": serviceUrl is required for ABAP sessions`);
348
+ // For ABAP, serviceUrl is required - use from config, defaultServiceUrl, or throw error
349
+ const serviceUrl = config.serviceUrl || this.defaultServiceUrl;
350
+ if (!serviceUrl) {
351
+ this.log?.error(`Cannot create session for ${destination}: serviceUrl is required. Missing in config and defaultServiceUrl in constructor.`);
352
+ throw new Error(`Cannot create session for destination "${destination}": serviceUrl is required for ABAP sessions. Provide it in config or constructor.`);
310
353
  }
311
- this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: serviceUrl(${config.serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
354
+ this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: serviceUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
312
355
  const newSession = {
313
- sapUrl: config.serviceUrl,
314
- jwtToken: config.authorizationToken || '',
356
+ serviceUrl: serviceUrl,
357
+ authorizationToken: config.authorizationToken || '',
315
358
  sapClient: config.sapClient,
316
359
  language: config.language,
317
360
  };
318
361
  await this.saveSession(destination, newSession);
319
- this.log?.info(`Session created for ${destination}: serviceUrl(${config.serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
362
+ this.log?.info(`Session created for ${destination}: serviceUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
320
363
  return;
321
364
  }
322
- // Update connection fields
365
+ // Update connection fields - convert internal format to IConfig
366
+ this.log?.debug(`Updating connection config for existing session ${destination}: serviceUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'unchanged'}), token(${config.authorizationToken?.length || 0} chars)`);
323
367
  const updated = {
324
- ...current,
325
- sapUrl: config.serviceUrl || current.sapUrl,
326
- jwtToken: config.authorizationToken,
368
+ serviceUrl: config.serviceUrl || current.sapUrl,
369
+ authorizationToken: config.authorizationToken,
327
370
  sapClient: config.sapClient !== undefined ? config.sapClient : current.sapClient,
328
371
  language: config.language !== undefined ? config.language : current.language,
372
+ uaaUrl: current.uaaUrl,
373
+ uaaClientId: current.uaaClientId,
374
+ uaaClientSecret: current.uaaClientSecret,
375
+ refreshToken: current.refreshToken,
329
376
  };
330
377
  await this.saveSession(destination, updated);
378
+ const finalServiceUrl = updated.serviceUrl || current.sapUrl;
379
+ this.log?.info(`Connection config updated for ${destination}: serviceUrl(${finalServiceUrl ? finalServiceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
331
380
  }
332
381
  }
333
382
  exports.AbapSessionStore = AbapSessionStore;
@@ -14,11 +14,13 @@ import type { ISessionStore, IConnectionConfig, IAuthorizationConfig, IConfig, I
14
14
  export declare class SafeAbapSessionStore implements ISessionStore {
15
15
  private sessions;
16
16
  private log?;
17
+ private defaultServiceUrl?;
17
18
  /**
18
19
  * Create a new SafeAbapSessionStore instance
19
20
  * @param log Optional logger for logging operations
21
+ * @param defaultServiceUrl Optional default service URL to use when serviceUrl is not provided in config
20
22
  */
21
- constructor(log?: ILogger);
23
+ constructor(log?: ILogger, defaultServiceUrl?: string);
22
24
  private loadRawSession;
23
25
  private validateSessionConfig;
24
26
  private convertToInternalFormat;
@@ -16,27 +16,33 @@ exports.SafeAbapSessionStore = void 0;
16
16
  class SafeAbapSessionStore {
17
17
  sessions = new Map();
18
18
  log;
19
+ defaultServiceUrl;
19
20
  /**
20
21
  * Create a new SafeAbapSessionStore instance
21
22
  * @param log Optional logger for logging operations
23
+ * @param defaultServiceUrl Optional default service URL to use when serviceUrl is not provided in config
22
24
  */
23
- constructor(log) {
25
+ constructor(log, defaultServiceUrl) {
24
26
  this.log = log;
27
+ this.defaultServiceUrl = defaultServiceUrl;
25
28
  }
26
29
  loadRawSession(destination) {
27
30
  return this.sessions.get(destination) || null;
28
31
  }
29
32
  validateSessionConfig(config) {
30
33
  if (!config || typeof config !== 'object') {
34
+ this.log?.error(`Invalid config format: not an object`);
31
35
  throw new Error('SafeAbapSessionStore can only store ABAP sessions (with sapUrl)');
32
36
  }
33
37
  const obj = config;
34
38
  // Accept IConfig format (has serviceUrl) or internal format (has sapUrl)
35
39
  const serviceUrl = obj.serviceUrl || obj.sapUrl;
36
40
  if (!serviceUrl) {
41
+ this.log?.error(`Validation failed: missing required field serviceUrl or sapUrl`);
37
42
  throw new Error('ABAP session config missing required field: serviceUrl or sapUrl');
38
43
  }
39
44
  if (!obj.authorizationToken && !obj.jwtToken) {
45
+ this.log?.error(`Validation failed: missing required field authorizationToken or jwtToken`);
40
46
  throw new Error('ABAP session config missing required field: authorizationToken or jwtToken');
41
47
  }
42
48
  }
@@ -60,19 +66,43 @@ class SafeAbapSessionStore {
60
66
  }
61
67
  async loadSession(destination) {
62
68
  this.log?.debug(`Loading session for destination: ${destination}`);
63
- const authConfig = await this.getAuthorizationConfig(destination);
64
- const connConfig = await this.getConnectionConfig(destination);
65
- if (!authConfig && !connConfig) {
69
+ const rawSession = this.loadRawSession(destination);
70
+ if (!rawSession) {
66
71
  this.log?.debug(`Session not found for destination: ${destination}`);
67
72
  return null;
68
73
  }
69
- const tokenLength = connConfig?.authorizationToken?.length || 0;
70
- const hasRefreshToken = !!authConfig?.refreshToken;
71
- this.log?.info(`Session loaded for ${destination}: token(${tokenLength} chars), hasRefreshToken(${hasRefreshToken}), sapUrl(${connConfig?.serviceUrl ? connConfig.serviceUrl.substring(0, 40) + '...' : 'none'})`);
72
- return {
73
- ...(authConfig || {}),
74
- ...(connConfig || {}),
75
- };
74
+ // Convert internal format to IConfig format
75
+ const result = {};
76
+ // Connection config fields
77
+ if (rawSession.sapUrl) {
78
+ result.serviceUrl = rawSession.sapUrl;
79
+ }
80
+ if (rawSession.jwtToken !== undefined) {
81
+ result.authorizationToken = rawSession.jwtToken;
82
+ }
83
+ if (rawSession.sapClient) {
84
+ result.sapClient = rawSession.sapClient;
85
+ }
86
+ if (rawSession.language) {
87
+ result.language = rawSession.language;
88
+ }
89
+ // Authorization config fields
90
+ if (rawSession.uaaUrl) {
91
+ result.uaaUrl = rawSession.uaaUrl;
92
+ }
93
+ if (rawSession.uaaClientId) {
94
+ result.uaaClientId = rawSession.uaaClientId;
95
+ }
96
+ if (rawSession.uaaClientSecret) {
97
+ result.uaaClientSecret = rawSession.uaaClientSecret;
98
+ }
99
+ if (rawSession.refreshToken) {
100
+ result.refreshToken = rawSession.refreshToken;
101
+ }
102
+ const tokenLength = rawSession.jwtToken?.length || 0;
103
+ const hasRefreshToken = !!rawSession.refreshToken;
104
+ this.log?.info(`Session loaded for ${destination}: token(${tokenLength} chars), hasRefreshToken(${hasRefreshToken}), sapUrl(${rawSession.sapUrl ? rawSession.sapUrl.substring(0, 40) + '...' : 'none'})`);
105
+ return result;
76
106
  }
77
107
  async saveSession(destination, config) {
78
108
  this.log?.debug(`Saving session for destination: ${destination}`);
@@ -85,16 +115,26 @@ class SafeAbapSessionStore {
85
115
  this.sessions.set(destination, internalConfig);
86
116
  }
87
117
  async deleteSession(destination) {
88
- this.sessions.delete(destination);
118
+ if (this.sessions.has(destination)) {
119
+ this.log?.debug(`Deleting session for destination: ${destination}`);
120
+ this.sessions.delete(destination);
121
+ this.log?.info(`Session deleted for destination: ${destination}`);
122
+ }
123
+ else {
124
+ this.log?.debug(`Session not found for deletion: ${destination}`);
125
+ }
89
126
  }
90
127
  async getConnectionConfig(destination) {
91
128
  const sessionConfig = this.loadRawSession(destination);
92
129
  if (!sessionConfig) {
130
+ this.log?.debug(`Connection config not found for ${destination}`);
93
131
  return null;
94
132
  }
95
133
  if (!sessionConfig.jwtToken || !sessionConfig.sapUrl) {
134
+ this.log?.warn(`Connection config for ${destination} missing required fields: jwtToken(${!!sessionConfig.jwtToken}), sapUrl(${!!sessionConfig.sapUrl})`);
96
135
  return null;
97
136
  }
137
+ this.log?.debug(`Connection config loaded for ${destination}: token(${sessionConfig.jwtToken.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
98
138
  return {
99
139
  serviceUrl: sessionConfig.sapUrl,
100
140
  authorizationToken: sessionConfig.jwtToken,
@@ -106,22 +146,25 @@ class SafeAbapSessionStore {
106
146
  const current = this.loadRawSession(destination);
107
147
  if (!current) {
108
148
  // Session doesn't exist - create new one
109
- // For ABAP, serviceUrl is required
110
- if (!config.serviceUrl) {
111
- throw new Error(`Cannot create session for destination "${destination}": serviceUrl is required for ABAP sessions`);
149
+ // For ABAP, serviceUrl is required - use from config, defaultServiceUrl, or throw error
150
+ const serviceUrl = config.serviceUrl || this.defaultServiceUrl;
151
+ if (!serviceUrl) {
152
+ this.log?.error(`Cannot create session for ${destination}: serviceUrl is required. Missing in config and defaultServiceUrl in constructor.`);
153
+ throw new Error(`Cannot create session for destination "${destination}": serviceUrl is required for ABAP sessions. Provide it in config or constructor.`);
112
154
  }
113
- this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: serviceUrl(${config.serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
155
+ this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: serviceUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
114
156
  const newSession = {
115
- sapUrl: config.serviceUrl,
157
+ sapUrl: serviceUrl,
116
158
  jwtToken: config.authorizationToken || '',
117
159
  sapClient: config.sapClient,
118
160
  language: config.language,
119
161
  };
120
162
  // Save directly to Map (internal format)
121
163
  this.sessions.set(destination, newSession);
122
- this.log?.info(`Session created for ${destination}: serviceUrl(${config.serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
164
+ this.log?.info(`Session created for ${destination}: serviceUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
123
165
  return;
124
166
  }
167
+ this.log?.debug(`Updating connection config for existing session ${destination}: serviceUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'unchanged'}), token(${config.authorizationToken?.length || 0} chars)`);
125
168
  const updated = {
126
169
  ...current,
127
170
  sapUrl: config.serviceUrl || current.sapUrl,
@@ -131,15 +174,19 @@ class SafeAbapSessionStore {
131
174
  };
132
175
  // Save directly to Map (internal format)
133
176
  this.sessions.set(destination, updated);
177
+ this.log?.info(`Connection config updated for ${destination}: serviceUrl(${updated.sapUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
134
178
  }
135
179
  async getAuthorizationConfig(destination) {
136
180
  const sessionConfig = this.loadRawSession(destination);
137
181
  if (!sessionConfig) {
182
+ this.log?.debug(`Authorization config not found for ${destination}`);
138
183
  return null;
139
184
  }
140
185
  if (!sessionConfig.uaaUrl || !sessionConfig.uaaClientId || !sessionConfig.uaaClientSecret) {
186
+ this.log?.warn(`Authorization config for ${destination} missing required UAA fields`);
141
187
  return null;
142
188
  }
189
+ this.log?.debug(`Authorization config loaded for ${destination}: uaaUrl(${sessionConfig.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!sessionConfig.refreshToken})`);
143
190
  return {
144
191
  uaaUrl: sessionConfig.uaaUrl,
145
192
  uaaClientId: sessionConfig.uaaClientId,
@@ -150,12 +197,13 @@ class SafeAbapSessionStore {
150
197
  async setAuthorizationConfig(destination, config) {
151
198
  const current = this.loadRawSession(destination);
152
199
  if (!current) {
153
- // Session doesn't exist - try to get serviceUrl from connection config
200
+ // Session doesn't exist - try to get serviceUrl from connection config or use defaultServiceUrl
154
201
  // For ABAP, we need sapUrl to create session
155
202
  const connConfig = await this.getConnectionConfig(destination);
156
- const sapUrl = connConfig?.serviceUrl;
203
+ const sapUrl = connConfig?.serviceUrl || this.defaultServiceUrl;
157
204
  if (!sapUrl) {
158
- throw new Error(`Cannot set authorization config for destination "${destination}": session does not exist and serviceUrl is required for ABAP sessions. Call setConnectionConfig first.`);
205
+ this.log?.error(`Cannot set authorization config for ${destination}: session does not exist and serviceUrl is required. Missing defaultServiceUrl in constructor.`);
206
+ 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.`);
159
207
  }
160
208
  this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: sapUrl(${sapUrl.substring(0, 40)}...)`);
161
209
  const newSession = {
@@ -168,8 +216,10 @@ class SafeAbapSessionStore {
168
216
  };
169
217
  // Save directly to Map (internal format)
170
218
  this.sessions.set(destination, newSession);
219
+ this.log?.info(`New session created for ${destination} via setAuthorizationConfig: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
171
220
  return;
172
221
  }
222
+ this.log?.debug(`Updating authorization config for existing session ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
173
223
  const updated = {
174
224
  ...current,
175
225
  uaaUrl: config.uaaUrl,
@@ -179,6 +229,7 @@ class SafeAbapSessionStore {
179
229
  };
180
230
  // Save directly to Map (internal format)
181
231
  this.sessions.set(destination, updated);
232
+ this.log?.info(`Authorization config updated for ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
182
233
  }
183
234
  }
184
235
  exports.SafeAbapSessionStore = SafeAbapSessionStore;
@@ -17,12 +17,14 @@ import type { IAuthorizationConfig, IConnectionConfig, ISessionStore, IConfig, I
17
17
  export declare class BtpSessionStore implements ISessionStore {
18
18
  protected directory: string;
19
19
  private log?;
20
+ private defaultServiceUrl;
20
21
  /**
21
22
  * Create a new BtpSessionStore instance
22
23
  * @param directory Directory where session .env files are located
24
+ * @param defaultServiceUrl Default service URL (required for BTP/XSUAA - cannot be obtained from service key)
23
25
  * @param log Optional logger for logging operations
24
26
  */
25
- constructor(directory: string, log?: ILogger);
27
+ constructor(directory: string, defaultServiceUrl: string, log?: ILogger);
26
28
  /**
27
29
  * Load session from file
28
30
  * @param filePath Path to session file
@@ -56,13 +56,16 @@ const path = __importStar(require("path"));
56
56
  class BtpSessionStore {
57
57
  directory;
58
58
  log;
59
+ defaultServiceUrl;
59
60
  /**
60
61
  * Create a new BtpSessionStore instance
61
62
  * @param directory Directory where session .env files are located
63
+ * @param defaultServiceUrl Default service URL (required for BTP/XSUAA - cannot be obtained from service key)
62
64
  * @param log Optional logger for logging operations
63
65
  */
64
- constructor(directory, log) {
66
+ constructor(directory, defaultServiceUrl, log) {
65
67
  this.directory = directory;
68
+ this.defaultServiceUrl = defaultServiceUrl;
66
69
  this.log = log;
67
70
  // Ensure directory exists - create if it doesn't
68
71
  if (!fs.existsSync(directory)) {
@@ -164,7 +167,12 @@ class BtpSessionStore {
164
167
  const fileName = `${destination}.env`;
165
168
  const filePath = path.join(this.directory, fileName);
166
169
  if (fs.existsSync(filePath)) {
170
+ this.log?.debug(`Deleting session for destination: ${destination}`);
167
171
  fs.unlinkSync(filePath);
172
+ this.log?.info(`Session deleted for destination: ${destination}`);
173
+ }
174
+ else {
175
+ this.log?.debug(`Session file not found for deletion: ${destination}`);
168
176
  }
169
177
  }
170
178
  /**
@@ -203,11 +211,13 @@ class BtpSessionStore {
203
211
  try {
204
212
  const raw = await this.loadFromFile(sessionPath);
205
213
  if (!raw || !isBtpBaseSessionConfig(raw)) {
214
+ this.log?.debug(`Invalid session format for ${destination}: missing required fields (jwtToken)`);
206
215
  return null;
207
216
  }
208
217
  return raw;
209
218
  }
210
219
  catch (error) {
220
+ this.log?.error(`Error loading session for ${destination}: ${error instanceof Error ? error.message : String(error)}`);
211
221
  return null;
212
222
  }
213
223
  }
@@ -269,10 +279,10 @@ class BtpSessionStore {
269
279
  const current = await this.loadRawSession(destination);
270
280
  if (!current) {
271
281
  // Session doesn't exist - create new one
272
- // For BTP, mcpUrl is optional, so we can create session without it
273
- this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig`);
282
+ // For BTP, use defaultServiceUrl (required - cannot be obtained from service key)
283
+ this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: mcpUrl(${this.defaultServiceUrl.substring(0, 40)}...)`);
274
284
  const newSession = {
275
- mcpUrl: undefined, // Will be set when connection config is set
285
+ mcpUrl: this.defaultServiceUrl,
276
286
  jwtToken: '', // Will be set when connection config is set
277
287
  uaaUrl: config.uaaUrl,
278
288
  uaaClientId: config.uaaClientId,
@@ -280,9 +290,11 @@ class BtpSessionStore {
280
290
  refreshToken: config.refreshToken,
281
291
  };
282
292
  await this.saveSession(destination, newSession);
293
+ this.log?.info(`New session created for ${destination} via setAuthorizationConfig: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
283
294
  return;
284
295
  }
285
296
  // Update authorization fields
297
+ this.log?.debug(`Updating authorization config for existing session ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
286
298
  const updated = {
287
299
  ...current,
288
300
  uaaUrl: config.uaaUrl,
@@ -291,6 +303,7 @@ class BtpSessionStore {
291
303
  refreshToken: config.refreshToken || current.refreshToken,
292
304
  };
293
305
  await this.saveSession(destination, updated);
306
+ this.log?.info(`Authorization config updated for ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
294
307
  }
295
308
  /**
296
309
  * Set connection configuration
@@ -302,23 +315,26 @@ class BtpSessionStore {
302
315
  const current = await this.loadRawSession(destination);
303
316
  if (!current) {
304
317
  // Session doesn't exist - create new one
305
- // For BTP, mcpUrl is optional
306
- this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
318
+ // For BTP, use config.serviceUrl if provided, otherwise use defaultServiceUrl (required)
319
+ const serviceUrl = config.serviceUrl || this.defaultServiceUrl;
320
+ this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
307
321
  const newSession = {
308
- mcpUrl: config.serviceUrl,
322
+ mcpUrl: serviceUrl,
309
323
  jwtToken: config.authorizationToken || '',
310
324
  };
311
325
  await this.saveSession(destination, newSession);
312
- this.log?.info(`Session created for ${destination}: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
326
+ this.log?.info(`Session created for ${destination}: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
313
327
  return;
314
328
  }
315
329
  // Update connection fields
330
+ this.log?.debug(`Updating connection config for existing session ${destination}: serviceUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'unchanged'}), token(${config.authorizationToken?.length || 0} chars)`);
316
331
  const updated = {
317
332
  ...current,
318
333
  mcpUrl: config.serviceUrl !== undefined ? config.serviceUrl : current.mcpUrl,
319
334
  jwtToken: config.authorizationToken !== undefined ? config.authorizationToken : current.jwtToken,
320
335
  };
321
336
  await this.saveSession(destination, updated);
337
+ this.log?.info(`Connection config updated for ${destination}: serviceUrl(${updated.mcpUrl ? updated.mcpUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
322
338
  }
323
339
  }
324
340
  exports.BtpSessionStore = BtpSessionStore;
@@ -14,11 +14,13 @@ import type { IConnectionConfig, ISessionStore, IAuthorizationConfig, IConfig, I
14
14
  export declare class SafeBtpSessionStore implements ISessionStore {
15
15
  private sessions;
16
16
  private log?;
17
+ private defaultServiceUrl;
17
18
  /**
18
19
  * Create a new SafeBtpSessionStore instance
20
+ * @param defaultServiceUrl Default service URL (required for BTP/XSUAA - cannot be obtained from service key)
19
21
  * @param log Optional logger for logging operations
20
22
  */
21
- constructor(log?: ILogger);
23
+ constructor(defaultServiceUrl: string, log?: ILogger);
22
24
  private loadRawSession;
23
25
  private validateSessionConfig;
24
26
  private convertToInternalFormat;
@@ -16,11 +16,14 @@ exports.SafeBtpSessionStore = void 0;
16
16
  class SafeBtpSessionStore {
17
17
  sessions = new Map();
18
18
  log;
19
+ defaultServiceUrl;
19
20
  /**
20
21
  * Create a new SafeBtpSessionStore instance
22
+ * @param defaultServiceUrl Default service URL (required for BTP/XSUAA - cannot be obtained from service key)
21
23
  * @param log Optional logger for logging operations
22
24
  */
23
- constructor(log) {
25
+ constructor(defaultServiceUrl, log) {
26
+ this.defaultServiceUrl = defaultServiceUrl;
24
27
  this.log = log;
25
28
  }
26
29
  loadRawSession(destination) {
@@ -90,17 +93,27 @@ class SafeBtpSessionStore {
90
93
  this.sessions.set(destination, internalConfig);
91
94
  }
92
95
  async deleteSession(destination) {
93
- this.sessions.delete(destination);
96
+ if (this.sessions.has(destination)) {
97
+ this.log?.debug(`Deleting session for destination: ${destination}`);
98
+ this.sessions.delete(destination);
99
+ this.log?.info(`Session deleted for destination: ${destination}`);
100
+ }
101
+ else {
102
+ this.log?.debug(`Session not found for deletion: ${destination}`);
103
+ }
94
104
  }
95
105
  async getConnectionConfig(destination) {
96
106
  const sessionConfig = this.loadRawSession(destination);
97
107
  if (!sessionConfig) {
108
+ this.log?.debug(`Connection config not found for ${destination}`);
98
109
  return null;
99
110
  }
100
111
  // Return null if jwtToken is undefined or null (but allow empty string)
101
112
  if (sessionConfig.jwtToken === undefined || sessionConfig.jwtToken === null) {
113
+ this.log?.warn(`Connection config for ${destination} missing required field: jwtToken`);
102
114
  return null;
103
115
  }
116
+ this.log?.debug(`Connection config loaded for ${destination}: token(${sessionConfig.jwtToken.length} chars), serviceUrl(${sessionConfig.mcpUrl ? sessionConfig.mcpUrl.substring(0, 40) + '...' : 'none'})`);
104
117
  return {
105
118
  serviceUrl: sessionConfig.mcpUrl, // May be undefined for base BTP
106
119
  authorizationToken: sessionConfig.jwtToken,
@@ -110,17 +123,19 @@ class SafeBtpSessionStore {
110
123
  const current = this.loadRawSession(destination);
111
124
  if (!current) {
112
125
  // Session doesn't exist - create new one
113
- // For BTP, mcpUrl is optional
114
- this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
126
+ // For BTP, use config.serviceUrl if provided, otherwise use defaultServiceUrl (required)
127
+ const serviceUrl = config.serviceUrl || this.defaultServiceUrl;
128
+ this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
115
129
  const newSession = {
116
- mcpUrl: config.serviceUrl,
130
+ mcpUrl: serviceUrl,
117
131
  jwtToken: config.authorizationToken || '',
118
132
  };
119
133
  // Save directly to Map (internal format)
120
134
  this.sessions.set(destination, newSession);
121
- this.log?.info(`Session created for ${destination}: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
135
+ this.log?.info(`Session created for ${destination}: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
122
136
  return;
123
137
  }
138
+ this.log?.debug(`Updating connection config for existing session ${destination}: serviceUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'unchanged'}), token(${config.authorizationToken?.length || 0} chars)`);
124
139
  const updated = {
125
140
  ...current,
126
141
  mcpUrl: config.serviceUrl !== undefined ? config.serviceUrl : current.mcpUrl,
@@ -128,15 +143,19 @@ class SafeBtpSessionStore {
128
143
  };
129
144
  // Save directly to Map (internal format)
130
145
  this.sessions.set(destination, updated);
146
+ this.log?.info(`Connection config updated for ${destination}: serviceUrl(${updated.mcpUrl ? updated.mcpUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
131
147
  }
132
148
  async getAuthorizationConfig(destination) {
133
149
  const sessionConfig = this.loadRawSession(destination);
134
150
  if (!sessionConfig) {
151
+ this.log?.debug(`Authorization config not found for ${destination}`);
135
152
  return null;
136
153
  }
137
154
  if (!sessionConfig.uaaUrl || !sessionConfig.uaaClientId || !sessionConfig.uaaClientSecret) {
155
+ this.log?.warn(`Authorization config for ${destination} missing required UAA fields`);
138
156
  return null;
139
157
  }
158
+ this.log?.debug(`Authorization config loaded for ${destination}: uaaUrl(${sessionConfig.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!sessionConfig.refreshToken})`);
140
159
  return {
141
160
  uaaUrl: sessionConfig.uaaUrl,
142
161
  uaaClientId: sessionConfig.uaaClientId,
@@ -148,10 +167,10 @@ class SafeBtpSessionStore {
148
167
  const current = this.loadRawSession(destination);
149
168
  if (!current) {
150
169
  // Session doesn't exist - create new one
151
- // For BTP, mcpUrl is optional, so we can create session without it
152
- this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig`);
170
+ // For BTP, use defaultServiceUrl (required - cannot be obtained from service key)
171
+ this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: mcpUrl(${this.defaultServiceUrl.substring(0, 40)}...)`);
153
172
  const newSession = {
154
- mcpUrl: undefined, // Will be set when connection config is set
173
+ mcpUrl: this.defaultServiceUrl,
155
174
  jwtToken: '', // Will be set when connection config is set
156
175
  uaaUrl: config.uaaUrl,
157
176
  uaaClientId: config.uaaClientId,
@@ -160,8 +179,10 @@ class SafeBtpSessionStore {
160
179
  };
161
180
  // Save directly to Map (internal format)
162
181
  this.sessions.set(destination, newSession);
182
+ this.log?.info(`New session created for ${destination} via setAuthorizationConfig: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
163
183
  return;
164
184
  }
185
+ this.log?.debug(`Updating authorization config for existing session ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
165
186
  const updated = {
166
187
  ...current,
167
188
  uaaUrl: config.uaaUrl,
@@ -171,6 +192,7 @@ class SafeBtpSessionStore {
171
192
  };
172
193
  // Save directly to Map (internal format)
173
194
  this.sessions.set(destination, updated);
195
+ this.log?.info(`Authorization config updated for ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
174
196
  }
175
197
  }
176
198
  exports.SafeBtpSessionStore = SafeBtpSessionStore;
@@ -14,11 +14,13 @@ import type { IConnectionConfig, ISessionStore, IAuthorizationConfig, IConfig, I
14
14
  export declare class SafeXsuaaSessionStore implements ISessionStore {
15
15
  private sessions;
16
16
  private log?;
17
+ private defaultServiceUrl;
17
18
  /**
18
19
  * Create a new SafeXsuaaSessionStore instance
20
+ * @param defaultServiceUrl Default service URL (required for XSUAA - cannot be obtained from service key)
19
21
  * @param log Optional logger for logging operations
20
22
  */
21
- constructor(log?: ILogger);
23
+ constructor(defaultServiceUrl: string, log?: ILogger);
22
24
  private loadRawSession;
23
25
  private validateSessionConfig;
24
26
  private convertToInternalFormat;
@@ -16,11 +16,14 @@ exports.SafeXsuaaSessionStore = void 0;
16
16
  class SafeXsuaaSessionStore {
17
17
  sessions = new Map();
18
18
  log;
19
+ defaultServiceUrl;
19
20
  /**
20
21
  * Create a new SafeXsuaaSessionStore instance
22
+ * @param defaultServiceUrl Default service URL (required for XSUAA - cannot be obtained from service key)
21
23
  * @param log Optional logger for logging operations
22
24
  */
23
- constructor(log) {
25
+ constructor(defaultServiceUrl, log) {
26
+ this.defaultServiceUrl = defaultServiceUrl;
24
27
  this.log = log;
25
28
  }
26
29
  loadRawSession(destination) {
@@ -90,7 +93,14 @@ class SafeXsuaaSessionStore {
90
93
  this.sessions.set(destination, internalConfig);
91
94
  }
92
95
  async deleteSession(destination) {
93
- this.sessions.delete(destination);
96
+ if (this.sessions.has(destination)) {
97
+ this.log?.debug(`Deleting session for destination: ${destination}`);
98
+ this.sessions.delete(destination);
99
+ this.log?.info(`Session deleted for destination: ${destination}`);
100
+ }
101
+ else {
102
+ this.log?.debug(`Session not found for deletion: ${destination}`);
103
+ }
94
104
  }
95
105
  async getConnectionConfig(destination) {
96
106
  const sessionConfig = this.loadRawSession(destination);
@@ -110,17 +120,19 @@ class SafeXsuaaSessionStore {
110
120
  const current = this.loadRawSession(destination);
111
121
  if (!current) {
112
122
  // Session doesn't exist - create new one
113
- // For XSUAA, mcpUrl is optional
114
- this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
123
+ // For XSUAA, use config.serviceUrl if provided, otherwise use defaultServiceUrl (required)
124
+ const serviceUrl = config.serviceUrl || this.defaultServiceUrl;
125
+ this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
115
126
  const newSession = {
116
- mcpUrl: config.serviceUrl,
127
+ mcpUrl: serviceUrl,
117
128
  jwtToken: config.authorizationToken || '',
118
129
  };
119
130
  // Save directly to Map (internal format)
120
131
  this.sessions.set(destination, newSession);
121
- this.log?.info(`Session created for ${destination}: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
132
+ this.log?.info(`Session created for ${destination}: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
122
133
  return;
123
134
  }
135
+ this.log?.debug(`Updating connection config for existing session ${destination}: serviceUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'unchanged'}), token(${config.authorizationToken?.length || 0} chars)`);
124
136
  const updated = {
125
137
  ...current,
126
138
  mcpUrl: config.serviceUrl !== undefined ? config.serviceUrl : current.mcpUrl,
@@ -128,15 +140,19 @@ class SafeXsuaaSessionStore {
128
140
  };
129
141
  // Save directly to Map (internal format)
130
142
  this.sessions.set(destination, updated);
143
+ this.log?.info(`Connection config updated for ${destination}: serviceUrl(${updated.mcpUrl ? updated.mcpUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
131
144
  }
132
145
  async getAuthorizationConfig(destination) {
133
146
  const sessionConfig = this.loadRawSession(destination);
134
147
  if (!sessionConfig) {
148
+ this.log?.debug(`Authorization config not found for ${destination}`);
135
149
  return null;
136
150
  }
137
151
  if (!sessionConfig.uaaUrl || !sessionConfig.uaaClientId || !sessionConfig.uaaClientSecret) {
152
+ this.log?.warn(`Authorization config for ${destination} missing required UAA fields`);
138
153
  return null;
139
154
  }
155
+ this.log?.debug(`Authorization config loaded for ${destination}: uaaUrl(${sessionConfig.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!sessionConfig.refreshToken})`);
140
156
  return {
141
157
  uaaUrl: sessionConfig.uaaUrl,
142
158
  uaaClientId: sessionConfig.uaaClientId,
@@ -148,10 +164,10 @@ class SafeXsuaaSessionStore {
148
164
  const current = this.loadRawSession(destination);
149
165
  if (!current) {
150
166
  // Session doesn't exist - create new one
151
- // For XSUAA, mcpUrl is optional, so we can create session without it
152
- this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig`);
167
+ // For XSUAA, use defaultServiceUrl (required - cannot be obtained from service key)
168
+ this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: mcpUrl(${this.defaultServiceUrl.substring(0, 40)}...)`);
153
169
  const newSession = {
154
- mcpUrl: undefined, // Will be set when connection config is set
170
+ mcpUrl: this.defaultServiceUrl,
155
171
  jwtToken: '', // Will be set when connection config is set
156
172
  uaaUrl: config.uaaUrl,
157
173
  uaaClientId: config.uaaClientId,
@@ -160,8 +176,10 @@ class SafeXsuaaSessionStore {
160
176
  };
161
177
  // Save directly to Map (internal format)
162
178
  this.sessions.set(destination, newSession);
179
+ this.log?.info(`New session created for ${destination} via setAuthorizationConfig: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
163
180
  return;
164
181
  }
182
+ this.log?.debug(`Updating authorization config for existing session ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
165
183
  const updated = {
166
184
  ...current,
167
185
  uaaUrl: config.uaaUrl,
@@ -171,6 +189,7 @@ class SafeXsuaaSessionStore {
171
189
  };
172
190
  // Save directly to Map (internal format)
173
191
  this.sessions.set(destination, updated);
192
+ this.log?.info(`Authorization config updated for ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
174
193
  }
175
194
  }
176
195
  exports.SafeXsuaaSessionStore = SafeXsuaaSessionStore;
@@ -17,12 +17,14 @@ import type { IAuthorizationConfig, IConnectionConfig, ISessionStore, IConfig, I
17
17
  export declare class XsuaaSessionStore implements ISessionStore {
18
18
  protected directory: string;
19
19
  private log?;
20
+ private defaultServiceUrl;
20
21
  /**
21
22
  * Create a new XsuaaSessionStore instance
22
23
  * @param directory Directory where session .env files are located
24
+ * @param defaultServiceUrl Default service URL (required for XSUAA - cannot be obtained from service key)
23
25
  * @param log Optional logger for logging operations
24
26
  */
25
- constructor(directory: string, log?: ILogger);
27
+ constructor(directory: string, defaultServiceUrl: string, log?: ILogger);
26
28
  /**
27
29
  * Get file name for destination
28
30
  * @param destination Destination name
@@ -56,13 +56,16 @@ const path = __importStar(require("path"));
56
56
  class XsuaaSessionStore {
57
57
  directory;
58
58
  log;
59
+ defaultServiceUrl;
59
60
  /**
60
61
  * Create a new XsuaaSessionStore instance
61
62
  * @param directory Directory where session .env files are located
63
+ * @param defaultServiceUrl Default service URL (required for XSUAA - cannot be obtained from service key)
62
64
  * @param log Optional logger for logging operations
63
65
  */
64
- constructor(directory, log) {
66
+ constructor(directory, defaultServiceUrl, log) {
65
67
  this.directory = directory;
68
+ this.defaultServiceUrl = defaultServiceUrl;
66
69
  this.log = log;
67
70
  // Ensure directory exists - create if it doesn't
68
71
  if (!fs.existsSync(directory)) {
@@ -172,7 +175,12 @@ class XsuaaSessionStore {
172
175
  const fileName = `${destination}.env`;
173
176
  const filePath = path.join(this.directory, fileName);
174
177
  if (fs.existsSync(filePath)) {
178
+ this.log?.debug(`Deleting session for destination: ${destination}`);
175
179
  fs.unlinkSync(filePath);
180
+ this.log?.info(`Session deleted for destination: ${destination}`);
181
+ }
182
+ else {
183
+ this.log?.debug(`Session file not found for deletion: ${destination}`);
176
184
  }
177
185
  }
178
186
  /**
@@ -211,11 +219,13 @@ class XsuaaSessionStore {
211
219
  try {
212
220
  const raw = await this.loadFromFile(sessionPath);
213
221
  if (!raw || !isXsuaaSessionConfig(raw)) {
222
+ this.log?.debug(`Invalid session format for ${destination}: missing required fields (jwtToken)`);
214
223
  return null;
215
224
  }
216
225
  return raw;
217
226
  }
218
227
  catch (error) {
228
+ this.log?.error(`Error loading session for ${destination}: ${error instanceof Error ? error.message : String(error)}`);
219
229
  return null;
220
230
  }
221
231
  }
@@ -240,23 +250,26 @@ class XsuaaSessionStore {
240
250
  const current = await this.loadRawSession(destination);
241
251
  if (!current) {
242
252
  // Session doesn't exist - create new one
243
- // For XSUAA, mcpUrl is optional
244
- this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
253
+ // For XSUAA, use config.serviceUrl if provided, otherwise use defaultServiceUrl (required)
254
+ const serviceUrl = config.serviceUrl || this.defaultServiceUrl;
255
+ this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
245
256
  const newSession = {
246
- mcpUrl: config.serviceUrl,
257
+ mcpUrl: serviceUrl,
247
258
  jwtToken: config.authorizationToken || '',
248
259
  };
249
260
  await this.saveSession(destination, newSession);
250
- this.log?.info(`Session created for ${destination}: mcpUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
261
+ this.log?.info(`Session created for ${destination}: mcpUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
251
262
  return;
252
263
  }
253
264
  // Update connection fields
265
+ this.log?.debug(`Updating connection config for existing session ${destination}: serviceUrl(${config.serviceUrl ? config.serviceUrl.substring(0, 40) + '...' : 'unchanged'}), token(${config.authorizationToken?.length || 0} chars)`);
254
266
  const updated = {
255
267
  ...current,
256
268
  mcpUrl: config.serviceUrl !== undefined ? config.serviceUrl : current.mcpUrl,
257
269
  jwtToken: config.authorizationToken !== undefined ? config.authorizationToken : current.jwtToken,
258
270
  };
259
271
  await this.saveSession(destination, updated);
272
+ this.log?.info(`Connection config updated for ${destination}: serviceUrl(${updated.mcpUrl ? updated.mcpUrl.substring(0, 40) + '...' : 'none'}), token(${config.authorizationToken?.length || 0} chars)`);
260
273
  }
261
274
  async getAuthorizationConfig(destination) {
262
275
  const sessionConfig = await this.loadRawSession(destination);
@@ -280,10 +293,10 @@ class XsuaaSessionStore {
280
293
  const current = await this.loadRawSession(destination);
281
294
  if (!current) {
282
295
  // Session doesn't exist - create new one
283
- // For XSUAA, mcpUrl is optional, so we can create session without it
284
- this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig`);
296
+ // For XSUAA, use defaultServiceUrl (required - cannot be obtained from service key)
297
+ this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: mcpUrl(${this.defaultServiceUrl.substring(0, 40)}...)`);
285
298
  const newSession = {
286
- mcpUrl: undefined, // Will be set when connection config is set
299
+ mcpUrl: this.defaultServiceUrl,
287
300
  jwtToken: '', // Will be set when connection config is set
288
301
  uaaUrl: config.uaaUrl,
289
302
  uaaClientId: config.uaaClientId,
@@ -291,9 +304,11 @@ class XsuaaSessionStore {
291
304
  refreshToken: config.refreshToken,
292
305
  };
293
306
  await this.saveSession(destination, newSession);
307
+ this.log?.info(`New session created for ${destination} via setAuthorizationConfig: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
294
308
  return;
295
309
  }
296
310
  // Update authorization fields
311
+ this.log?.debug(`Updating authorization config for existing session ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
297
312
  const updated = {
298
313
  ...current,
299
314
  uaaUrl: config.uaaUrl,
@@ -302,6 +317,7 @@ class XsuaaSessionStore {
302
317
  refreshToken: config.refreshToken || current.refreshToken,
303
318
  };
304
319
  await this.saveSession(destination, updated);
320
+ this.log?.info(`Authorization config updated for ${destination}: uaaUrl(${config.uaaUrl.substring(0, 30)}...), hasRefreshToken(${!!config.refreshToken})`);
305
321
  }
306
322
  }
307
323
  exports.XsuaaSessionStore = XsuaaSessionStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/auth-stores",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
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.1.3",
52
+ "@mcp-abap-adt/interfaces": "^0.1.4",
53
53
  "dotenv": "^17.2.1"
54
54
  },
55
55
  "devDependencies": {