@mcp-abap-adt/connection 0.1.15 → 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.
@@ -48,16 +48,12 @@ class AbstractAbapConnection {
48
48
  cookieStore = new Map();
49
49
  baseUrl;
50
50
  sessionId = null;
51
- sessionStorage = null;
52
51
  sessionMode = "stateless";
53
- constructor(config, logger, sessionStorage, sessionId) {
52
+ constructor(config, logger, sessionId) {
54
53
  this.config = config;
55
54
  this.logger = logger;
56
- this.sessionStorage = sessionStorage || null;
57
- // Always generate sessionId (used for sap-adt-connection-id header in all session types)
55
+ // Generate sessionId (used for sap-adt-connection-id header)
58
56
  this.sessionId = sessionId || (0, crypto_1.randomUUID)();
59
- // Session mode depends only on storage availability (sessionId exists for both modes)
60
- this.sessionMode = sessionStorage ? "stateful" : "stateless";
61
57
  // Initialize baseUrl from config (required, will throw if invalid)
62
58
  try {
63
59
  const urlObj = new URL(config.url);
@@ -66,7 +62,7 @@ class AbstractAbapConnection {
66
62
  catch (error) {
67
63
  throw new Error(`Invalid URL in configuration: ${error instanceof Error ? error.message : error}`);
68
64
  }
69
- this.logger.debug(`AbstractAbapConnection - Session ID: ${this.sessionId.substring(0, 8)}..., mode: ${this.sessionMode}`);
65
+ this.logger?.debug(`AbstractAbapConnection - Session ID: ${this.sessionId.substring(0, 8)}...`);
70
66
  }
71
67
  /**
72
68
  * Set session type (stateful or stateless)
@@ -76,15 +72,13 @@ class AbstractAbapConnection {
76
72
  */
77
73
  setSessionType(type) {
78
74
  this.sessionMode = type;
79
- this.logger.debug(`Session type set to: ${type}`, {
80
- sessionId: this.sessionId?.substring(0, 8),
81
- hasStorage: !!this.sessionStorage
75
+ this.logger?.debug(`Session type set to: ${type}`, {
76
+ sessionId: this.sessionId?.substring(0, 8)
82
77
  });
83
78
  }
84
79
  /**
85
80
  * Enable stateful session mode (tells SAP to maintain stateful session)
86
81
  * This controls whether x-sap-adt-sessiontype: stateful header is used
87
- * Storage is controlled separately via setSessionStorage()
88
82
  * @deprecated Use setSessionType("stateful") instead
89
83
  */
90
84
  enableStatefulSession() {
@@ -92,20 +86,14 @@ class AbstractAbapConnection {
92
86
  }
93
87
  /**
94
88
  * Disable stateful session mode (switch to stateless)
95
- * Optionally saves current state before switching
96
89
  * @deprecated Use setSessionType("stateless") instead
97
90
  */
98
- async disableStatefulSession(saveBeforeDisable = false) {
91
+ disableStatefulSession() {
99
92
  if (this.sessionMode === "stateless") {
100
93
  return;
101
94
  }
102
- if (saveBeforeDisable && this.sessionId && this.sessionStorage) {
103
- await this.saveSessionState();
104
- }
105
95
  this.sessionMode = "stateless";
106
- this.logger.debug("Stateful session mode disabled", {
107
- savedBeforeDisable: saveBeforeDisable
108
- });
96
+ this.logger?.debug("Stateful session mode disabled");
109
97
  }
110
98
  /**
111
99
  * Get current session mode
@@ -114,18 +102,12 @@ class AbstractAbapConnection {
114
102
  return this.sessionMode;
115
103
  }
116
104
  /**
117
- * Set session ID for stateful operations
118
- * When session ID is set, session state (cookies, CSRF token) will be persisted
119
- * @deprecated Use enableStatefulSession() instead
105
+ * Set session ID
106
+ * @deprecated Session ID is auto-generated, use setSessionType() to control session mode
120
107
  */
121
108
  setSessionId(sessionId) {
122
- if (this.sessionStorage) {
123
- this.sessionId = sessionId;
124
- this.sessionMode = "stateful";
125
- }
126
- else {
127
- this.logger.warn("Cannot set session ID without session storage. Use enableStatefulSession() instead.");
128
- }
109
+ this.sessionId = sessionId;
110
+ this.logger?.debug(`Session ID set to: ${sessionId.substring(0, 8)}...`);
129
111
  }
130
112
  /**
131
113
  * Get current session ID
@@ -133,132 +115,6 @@ class AbstractAbapConnection {
133
115
  getSessionId() {
134
116
  return this.sessionId;
135
117
  }
136
- /**
137
- * Set session storage (can be changed at runtime)
138
- * This controls whether session state (cookies, CSRF token) is persisted to disk/storage
139
- */
140
- async setSessionStorage(storage) {
141
- this.sessionStorage = storage;
142
- // Load existing session state if storage is provided
143
- if (storage && this.sessionId) {
144
- await this.loadSessionState();
145
- }
146
- this.logger.debug("Session storage configured", {
147
- hasStorage: !!storage,
148
- sessionMode: this.sessionMode
149
- });
150
- }
151
- /**
152
- * Get current session storage
153
- */
154
- getSessionStorage() {
155
- return this.sessionStorage;
156
- }
157
- /**
158
- * Load session state from storage
159
- */
160
- async loadSessionState() {
161
- if (!this.sessionId || !this.sessionStorage) {
162
- return;
163
- }
164
- try {
165
- const state = await this.sessionStorage.load(this.sessionId);
166
- if (state) {
167
- this.csrfToken = state.csrfToken;
168
- this.cookies = state.cookies;
169
- this.cookieStore = new Map(Object.entries(state.cookieStore));
170
- this.logger.debug("Session state loaded", {
171
- sessionId: this.sessionId,
172
- hasCookies: !!this.cookies,
173
- hasCsrfToken: !!this.csrfToken
174
- });
175
- }
176
- }
177
- catch (error) {
178
- this.logger.warn("Failed to load session state", {
179
- sessionId: this.sessionId,
180
- error: error instanceof Error ? error.message : String(error)
181
- });
182
- }
183
- }
184
- /**
185
- * Save session state to storage
186
- * Only saves if in stateful mode
187
- */
188
- async saveSessionState() {
189
- if (this.sessionMode !== "stateful" || !this.sessionId || !this.sessionStorage) {
190
- return;
191
- }
192
- try {
193
- const state = {
194
- cookies: this.cookies,
195
- csrfToken: this.csrfToken,
196
- cookieStore: Object.fromEntries(this.cookieStore)
197
- };
198
- await this.sessionStorage.save(this.sessionId, state);
199
- this.logger.debug("Session state saved", {
200
- sessionId: this.sessionId,
201
- hasCookies: !!this.cookies,
202
- hasCsrfToken: !!this.csrfToken
203
- });
204
- }
205
- catch (error) {
206
- this.logger.warn("Failed to save session state", {
207
- sessionId: this.sessionId,
208
- error: error instanceof Error ? error.message : String(error)
209
- });
210
- }
211
- }
212
- /**
213
- * Get current session state
214
- * Returns cookies, CSRF token, and cookie store for manual persistence
215
- * @returns Current session state or null if no session data
216
- */
217
- getSessionState() {
218
- if (!this.cookies && !this.csrfToken) {
219
- return null;
220
- }
221
- return {
222
- cookies: this.cookies,
223
- csrfToken: this.csrfToken,
224
- cookieStore: Object.fromEntries(this.cookieStore)
225
- };
226
- }
227
- /**
228
- * Set session state manually
229
- * Allows user to restore session from custom storage (e.g., database, Redis)
230
- * @param state - Session state with cookies, CSRF token, and cookie store
231
- */
232
- setSessionState(state) {
233
- this.cookies = state.cookies || null;
234
- this.csrfToken = state.csrfToken || null;
235
- this.cookieStore = new Map(Object.entries(state.cookieStore || {}));
236
- this.logger.debug("Session state set manually", {
237
- hasCookies: !!this.cookies,
238
- hasCsrfToken: !!this.csrfToken,
239
- cookieCount: this.cookieStore.size
240
- });
241
- }
242
- /**
243
- * Clear session state from storage
244
- */
245
- async clearSessionState() {
246
- if (!this.sessionId || !this.sessionStorage) {
247
- return;
248
- }
249
- try {
250
- await this.sessionStorage.delete(this.sessionId);
251
- this.logger.debug("Session state cleared", {
252
- sessionId: this.sessionId
253
- });
254
- }
255
- catch (error) {
256
- this.logger.warn("Failed to clear session state", {
257
- sessionId: this.sessionId,
258
- error: error instanceof Error ? error.message : String(error)
259
- });
260
- }
261
- }
262
118
  getConfig() {
263
119
  return this.config;
264
120
  }
@@ -302,7 +158,7 @@ class AbstractAbapConnection {
302
158
  catch (error) {
303
159
  // If CSRF token can't be fetched upfront, continue anyway
304
160
  // The retry logic will handle CSRF token errors automatically
305
- this.logger.debug(`[DEBUG] BaseAbapConnection - Could not fetch CSRF token upfront, will retry on error: ${error instanceof Error ? error.message : String(error)}`);
161
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Could not fetch CSRF token upfront, will retry on error: ${error instanceof Error ? error.message : String(error)}`);
306
162
  }
307
163
  }
308
164
  }
@@ -333,10 +189,10 @@ class AbstractAbapConnection {
333
189
  // Add cookies LAST (MUST NOT be overridden by custom headers)
334
190
  if (this.cookies) {
335
191
  requestHeaders["Cookie"] = this.cookies;
336
- this.logger.debug(`[DEBUG] BaseAbapConnection - Adding cookies to request (first 100 chars): ${this.cookies.substring(0, 100)}...`);
192
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Adding cookies to request (first 100 chars): ${this.cookies.substring(0, 100)}...`);
337
193
  }
338
194
  else {
339
- this.logger.debug(`[DEBUG] BaseAbapConnection - NO COOKIES available for this request to ${requestUrl}`);
195
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - NO COOKIES available for this request to ${requestUrl}`);
340
196
  }
341
197
  if ((normalizedMethod === "POST" || normalizedMethod === "PUT") && data) {
342
198
  if (typeof data === "string" && !requestHeaders["Content-Type"]) {
@@ -359,7 +215,7 @@ class AbstractAbapConnection {
359
215
  if (data !== undefined) {
360
216
  requestConfig.data = data;
361
217
  }
362
- this.logger.debug(`Executing ${normalizedMethod} request to: ${requestUrl}`, {
218
+ this.logger?.debug(`Executing ${normalizedMethod} request to: ${requestUrl}`, {
363
219
  type: "REQUEST_INFO",
364
220
  url: requestUrl,
365
221
  method: normalizedMethod
@@ -367,9 +223,7 @@ class AbstractAbapConnection {
367
223
  try {
368
224
  const response = await this.getAxiosInstance()(requestConfig);
369
225
  this.updateCookiesFromResponse(response.headers);
370
- // Save session state after successful request (if session storage is configured)
371
- await this.saveSessionState();
372
- this.logger.debug(`Request succeeded with status ${response.status}`, {
226
+ this.logger?.debug(`Request succeeded with status ${response.status}`, {
373
227
  type: "REQUEST_SUCCESS",
374
228
  status: response.status,
375
229
  url: requestUrl,
@@ -393,18 +247,16 @@ class AbstractAbapConnection {
393
247
  : JSON.stringify(error.response.data).slice(0, 200);
394
248
  this.updateCookiesFromResponse(error.response.headers);
395
249
  }
396
- // Save session state even on error (cookies might have been updated)
397
- await this.saveSessionState();
398
250
  // Log 404 as debug (common for existence checks), other errors as error
399
251
  if (errorDetails.status === 404) {
400
- this.logger.debug(errorDetails.message, errorDetails);
252
+ this.logger?.debug(errorDetails.message, errorDetails);
401
253
  }
402
254
  else {
403
- this.logger.error(errorDetails.message, errorDetails);
255
+ this.logger?.error(errorDetails.message, errorDetails);
404
256
  }
405
257
  // Retry logic for CSRF token errors (403 with CSRF message)
406
258
  if (this.shouldRetryCsrf(error)) {
407
- this.logger.debug("CSRF token validation failed, fetching new token and retrying request", {
259
+ this.logger?.debug("CSRF token validation failed, fetching new token and retrying request", {
408
260
  url: requestUrl,
409
261
  method: normalizedMethod
410
262
  });
@@ -417,8 +269,6 @@ class AbstractAbapConnection {
417
269
  }
418
270
  const retryResponse = await this.getAxiosInstance()(requestConfig);
419
271
  this.updateCookiesFromResponse(retryResponse.headers);
420
- // Save session state after retry
421
- await this.saveSessionState();
422
272
  return retryResponse;
423
273
  }
424
274
  // Retry logic for 401 errors on GET requests (authentication issue - need cookies)
@@ -430,29 +280,27 @@ class AbstractAbapConnection {
430
280
  ) {
431
281
  // If we already have cookies from error response, retry immediately
432
282
  if (this.cookies) {
433
- this.logger.debug(`[DEBUG] BaseAbapConnection - 401 on GET request, retrying with cookies from error response`);
283
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - 401 on GET request, retrying with cookies from error response`);
434
284
  requestHeaders["Cookie"] = this.cookies;
435
285
  const retryResponse = await this.getAxiosInstance()(requestConfig);
436
286
  this.updateCookiesFromResponse(retryResponse.headers);
437
- await this.saveSessionState();
438
287
  return retryResponse;
439
288
  }
440
289
  // If no cookies, try to get them via CSRF token fetch
441
- this.logger.debug(`[DEBUG] BaseAbapConnection - 401 on GET request, attempting to get cookies via CSRF token fetch`);
290
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - 401 on GET request, attempting to get cookies via CSRF token fetch`);
442
291
  try {
443
292
  // Try to get CSRF token (this will also get cookies)
444
293
  this.csrfToken = await this.fetchCsrfToken(requestUrl, 3, 1000);
445
294
  if (this.cookies) {
446
295
  requestHeaders["Cookie"] = this.cookies;
447
- this.logger.debug(`[DEBUG] BaseAbapConnection - Retrying GET request with cookies from CSRF fetch`);
296
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Retrying GET request with cookies from CSRF fetch`);
448
297
  const retryResponse = await this.getAxiosInstance()(requestConfig);
449
298
  this.updateCookiesFromResponse(retryResponse.headers);
450
- await this.saveSessionState();
451
299
  return retryResponse;
452
300
  }
453
301
  }
454
302
  catch (csrfError) {
455
- this.logger.debug(`[DEBUG] BaseAbapConnection - Failed to get CSRF token for 401 retry: ${csrfError instanceof Error ? csrfError.message : String(csrfError)}`);
303
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Failed to get CSRF token for 401 retry: ${csrfError instanceof Error ? csrfError.message : String(csrfError)}`);
456
304
  // Fall through to throw original error
457
305
  }
458
306
  }
@@ -476,11 +324,11 @@ class AbstractAbapConnection {
476
324
  csrfUrl = `${base}${csrfConfig_js_1.CSRF_CONFIG.ENDPOINT}`;
477
325
  }
478
326
  // If URL already contains the endpoint, use it as is
479
- this.logger.debug(`Fetching CSRF token from: ${csrfUrl}`);
327
+ this.logger?.debug(`Fetching CSRF token from: ${csrfUrl}`);
480
328
  for (let attempt = 0; attempt <= retryCount; attempt++) {
481
329
  try {
482
330
  if (attempt > 0) {
483
- this.logger.debug(`Retry attempt ${attempt}/${retryCount} for CSRF token`);
331
+ this.logger?.debug(`Retry attempt ${attempt}/${retryCount} for CSRF token`);
484
332
  }
485
333
  const authHeaders = await this.getAuthHeaders();
486
334
  const headers = {
@@ -491,13 +339,13 @@ class AbstractAbapConnection {
491
339
  // Even on first attempt, if we have cookies from previous session or error response, use them
492
340
  if (this.cookies) {
493
341
  headers["Cookie"] = this.cookies;
494
- this.logger.debug(`[DEBUG] BaseAbapConnection - Adding cookies to CSRF token request (attempt ${attempt + 1}, first 100 chars): ${this.cookies.substring(0, 100)}...`);
342
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Adding cookies to CSRF token request (attempt ${attempt + 1}, first 100 chars): ${this.cookies.substring(0, 100)}...`);
495
343
  }
496
344
  else {
497
- this.logger.debug(`[DEBUG] BaseAbapConnection - No cookies available for CSRF token request (will get fresh cookies from response)`);
345
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - No cookies available for CSRF token request (will get fresh cookies from response)`);
498
346
  }
499
347
  // Log request details for debugging (only if debug logging is enabled)
500
- this.logger.debug(`[DEBUG] CSRF Token Request: url=${csrfUrl}, method=GET, hasAuth=${!!authHeaders.Authorization}, hasClient=${!!authHeaders["X-SAP-Client"]}, hasCookies=${!!headers["Cookie"]}, attempt=${attempt + 1}`);
348
+ this.logger?.debug(`[DEBUG] CSRF Token Request: url=${csrfUrl}, method=GET, hasAuth=${!!authHeaders.Authorization}, hasClient=${!!authHeaders["X-SAP-Client"]}, hasCookies=${!!headers["Cookie"]}, attempt=${attempt + 1}`);
501
349
  const response = await this.getAxiosInstance()({
502
350
  method: "GET",
503
351
  url: csrfUrl,
@@ -507,7 +355,7 @@ class AbstractAbapConnection {
507
355
  this.updateCookiesFromResponse(response.headers);
508
356
  const token = response.headers["x-csrf-token"];
509
357
  if (!token) {
510
- this.logger.error("No CSRF token in response headers", {
358
+ this.logger?.error("No CSRF token in response headers", {
511
359
  headers: response.headers,
512
360
  status: response.status
513
361
  });
@@ -520,15 +368,13 @@ class AbstractAbapConnection {
520
368
  if (response.headers["set-cookie"]) {
521
369
  this.updateCookiesFromResponse(response.headers);
522
370
  if (this.cookies) {
523
- this.logger.debug(`[DEBUG] BaseAbapConnection - Cookies received from CSRF response (first 100 chars): ${this.cookies.substring(0, 100)}...`);
524
- this.logger.debug("Cookies extracted from response", {
371
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Cookies received from CSRF response (first 100 chars): ${this.cookies.substring(0, 100)}...`);
372
+ this.logger?.debug("Cookies extracted from response", {
525
373
  cookieLength: this.cookies.length
526
374
  });
527
375
  }
528
376
  }
529
- // Save session state after CSRF token fetch (cookies and token are now available)
530
- await this.saveSessionState();
531
- this.logger.debug("CSRF token successfully obtained");
377
+ this.logger?.debug("CSRF token successfully obtained");
532
378
  return token;
533
379
  }
534
380
  catch (error) {
@@ -538,20 +384,20 @@ class AbstractAbapConnection {
538
384
  if (error.response?.headers) {
539
385
  this.updateCookiesFromResponse(error.response.headers);
540
386
  if (this.cookies) {
541
- this.logger.debug("Cookies extracted from error response", {
387
+ this.logger?.debug("Cookies extracted from error response", {
542
388
  status: error.response.status,
543
389
  cookieLength: this.cookies.length
544
390
  });
545
391
  }
546
392
  }
547
- this.logger.error(`CSRF token error: ${error.message}`, {
393
+ this.logger?.error(`CSRF token error: ${error.message}`, {
548
394
  url: csrfUrl,
549
395
  status: error.response?.status,
550
396
  attempt: attempt + 1,
551
397
  maxAttempts: retryCount + 1
552
398
  });
553
399
  if (error.response?.status === 405 && error.response?.headers["x-csrf-token"]) {
554
- this.logger.debug("CSRF: SAP returned 405 (Method Not Allowed) — not critical, token found in header");
400
+ this.logger?.debug("CSRF: SAP returned 405 (Method Not Allowed) — not critical, token found in header");
555
401
  const token = error.response.headers["x-csrf-token"];
556
402
  if (token) {
557
403
  this.updateCookiesFromResponse(error.response.headers);
@@ -559,13 +405,13 @@ class AbstractAbapConnection {
559
405
  }
560
406
  }
561
407
  if (error.response?.headers["x-csrf-token"]) {
562
- this.logger.debug(`Got CSRF token despite error (status: ${error.response?.status})`);
408
+ this.logger?.debug(`Got CSRF token despite error (status: ${error.response?.status})`);
563
409
  const token = error.response.headers["x-csrf-token"];
564
410
  this.updateCookiesFromResponse(error.response.headers);
565
411
  return token;
566
412
  }
567
413
  if (error.response) {
568
- this.logger.error("CSRF error details", {
414
+ this.logger?.error("CSRF error details", {
569
415
  status: error.response.status,
570
416
  statusText: error.response.statusText,
571
417
  headers: Object.keys(error.response.headers),
@@ -575,13 +421,13 @@ class AbstractAbapConnection {
575
421
  });
576
422
  }
577
423
  else if (error.request) {
578
- this.logger.error("CSRF request error - no response received", {
424
+ this.logger?.error("CSRF request error - no response received", {
579
425
  request: error.request.path
580
426
  });
581
427
  }
582
428
  }
583
429
  else {
584
- this.logger.error("CSRF non-axios error", {
430
+ this.logger?.error("CSRF non-axios error", {
585
431
  error: error instanceof Error ? error.message : String(error)
586
432
  });
587
433
  }
@@ -655,14 +501,14 @@ class AbstractAbapConnection {
655
501
  return;
656
502
  }
657
503
  this.cookies = combined;
658
- this.logger.debug(`[DEBUG] BaseAbapConnection - Updated cookies from response (first 100 chars): ${this.cookies.substring(0, 100)}...`);
504
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Updated cookies from response (first 100 chars): ${this.cookies.substring(0, 100)}...`);
659
505
  }
660
506
  getAxiosInstance() {
661
507
  if (!this.axiosInstance) {
662
508
  const rejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === "1" ||
663
509
  (process.env.TLS_REJECT_UNAUTHORIZED === "1" &&
664
510
  process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0");
665
- this.logger.debug(`TLS configuration: rejectUnauthorized=${rejectUnauthorized}`);
511
+ this.logger?.debug(`TLS configuration: rejectUnauthorized=${rejectUnauthorized}`);
666
512
  this.axiosInstance = axios_1.default.create({
667
513
  httpsAgent: new https_1.Agent({
668
514
  rejectUnauthorized
@@ -675,20 +521,20 @@ class AbstractAbapConnection {
675
521
  // If we already have a CSRF token, reuse it to keep the same SAP session
676
522
  // SAP ties the lock handle to the HTTP session (SAP_SESSIONID cookie)
677
523
  if (this.csrfToken) {
678
- this.logger.debug(`[DEBUG] BaseAbapConnection - Reusing existing CSRF token to maintain session`);
524
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Reusing existing CSRF token to maintain session`);
679
525
  return;
680
526
  }
681
527
  try {
682
- this.logger.debug(`[DEBUG] BaseAbapConnection - Fetching NEW CSRF token (will create new SAP session)`);
528
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Fetching NEW CSRF token (will create new SAP session)`);
683
529
  this.csrfToken = await this.fetchCsrfToken(requestUrl);
684
530
  }
685
531
  catch (error) {
686
- // fetchCsrfToken already handles auth errors and auto-refresh
532
+ // fetchCsrfToken handles auth errors
687
533
  // Just re-throw the error with minimal logging to avoid duplicate error messages
688
534
  const errorMsg = error instanceof Error ? error.message : csrfConfig_js_1.CSRF_ERROR_MESSAGES.REQUIRED_FOR_MUTATION;
689
535
  // Only log at DEBUG level to avoid duplicate error messages
690
536
  // (fetchCsrfToken already logged the error at ERROR level if auth failed)
691
- this.logger.debug(`[DEBUG] BaseAbapConnection - ensureFreshCsrfToken failed: ${errorMsg}`);
537
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - ensureFreshCsrfToken failed: ${errorMsg}`);
692
538
  throw error;
693
539
  }
694
540
  }
@@ -1,11 +1,11 @@
1
1
  import { SapConfig } from "../config/sapConfig.js";
2
2
  import { AbstractAbapConnection } from "./AbstractAbapConnection.js";
3
- import { ILogger, ISessionStorage } from "../logger.js";
3
+ import { ILogger } from "../logger.js";
4
4
  /**
5
5
  * Basic Authentication connection for on-premise SAP systems
6
6
  */
7
7
  export declare class BaseAbapConnection extends AbstractAbapConnection {
8
- constructor(config: SapConfig, logger: ILogger, sessionStorage?: ISessionStorage, sessionId?: string);
8
+ constructor(config: SapConfig, logger?: ILogger | null, sessionId?: string);
9
9
  /**
10
10
  * Connect to SAP system with Basic Auth
11
11
  * Fetches CSRF token which also establishes session cookies
@@ -1 +1 @@
1
- {"version":3,"file":"BaseAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/BaseAbapConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGxD;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,sBAAsB;gBAE1D,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,OAAO,EACf,cAAc,CAAC,EAAE,eAAe,EAChC,SAAS,CAAC,EAAE,MAAM;IAMpB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC9B,SAAS,CAAC,wBAAwB,IAAI,MAAM;IAQ5C,OAAO,CAAC,MAAM,CAAC,cAAc;CAa9B"}
1
+ {"version":3,"file":"BaseAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/BaseAbapConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,sBAAsB;gBAE1D,MAAM,EAAE,SAAS,EACjB,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,CAAC,EAAE,MAAM;IAMpB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC9B,SAAS,CAAC,wBAAwB,IAAI,MAAM;IAQ5C,OAAO,CAAC,MAAM,CAAC,cAAc;CAa9B"}
@@ -7,9 +7,9 @@ const axios_1 = require("axios");
7
7
  * Basic Authentication connection for on-premise SAP systems
8
8
  */
9
9
  class BaseAbapConnection extends AbstractAbapConnection_js_1.AbstractAbapConnection {
10
- constructor(config, logger, sessionStorage, sessionId) {
10
+ constructor(config, logger, sessionId) {
11
11
  BaseAbapConnection.validateConfig(config);
12
- super(config, logger, sessionStorage, sessionId);
12
+ super(config, logger || null, sessionId);
13
13
  }
14
14
  /**
15
15
  * Connect to SAP system with Basic Auth
@@ -18,14 +18,12 @@ class BaseAbapConnection extends AbstractAbapConnection_js_1.AbstractAbapConnect
18
18
  async connect() {
19
19
  const baseUrl = await this.getBaseUrl();
20
20
  const discoveryUrl = `${baseUrl}/sap/bc/adt/discovery`;
21
- this.logger.debug(`[DEBUG] BaseAbapConnection - Connecting to SAP system: ${discoveryUrl}`);
21
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Connecting to SAP system: ${discoveryUrl}`);
22
22
  try {
23
23
  // Try to get CSRF token (this will also get cookies)
24
24
  const token = await this.fetchCsrfToken(discoveryUrl, 3, 1000);
25
25
  this.setCsrfToken(token);
26
- // Save session state after successful connection
27
- await this.saveSessionState();
28
- this.logger.debug("Successfully connected to SAP system", {
26
+ this.logger?.debug("Successfully connected to SAP system", {
29
27
  hasCsrfToken: !!this.getCsrfToken(),
30
28
  hasCookies: !!this.getCookies(),
31
29
  cookieLength: this.getCookies()?.length || 0
@@ -35,13 +33,12 @@ class BaseAbapConnection extends AbstractAbapConnection_js_1.AbstractAbapConnect
35
33
  // For Basic auth, log warning but don't fail
36
34
  // The retry logic in makeAdtRequest will handle transient errors automatically
37
35
  const errorMsg = error instanceof Error ? error.message : String(error);
38
- this.logger.warn(`[WARN] BaseAbapConnection - Could not connect to SAP system upfront: ${errorMsg}. Will retry on first request.`);
36
+ this.logger?.warn(`[WARN] BaseAbapConnection - Could not connect to SAP system upfront: ${errorMsg}. Will retry on first request.`);
39
37
  // Still try to extract cookies from error response if available
40
38
  if (error instanceof axios_1.AxiosError && error.response?.headers) {
41
39
  // updateCookiesFromResponse is private, but cookies are extracted in fetchCsrfToken
42
40
  if (this.getCookies()) {
43
- this.logger.debug(`[DEBUG] BaseAbapConnection - Cookies extracted from error response during connect (first 100 chars): ${this.getCookies().substring(0, 100)}...`);
44
- await this.saveSessionState();
41
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - Cookies extracted from error response during connect (first 100 chars): ${this.getCookies().substring(0, 100)}...`);
45
42
  }
46
43
  }
47
44
  }
@@ -1,36 +1,28 @@
1
1
  import { SapConfig } from "../config/sapConfig.js";
2
2
  import { AbstractAbapConnection } from "./AbstractAbapConnection.js";
3
3
  import { AbapRequestOptions } from "./AbapConnection.js";
4
- import { ILogger, ISessionStorage } from "../logger.js";
4
+ import { ILogger } from "../logger.js";
5
5
  import { AxiosResponse } from "axios";
6
6
  /**
7
7
  * JWT Authentication connection for SAP BTP Cloud systems
8
- * Supports automatic token refresh using OAuth2 refresh tokens
8
+ * Note: Token refresh functionality is not supported in this package.
9
+ * Use @mcp-abap-adt/auth-broker for token refresh functionality.
9
10
  */
10
11
  export declare class JwtAbapConnection extends AbstractAbapConnection {
11
- private tokenRefreshInProgress;
12
- constructor(config: SapConfig, logger: ILogger, sessionStorage?: ISessionStorage, sessionId?: string);
12
+ constructor(config: SapConfig, logger?: ILogger | null, sessionId?: string);
13
13
  protected buildAuthorizationHeader(): string;
14
- /**
15
- * Refresh JWT token using refresh token
16
- * @returns Promise that resolves when token is refreshed
17
- */
18
- refreshToken(): Promise<void>;
19
- /**
20
- * Check if token refresh is possible
21
- */
22
- canRefreshToken(): boolean;
23
14
  /**
24
15
  * Override connect to handle JWT token refresh on errors
25
16
  */
26
17
  connect(): Promise<void>;
27
18
  /**
28
- * Override makeAdtRequest to handle JWT token refresh on 401/403
19
+ * Override makeAdtRequest to handle JWT auth errors
20
+ * Note: Token refresh is not supported in connection package - use auth-broker instead
29
21
  */
30
22
  makeAdtRequest(options: AbapRequestOptions): Promise<AxiosResponse>;
31
23
  /**
32
- * Override fetchCsrfToken to handle JWT token refresh on 401/403 errors
33
- * This ensures that token refresh works even when CSRF token is fetched during makeAdtRequest
24
+ * Override fetchCsrfToken to handle JWT auth errors
25
+ * Note: Token refresh is not supported in connection package - use auth-broker instead
34
26
  */
35
27
  protected fetchCsrfToken(url: string, retryCount?: number, retryDelay?: number): Promise<string>;
36
28
  private static validateConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"JwtAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/JwtAbapConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAgB,MAAM,cAAc,CAAC;AAEtE,OAAO,EAAc,aAAa,EAAE,MAAM,OAAO,CAAC;AAElD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,sBAAsB;IAC3D,OAAO,CAAC,sBAAsB,CAAkB;gBAG9C,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,OAAO,EACf,cAAc,CAAC,EAAE,eAAe,EAChC,SAAS,CAAC,EAAE,MAAM;IAMpB,SAAS,CAAC,wBAAwB,IAAI,MAAM;IAS5C;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IA6EnC;;OAEG;IACH,eAAe,IAAI,OAAO;IAU1B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4G9B;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAuGzE;;;OAGG;cACa,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,SAAI,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IA4C/F,OAAO,CAAC,MAAM,CAAC,cAAc;CAS9B"}
1
+ {"version":3,"file":"JwtAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/JwtAbapConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAc,aAAa,EAAE,MAAM,OAAO,CAAC;AAElD;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,sBAAsB;gBAGzD,MAAM,EAAE,SAAS,EACjB,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,CAAC,EAAE,MAAM;IAMpB,SAAS,CAAC,wBAAwB,IAAI,MAAM;IAW5C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAkCzE;;;OAGG;cACa,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,SAAI,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IA8B/F,OAAO,CAAC,MAAM,CAAC,cAAc;CAS9B"}