@mcp-abap-adt/connection 0.1.14 → 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,23 +247,19 @@ 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
- if (this.logger.csrfToken) {
408
- this.logger.csrfToken("retry", "CSRF token validation failed, fetching new token and retrying request", {
409
- url: requestUrl,
410
- method: normalizedMethod
411
- });
412
- }
259
+ this.logger?.debug("CSRF token validation failed, fetching new token and retrying request", {
260
+ url: requestUrl,
261
+ method: normalizedMethod
262
+ });
413
263
  this.csrfToken = await this.fetchCsrfToken(requestUrl, 5, 2000);
414
264
  if (this.csrfToken) {
415
265
  requestHeaders["x-csrf-token"] = this.csrfToken;
@@ -419,8 +269,6 @@ class AbstractAbapConnection {
419
269
  }
420
270
  const retryResponse = await this.getAxiosInstance()(requestConfig);
421
271
  this.updateCookiesFromResponse(retryResponse.headers);
422
- // Save session state after retry
423
- await this.saveSessionState();
424
272
  return retryResponse;
425
273
  }
426
274
  // Retry logic for 401 errors on GET requests (authentication issue - need cookies)
@@ -432,29 +280,27 @@ class AbstractAbapConnection {
432
280
  ) {
433
281
  // If we already have cookies from error response, retry immediately
434
282
  if (this.cookies) {
435
- 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`);
436
284
  requestHeaders["Cookie"] = this.cookies;
437
285
  const retryResponse = await this.getAxiosInstance()(requestConfig);
438
286
  this.updateCookiesFromResponse(retryResponse.headers);
439
- await this.saveSessionState();
440
287
  return retryResponse;
441
288
  }
442
289
  // If no cookies, try to get them via CSRF token fetch
443
- 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`);
444
291
  try {
445
292
  // Try to get CSRF token (this will also get cookies)
446
293
  this.csrfToken = await this.fetchCsrfToken(requestUrl, 3, 1000);
447
294
  if (this.cookies) {
448
295
  requestHeaders["Cookie"] = this.cookies;
449
- 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`);
450
297
  const retryResponse = await this.getAxiosInstance()(requestConfig);
451
298
  this.updateCookiesFromResponse(retryResponse.headers);
452
- await this.saveSessionState();
453
299
  return retryResponse;
454
300
  }
455
301
  }
456
302
  catch (csrfError) {
457
- 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)}`);
458
304
  // Fall through to throw original error
459
305
  }
460
306
  }
@@ -478,13 +324,11 @@ class AbstractAbapConnection {
478
324
  csrfUrl = `${base}${csrfConfig_js_1.CSRF_CONFIG.ENDPOINT}`;
479
325
  }
480
326
  // If URL already contains the endpoint, use it as is
481
- if (this.logger.csrfToken) {
482
- this.logger.csrfToken("fetch", `Fetching CSRF token from: ${csrfUrl}`);
483
- }
327
+ this.logger?.debug(`Fetching CSRF token from: ${csrfUrl}`);
484
328
  for (let attempt = 0; attempt <= retryCount; attempt++) {
485
329
  try {
486
- if (attempt > 0 && this.logger.csrfToken) {
487
- this.logger.csrfToken("retry", `Retry attempt ${attempt}/${retryCount} for CSRF token`);
330
+ if (attempt > 0) {
331
+ this.logger?.debug(`Retry attempt ${attempt}/${retryCount} for CSRF token`);
488
332
  }
489
333
  const authHeaders = await this.getAuthHeaders();
490
334
  const headers = {
@@ -495,13 +339,13 @@ class AbstractAbapConnection {
495
339
  // Even on first attempt, if we have cookies from previous session or error response, use them
496
340
  if (this.cookies) {
497
341
  headers["Cookie"] = this.cookies;
498
- 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)}...`);
499
343
  }
500
344
  else {
501
- 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)`);
502
346
  }
503
347
  // Log request details for debugging (only if debug logging is enabled)
504
- 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}`);
505
349
  const response = await this.getAxiosInstance()({
506
350
  method: "GET",
507
351
  url: csrfUrl,
@@ -511,12 +355,10 @@ class AbstractAbapConnection {
511
355
  this.updateCookiesFromResponse(response.headers);
512
356
  const token = response.headers["x-csrf-token"];
513
357
  if (!token) {
514
- if (this.logger.csrfToken) {
515
- this.logger.csrfToken("error", "No CSRF token in response headers", {
516
- headers: response.headers,
517
- status: response.status
518
- });
519
- }
358
+ this.logger?.error("No CSRF token in response headers", {
359
+ headers: response.headers,
360
+ status: response.status
361
+ });
520
362
  if (attempt < retryCount) {
521
363
  await new Promise((resolve) => setTimeout(resolve, retryDelay));
522
364
  continue;
@@ -526,19 +368,13 @@ class AbstractAbapConnection {
526
368
  if (response.headers["set-cookie"]) {
527
369
  this.updateCookiesFromResponse(response.headers);
528
370
  if (this.cookies) {
529
- this.logger.debug(`[DEBUG] BaseAbapConnection - Cookies received from CSRF response (first 100 chars): ${this.cookies.substring(0, 100)}...`);
530
- if (this.logger.csrfToken) {
531
- this.logger.csrfToken("success", "Cookies extracted from response", {
532
- cookieLength: this.cookies.length
533
- });
534
- }
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", {
373
+ cookieLength: this.cookies.length
374
+ });
535
375
  }
536
376
  }
537
- // Save session state after CSRF token fetch (cookies and token are now available)
538
- await this.saveSessionState();
539
- if (this.logger.csrfToken) {
540
- this.logger.csrfToken("success", "CSRF token successfully obtained");
541
- }
377
+ this.logger?.debug("CSRF token successfully obtained");
542
378
  return token;
543
379
  }
544
380
  catch (error) {
@@ -548,24 +384,20 @@ class AbstractAbapConnection {
548
384
  if (error.response?.headers) {
549
385
  this.updateCookiesFromResponse(error.response.headers);
550
386
  if (this.cookies) {
551
- this.logger.debug("Cookies extracted from error response", {
387
+ this.logger?.debug("Cookies extracted from error response", {
552
388
  status: error.response.status,
553
389
  cookieLength: this.cookies.length
554
390
  });
555
391
  }
556
392
  }
557
- if (this.logger.csrfToken) {
558
- this.logger.csrfToken("error", `CSRF token error: ${error.message}`, {
559
- url: csrfUrl,
560
- status: error.response?.status,
561
- attempt: attempt + 1,
562
- maxAttempts: retryCount + 1
563
- });
564
- }
393
+ this.logger?.error(`CSRF token error: ${error.message}`, {
394
+ url: csrfUrl,
395
+ status: error.response?.status,
396
+ attempt: attempt + 1,
397
+ maxAttempts: retryCount + 1
398
+ });
565
399
  if (error.response?.status === 405 && error.response?.headers["x-csrf-token"]) {
566
- if (this.logger.csrfToken) {
567
- this.logger.csrfToken("retry", "CSRF: SAP returned 405 (Method Not Allowed) — not critical, token found in header");
568
- }
400
+ this.logger?.debug("CSRF: SAP returned 405 (Method Not Allowed) — not critical, token found in header");
569
401
  const token = error.response.headers["x-csrf-token"];
570
402
  if (token) {
571
403
  this.updateCookiesFromResponse(error.response.headers);
@@ -573,15 +405,13 @@ class AbstractAbapConnection {
573
405
  }
574
406
  }
575
407
  if (error.response?.headers["x-csrf-token"]) {
576
- if (this.logger.csrfToken) {
577
- this.logger.csrfToken("success", `Got CSRF token despite error (status: ${error.response?.status})`);
578
- }
408
+ this.logger?.debug(`Got CSRF token despite error (status: ${error.response?.status})`);
579
409
  const token = error.response.headers["x-csrf-token"];
580
410
  this.updateCookiesFromResponse(error.response.headers);
581
411
  return token;
582
412
  }
583
- if (error.response && this.logger.csrfToken) {
584
- this.logger.csrfToken("error", "CSRF error details", {
413
+ if (error.response) {
414
+ this.logger?.error("CSRF error details", {
585
415
  status: error.response.status,
586
416
  statusText: error.response.statusText,
587
417
  headers: Object.keys(error.response.headers),
@@ -590,14 +420,14 @@ class AbstractAbapConnection {
590
420
  : JSON.stringify(error.response.data).slice(0, 200)
591
421
  });
592
422
  }
593
- else if (error.request && this.logger.csrfToken) {
594
- this.logger.csrfToken("error", "CSRF request error - no response received", {
423
+ else if (error.request) {
424
+ this.logger?.error("CSRF request error - no response received", {
595
425
  request: error.request.path
596
426
  });
597
427
  }
598
428
  }
599
- else if (this.logger.csrfToken) {
600
- this.logger.csrfToken("error", "CSRF non-axios error", {
429
+ else {
430
+ this.logger?.error("CSRF non-axios error", {
601
431
  error: error instanceof Error ? error.message : String(error)
602
432
  });
603
433
  }
@@ -671,16 +501,14 @@ class AbstractAbapConnection {
671
501
  return;
672
502
  }
673
503
  this.cookies = combined;
674
- 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)}...`);
675
505
  }
676
506
  getAxiosInstance() {
677
507
  if (!this.axiosInstance) {
678
508
  const rejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === "1" ||
679
509
  (process.env.TLS_REJECT_UNAUTHORIZED === "1" &&
680
510
  process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0");
681
- if (this.logger.tlsConfig) {
682
- this.logger.tlsConfig(rejectUnauthorized);
683
- }
511
+ this.logger?.debug(`TLS configuration: rejectUnauthorized=${rejectUnauthorized}`);
684
512
  this.axiosInstance = axios_1.default.create({
685
513
  httpsAgent: new https_1.Agent({
686
514
  rejectUnauthorized
@@ -693,20 +521,20 @@ class AbstractAbapConnection {
693
521
  // If we already have a CSRF token, reuse it to keep the same SAP session
694
522
  // SAP ties the lock handle to the HTTP session (SAP_SESSIONID cookie)
695
523
  if (this.csrfToken) {
696
- 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`);
697
525
  return;
698
526
  }
699
527
  try {
700
- 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)`);
701
529
  this.csrfToken = await this.fetchCsrfToken(requestUrl);
702
530
  }
703
531
  catch (error) {
704
- // fetchCsrfToken already handles auth errors and auto-refresh
532
+ // fetchCsrfToken handles auth errors
705
533
  // Just re-throw the error with minimal logging to avoid duplicate error messages
706
534
  const errorMsg = error instanceof Error ? error.message : csrfConfig_js_1.CSRF_ERROR_MESSAGES.REQUIRED_FOR_MUTATION;
707
535
  // Only log at DEBUG level to avoid duplicate error messages
708
536
  // (fetchCsrfToken already logged the error at ERROR level if auth failed)
709
- this.logger.debug(`[DEBUG] BaseAbapConnection - ensureFreshCsrfToken failed: ${errorMsg}`);
537
+ this.logger?.debug(`[DEBUG] BaseAbapConnection - ensureFreshCsrfToken failed: ${errorMsg}`);
710
538
  throw error;
711
539
  }
712
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"}