@mcp-abap-adt/auth-stores 0.2.7 → 0.2.9

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/index.d.ts +10 -13
  3. package/dist/index.js +32 -35
  4. package/dist/loaders/abap/serviceKeyLoader.js +3 -6
  5. package/dist/loaders/xsuaa/xsuaaServiceKeyLoader.js +2 -2
  6. package/dist/parsers/abap/AbapServiceKeyParser.d.ts +2 -2
  7. package/dist/parsers/abap/AbapServiceKeyParser.js +20 -7
  8. package/dist/parsers/xsuaa/XsuaaServiceKeyParser.d.ts +2 -2
  9. package/dist/parsers/xsuaa/XsuaaServiceKeyParser.js +24 -16
  10. package/dist/storage/abap/envLoader.js +7 -5
  11. package/dist/storage/abap/tokenStorage.js +4 -4
  12. package/dist/storage/xsuaa/xsuaaEnvLoader.js +14 -9
  13. package/dist/storage/xsuaa/xsuaaTokenStorage.js +12 -7
  14. package/dist/stores/abap/AbapServiceKeyStore.d.ts +1 -1
  15. package/dist/stores/abap/AbapServiceKeyStore.js +11 -6
  16. package/dist/stores/abap/AbapSessionStore.d.ts +1 -1
  17. package/dist/stores/abap/AbapSessionStore.js +33 -14
  18. package/dist/stores/abap/SafeAbapSessionStore.d.ts +1 -1
  19. package/dist/stores/abap/SafeAbapSessionStore.js +13 -7
  20. package/dist/stores/env/EnvFileSessionStore.d.ts +8 -3
  21. package/dist/stores/env/EnvFileSessionStore.js +107 -15
  22. package/dist/stores/xsuaa/SafeXsuaaSessionStore.d.ts +1 -1
  23. package/dist/stores/xsuaa/SafeXsuaaSessionStore.js +18 -10
  24. package/dist/stores/xsuaa/XsuaaServiceKeyStore.d.ts +1 -1
  25. package/dist/stores/xsuaa/XsuaaServiceKeyStore.js +10 -5
  26. package/dist/stores/xsuaa/XsuaaSessionStore.d.ts +1 -1
  27. package/dist/stores/xsuaa/XsuaaSessionStore.js +19 -12
  28. package/dist/utils/EnvFileHandler.js +5 -5
  29. package/dist/utils/JsonFileHandler.js +3 -3
  30. package/dist/utils/pathResolver.js +8 -5
  31. package/package.json +7 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.9] - 2025-12-22
11
+
12
+ ### Changed
13
+ - **Migrated to Biome**: Replaced ESLint/Prettier with Biome for linting and formatting
14
+ - Added `@biomejs/biome` as dev dependency (^2.3.10)
15
+ - Added `biome.json` configuration file with recommended rules
16
+ - Added npm scripts: `lint`, `lint:check`, `format`
17
+ - Updated `build` script to include Biome check before TypeScript compilation
18
+ - All code now follows Biome formatting and linting rules
19
+ - Updated Node.js imports to use `node:` protocol (fs, path, os)
20
+
21
+ ### Fixed
22
+ - **Type Safety Improvements**: Replaced `any` types with `unknown` for better type safety
23
+ - Parser methods (`canParse`, `parse`): Changed parameter types from `any` to `unknown` with proper type guards
24
+ - `AbapSessionStore`: Replaced `as any` casts with proper type intersections (`IConfig & Record<string, unknown>`)
25
+ - All parsers now use proper type guards to safely access object properties
26
+ - **Code Quality**: Improved code organization
27
+ - Organized imports automatically
28
+ - Fixed code formatting issues
29
+ - Improved type safety in session store operations
30
+
31
+ ## [0.2.8] - 2025-12-21
32
+
33
+ ### Added
34
+ - **EnvFileSessionStore**: File persistence for JWT tokens
35
+ - `save()` method writes `SAP_JWT_TOKEN` and `SAP_REFRESH_TOKEN` back to the .env file
36
+ - `setToken()`, `setRefreshToken()`, `setConnectionConfig()`, `setAuthorizationConfig()`, `saveSession()` now automatically persist JWT changes to file
37
+ - Enables token refresh flow to update the .env file with new tokens
38
+
39
+ ### Changed
40
+ - **EnvFileSessionStore**: No longer "read-only" for JWT auth
41
+ - Basic auth credentials remain read-only (not written back)
42
+ - JWT tokens are persisted on update
43
+
10
44
  ## [0.2.7] - 2025-12-21
11
45
 
12
46
  ### Fixed
package/dist/index.d.ts CHANGED
@@ -4,20 +4,17 @@
4
4
  *
5
5
  * Provides ABAP and XSUAA store implementations
6
6
  */
7
+ export { FileNotFoundError, InvalidConfigError, ParseError, StorageError, StoreError, } from './errors/StoreErrors';
8
+ export { loadServiceKey } from './loaders/abap/serviceKeyLoader';
9
+ export { loadXSUAAServiceKey } from './loaders/xsuaa/xsuaaServiceKeyLoader';
10
+ export { AbapServiceKeyStore } from './stores/abap/AbapServiceKeyStore';
7
11
  export { AbapSessionStore } from './stores/abap/AbapSessionStore';
8
12
  export { SafeAbapSessionStore } from './stores/abap/SafeAbapSessionStore';
9
- export { AbapServiceKeyStore } from './stores/abap/AbapServiceKeyStore';
10
- export { XsuaaSessionStore } from './stores/xsuaa/XsuaaSessionStore';
11
- export { SafeXsuaaSessionStore } from './stores/xsuaa/SafeXsuaaSessionStore';
12
- export { XsuaaServiceKeyStore } from './stores/xsuaa/XsuaaServiceKeyStore';
13
- export { XsuaaSessionStore as BtpSessionStore } from './stores/xsuaa/XsuaaSessionStore';
14
- export { SafeXsuaaSessionStore as SafeBtpSessionStore } from './stores/xsuaa/SafeXsuaaSessionStore';
15
- export { XsuaaServiceKeyStore as BtpServiceKeyStore } from './stores/xsuaa/XsuaaServiceKeyStore';
16
13
  export { EnvFileSessionStore } from './stores/env/EnvFileSessionStore';
17
- export { StoreError, FileNotFoundError, ParseError, InvalidConfigError, StorageError } from './errors/StoreErrors';
18
- export { resolveSearchPaths, findFileInPaths } from './utils/pathResolver';
19
- export { JsonFileHandler } from './utils/JsonFileHandler';
14
+ export { SafeXsuaaSessionStore, SafeXsuaaSessionStore as SafeBtpSessionStore, } from './stores/xsuaa/SafeXsuaaSessionStore';
15
+ export { XsuaaServiceKeyStore, XsuaaServiceKeyStore as BtpServiceKeyStore, } from './stores/xsuaa/XsuaaServiceKeyStore';
16
+ export { XsuaaSessionStore, XsuaaSessionStore as BtpSessionStore, } from './stores/xsuaa/XsuaaSessionStore';
17
+ export { ABAP_AUTHORIZATION_VARS, ABAP_CONNECTION_VARS, BTP_AUTHORIZATION_VARS, BTP_CONNECTION_VARS, XSUAA_AUTHORIZATION_VARS, XSUAA_CONNECTION_VARS, } from './utils/constants';
20
18
  export { EnvFileHandler } from './utils/EnvFileHandler';
21
- export { ABAP_AUTHORIZATION_VARS, ABAP_CONNECTION_VARS, BTP_AUTHORIZATION_VARS, BTP_CONNECTION_VARS, XSUAA_AUTHORIZATION_VARS, XSUAA_CONNECTION_VARS } from './utils/constants';
22
- export { loadServiceKey } from './loaders/abap/serviceKeyLoader';
23
- export { loadXSUAAServiceKey } from './loaders/xsuaa/xsuaaServiceKeyLoader';
19
+ export { JsonFileHandler } from './utils/JsonFileHandler';
20
+ export { findFileInPaths, resolveSearchPaths } from './utils/pathResolver';
package/dist/index.js CHANGED
@@ -6,46 +6,40 @@
6
6
  * Provides ABAP and XSUAA store implementations
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.loadXSUAAServiceKey = exports.loadServiceKey = exports.XSUAA_CONNECTION_VARS = exports.XSUAA_AUTHORIZATION_VARS = exports.BTP_CONNECTION_VARS = exports.BTP_AUTHORIZATION_VARS = exports.ABAP_CONNECTION_VARS = exports.ABAP_AUTHORIZATION_VARS = exports.EnvFileHandler = exports.JsonFileHandler = exports.findFileInPaths = exports.resolveSearchPaths = exports.StorageError = exports.InvalidConfigError = exports.ParseError = exports.FileNotFoundError = exports.StoreError = exports.EnvFileSessionStore = exports.BtpServiceKeyStore = exports.SafeBtpSessionStore = exports.BtpSessionStore = exports.XsuaaServiceKeyStore = exports.SafeXsuaaSessionStore = exports.XsuaaSessionStore = exports.AbapServiceKeyStore = exports.SafeAbapSessionStore = exports.AbapSessionStore = void 0;
9
+ exports.resolveSearchPaths = exports.findFileInPaths = exports.JsonFileHandler = exports.EnvFileHandler = exports.XSUAA_CONNECTION_VARS = exports.XSUAA_AUTHORIZATION_VARS = exports.BTP_CONNECTION_VARS = exports.BTP_AUTHORIZATION_VARS = exports.ABAP_CONNECTION_VARS = exports.ABAP_AUTHORIZATION_VARS = exports.BtpSessionStore = exports.XsuaaSessionStore = exports.BtpServiceKeyStore = exports.XsuaaServiceKeyStore = exports.SafeBtpSessionStore = exports.SafeXsuaaSessionStore = exports.EnvFileSessionStore = exports.SafeAbapSessionStore = exports.AbapSessionStore = exports.AbapServiceKeyStore = exports.loadXSUAAServiceKey = exports.loadServiceKey = exports.StoreError = exports.StorageError = exports.ParseError = exports.InvalidConfigError = exports.FileNotFoundError = void 0;
10
+ // Error classes
11
+ var StoreErrors_1 = require("./errors/StoreErrors");
12
+ Object.defineProperty(exports, "FileNotFoundError", { enumerable: true, get: function () { return StoreErrors_1.FileNotFoundError; } });
13
+ Object.defineProperty(exports, "InvalidConfigError", { enumerable: true, get: function () { return StoreErrors_1.InvalidConfigError; } });
14
+ Object.defineProperty(exports, "ParseError", { enumerable: true, get: function () { return StoreErrors_1.ParseError; } });
15
+ Object.defineProperty(exports, "StorageError", { enumerable: true, get: function () { return StoreErrors_1.StorageError; } });
16
+ Object.defineProperty(exports, "StoreError", { enumerable: true, get: function () { return StoreErrors_1.StoreError; } });
17
+ // Loaders
18
+ var serviceKeyLoader_1 = require("./loaders/abap/serviceKeyLoader");
19
+ Object.defineProperty(exports, "loadServiceKey", { enumerable: true, get: function () { return serviceKeyLoader_1.loadServiceKey; } });
20
+ var xsuaaServiceKeyLoader_1 = require("./loaders/xsuaa/xsuaaServiceKeyLoader");
21
+ Object.defineProperty(exports, "loadXSUAAServiceKey", { enumerable: true, get: function () { return xsuaaServiceKeyLoader_1.loadXSUAAServiceKey; } });
22
+ var AbapServiceKeyStore_1 = require("./stores/abap/AbapServiceKeyStore");
23
+ Object.defineProperty(exports, "AbapServiceKeyStore", { enumerable: true, get: function () { return AbapServiceKeyStore_1.AbapServiceKeyStore; } });
10
24
  // ABAP stores (with sapUrl)
11
25
  var AbapSessionStore_1 = require("./stores/abap/AbapSessionStore");
12
26
  Object.defineProperty(exports, "AbapSessionStore", { enumerable: true, get: function () { return AbapSessionStore_1.AbapSessionStore; } });
13
27
  var SafeAbapSessionStore_1 = require("./stores/abap/SafeAbapSessionStore");
14
28
  Object.defineProperty(exports, "SafeAbapSessionStore", { enumerable: true, get: function () { return SafeAbapSessionStore_1.SafeAbapSessionStore; } });
15
- var AbapServiceKeyStore_1 = require("./stores/abap/AbapServiceKeyStore");
16
- Object.defineProperty(exports, "AbapServiceKeyStore", { enumerable: true, get: function () { return AbapServiceKeyStore_1.AbapServiceKeyStore; } });
17
- // XSUAA stores
18
- var XsuaaSessionStore_1 = require("./stores/xsuaa/XsuaaSessionStore");
19
- Object.defineProperty(exports, "XsuaaSessionStore", { enumerable: true, get: function () { return XsuaaSessionStore_1.XsuaaSessionStore; } });
29
+ // Env file stores (for --env=path scenarios)
30
+ var EnvFileSessionStore_1 = require("./stores/env/EnvFileSessionStore");
31
+ Object.defineProperty(exports, "EnvFileSessionStore", { enumerable: true, get: function () { return EnvFileSessionStore_1.EnvFileSessionStore; } });
20
32
  var SafeXsuaaSessionStore_1 = require("./stores/xsuaa/SafeXsuaaSessionStore");
21
33
  Object.defineProperty(exports, "SafeXsuaaSessionStore", { enumerable: true, get: function () { return SafeXsuaaSessionStore_1.SafeXsuaaSessionStore; } });
34
+ Object.defineProperty(exports, "SafeBtpSessionStore", { enumerable: true, get: function () { return SafeXsuaaSessionStore_1.SafeXsuaaSessionStore; } });
22
35
  var XsuaaServiceKeyStore_1 = require("./stores/xsuaa/XsuaaServiceKeyStore");
23
36
  Object.defineProperty(exports, "XsuaaServiceKeyStore", { enumerable: true, get: function () { return XsuaaServiceKeyStore_1.XsuaaServiceKeyStore; } });
37
+ Object.defineProperty(exports, "BtpServiceKeyStore", { enumerable: true, get: function () { return XsuaaServiceKeyStore_1.XsuaaServiceKeyStore; } });
38
+ // XSUAA stores
24
39
  // BTP stores - aliases for XSUAA (backward compatibility)
25
- var XsuaaSessionStore_2 = require("./stores/xsuaa/XsuaaSessionStore");
26
- Object.defineProperty(exports, "BtpSessionStore", { enumerable: true, get: function () { return XsuaaSessionStore_2.XsuaaSessionStore; } });
27
- var SafeXsuaaSessionStore_2 = require("./stores/xsuaa/SafeXsuaaSessionStore");
28
- Object.defineProperty(exports, "SafeBtpSessionStore", { enumerable: true, get: function () { return SafeXsuaaSessionStore_2.SafeXsuaaSessionStore; } });
29
- var XsuaaServiceKeyStore_2 = require("./stores/xsuaa/XsuaaServiceKeyStore");
30
- Object.defineProperty(exports, "BtpServiceKeyStore", { enumerable: true, get: function () { return XsuaaServiceKeyStore_2.XsuaaServiceKeyStore; } });
31
- // Env file stores (for --env=path scenarios)
32
- var EnvFileSessionStore_1 = require("./stores/env/EnvFileSessionStore");
33
- Object.defineProperty(exports, "EnvFileSessionStore", { enumerable: true, get: function () { return EnvFileSessionStore_1.EnvFileSessionStore; } });
34
- // Error classes
35
- var StoreErrors_1 = require("./errors/StoreErrors");
36
- Object.defineProperty(exports, "StoreError", { enumerable: true, get: function () { return StoreErrors_1.StoreError; } });
37
- Object.defineProperty(exports, "FileNotFoundError", { enumerable: true, get: function () { return StoreErrors_1.FileNotFoundError; } });
38
- Object.defineProperty(exports, "ParseError", { enumerable: true, get: function () { return StoreErrors_1.ParseError; } });
39
- Object.defineProperty(exports, "InvalidConfigError", { enumerable: true, get: function () { return StoreErrors_1.InvalidConfigError; } });
40
- Object.defineProperty(exports, "StorageError", { enumerable: true, get: function () { return StoreErrors_1.StorageError; } });
41
- // Utils
42
- var pathResolver_1 = require("./utils/pathResolver");
43
- Object.defineProperty(exports, "resolveSearchPaths", { enumerable: true, get: function () { return pathResolver_1.resolveSearchPaths; } });
44
- Object.defineProperty(exports, "findFileInPaths", { enumerable: true, get: function () { return pathResolver_1.findFileInPaths; } });
45
- var JsonFileHandler_1 = require("./utils/JsonFileHandler");
46
- Object.defineProperty(exports, "JsonFileHandler", { enumerable: true, get: function () { return JsonFileHandler_1.JsonFileHandler; } });
47
- var EnvFileHandler_1 = require("./utils/EnvFileHandler");
48
- Object.defineProperty(exports, "EnvFileHandler", { enumerable: true, get: function () { return EnvFileHandler_1.EnvFileHandler; } });
40
+ var XsuaaSessionStore_1 = require("./stores/xsuaa/XsuaaSessionStore");
41
+ Object.defineProperty(exports, "XsuaaSessionStore", { enumerable: true, get: function () { return XsuaaSessionStore_1.XsuaaSessionStore; } });
42
+ Object.defineProperty(exports, "BtpSessionStore", { enumerable: true, get: function () { return XsuaaSessionStore_1.XsuaaSessionStore; } });
49
43
  var constants_1 = require("./utils/constants");
50
44
  Object.defineProperty(exports, "ABAP_AUTHORIZATION_VARS", { enumerable: true, get: function () { return constants_1.ABAP_AUTHORIZATION_VARS; } });
51
45
  Object.defineProperty(exports, "ABAP_CONNECTION_VARS", { enumerable: true, get: function () { return constants_1.ABAP_CONNECTION_VARS; } });
@@ -53,8 +47,11 @@ Object.defineProperty(exports, "BTP_AUTHORIZATION_VARS", { enumerable: true, get
53
47
  Object.defineProperty(exports, "BTP_CONNECTION_VARS", { enumerable: true, get: function () { return constants_1.BTP_CONNECTION_VARS; } });
54
48
  Object.defineProperty(exports, "XSUAA_AUTHORIZATION_VARS", { enumerable: true, get: function () { return constants_1.XSUAA_AUTHORIZATION_VARS; } });
55
49
  Object.defineProperty(exports, "XSUAA_CONNECTION_VARS", { enumerable: true, get: function () { return constants_1.XSUAA_CONNECTION_VARS; } });
56
- // Loaders
57
- var serviceKeyLoader_1 = require("./loaders/abap/serviceKeyLoader");
58
- Object.defineProperty(exports, "loadServiceKey", { enumerable: true, get: function () { return serviceKeyLoader_1.loadServiceKey; } });
59
- var xsuaaServiceKeyLoader_1 = require("./loaders/xsuaa/xsuaaServiceKeyLoader");
60
- Object.defineProperty(exports, "loadXSUAAServiceKey", { enumerable: true, get: function () { return xsuaaServiceKeyLoader_1.loadXSUAAServiceKey; } });
50
+ var EnvFileHandler_1 = require("./utils/EnvFileHandler");
51
+ Object.defineProperty(exports, "EnvFileHandler", { enumerable: true, get: function () { return EnvFileHandler_1.EnvFileHandler; } });
52
+ var JsonFileHandler_1 = require("./utils/JsonFileHandler");
53
+ Object.defineProperty(exports, "JsonFileHandler", { enumerable: true, get: function () { return JsonFileHandler_1.JsonFileHandler; } });
54
+ // Utils
55
+ var pathResolver_1 = require("./utils/pathResolver");
56
+ Object.defineProperty(exports, "findFileInPaths", { enumerable: true, get: function () { return pathResolver_1.findFileInPaths; } });
57
+ Object.defineProperty(exports, "resolveSearchPaths", { enumerable: true, get: function () { return pathResolver_1.resolveSearchPaths; } });
@@ -41,8 +41,8 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  })();
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.loadServiceKey = loadServiceKey;
44
- const fs = __importStar(require("fs"));
45
- const path = __importStar(require("path"));
44
+ const fs = __importStar(require("node:fs"));
45
+ const path = __importStar(require("node:path"));
46
46
  const AbapServiceKeyParser_1 = require("../../parsers/abap/AbapServiceKeyParser");
47
47
  const XsuaaServiceKeyParser_1 = require("../../parsers/xsuaa/XsuaaServiceKeyParser");
48
48
  /**
@@ -62,10 +62,7 @@ async function loadServiceKey(destination, directory) {
62
62
  const fileContent = fs.readFileSync(serviceKeyPath, 'utf8');
63
63
  const rawData = JSON.parse(fileContent);
64
64
  // Try parsers in order: ABAP format first, then XSUAA format
65
- const parsers = [
66
- new AbapServiceKeyParser_1.AbapServiceKeyParser(),
67
- new XsuaaServiceKeyParser_1.XsuaaServiceKeyParser(),
68
- ];
65
+ const parsers = [new AbapServiceKeyParser_1.AbapServiceKeyParser(), new XsuaaServiceKeyParser_1.XsuaaServiceKeyParser()];
69
66
  for (const parser of parsers) {
70
67
  if (parser.canParse(rawData)) {
71
68
  return parser.parse(rawData);
@@ -45,8 +45,8 @@ var __importStar = (this && this.__importStar) || (function () {
45
45
  })();
46
46
  Object.defineProperty(exports, "__esModule", { value: true });
47
47
  exports.loadXSUAAServiceKey = loadXSUAAServiceKey;
48
- const fs = __importStar(require("fs"));
49
- const path = __importStar(require("path"));
48
+ const fs = __importStar(require("node:fs"));
49
+ const path = __importStar(require("node:path"));
50
50
  const XsuaaServiceKeyParser_1 = require("../../parsers/xsuaa/XsuaaServiceKeyParser");
51
51
  /**
52
52
  * Load XSUAA service key from {destination}.json file
@@ -31,12 +31,12 @@ export declare class AbapServiceKeyParser {
31
31
  * @param rawData Raw JSON data from service key file
32
32
  * @returns true if data has nested uaa object, false otherwise
33
33
  */
34
- canParse(rawData: any): boolean;
34
+ canParse(rawData: unknown): boolean;
35
35
  /**
36
36
  * Parse raw service key data
37
37
  * @param rawData Raw JSON data from service key file
38
38
  * @returns Parsed service key object
39
39
  * @throws Error if data cannot be parsed or is invalid
40
40
  */
41
- parse(rawData: any): unknown;
41
+ parse(rawData: unknown): unknown;
42
42
  }
@@ -36,8 +36,14 @@ class AbapServiceKeyParser {
36
36
  * @returns true if data has nested uaa object, false otherwise
37
37
  */
38
38
  canParse(rawData) {
39
- const result = rawData && typeof rawData === 'object' && rawData.uaa && typeof rawData.uaa === 'object';
40
- this.log?.debug(`canParse check: hasUaa(${!!rawData?.uaa}), result(${result})`);
39
+ if (!rawData || typeof rawData !== 'object' || Array.isArray(rawData)) {
40
+ return false;
41
+ }
42
+ const data = rawData;
43
+ const result = !!(data.uaa &&
44
+ typeof data.uaa === 'object' &&
45
+ !Array.isArray(data.uaa));
46
+ this.log?.debug(`canParse check: hasUaa(${!!data.uaa}), result(${result})`);
41
47
  return result;
42
48
  }
43
49
  /**
@@ -47,21 +53,28 @@ class AbapServiceKeyParser {
47
53
  * @throws Error if data cannot be parsed or is invalid
48
54
  */
49
55
  parse(rawData) {
50
- this.log?.debug(`Parsing ABAP service key: hasUaa(${!!rawData?.uaa}), keys(${rawData ? Object.keys(rawData).join(', ') : 'none'})`);
56
+ if (!rawData || typeof rawData !== 'object' || Array.isArray(rawData)) {
57
+ throw new Error('Service key data must be an object');
58
+ }
59
+ const data = rawData;
60
+ this.log?.debug(`Parsing ABAP service key: hasUaa(${!!data.uaa}), keys(${Object.keys(data).join(', ')})`);
51
61
  if (!this.canParse(rawData)) {
52
62
  this.log?.error(`Service key does not match ABAP format: missing uaa object`);
53
63
  throw new Error('Service key does not match ABAP format (missing uaa object)');
54
64
  }
65
+ // After canParse, we know uaa exists and is an object
66
+ const uaa = data.uaa;
55
67
  // Validate UAA configuration
56
- const hasUrl = !!rawData.uaa.url;
57
- const hasClientId = !!rawData.uaa.clientid;
58
- const hasClientSecret = !!rawData.uaa.clientsecret;
68
+ const hasUrl = typeof uaa.url === 'string' && uaa.url.length > 0;
69
+ const hasClientId = typeof uaa.clientid === 'string' && uaa.clientid.length > 0;
70
+ const hasClientSecret = typeof uaa.clientsecret === 'string' && uaa.clientsecret.length > 0;
59
71
  this.log?.debug(`UAA validation: url(${hasUrl}), clientid(${hasClientId}), clientsecret(${hasClientSecret})`);
60
72
  if (!hasUrl || !hasClientId || !hasClientSecret) {
61
73
  this.log?.error(`Service key uaa object missing required fields: url(${hasUrl}), clientid(${hasClientId}), clientsecret(${hasClientSecret})`);
62
74
  throw new Error('Service key "uaa" object missing required fields: url, clientid, clientsecret');
63
75
  }
64
- this.log?.debug(`ABAP service key parsed successfully: uaaUrl(${rawData.uaa.url.substring(0, 40)}...), hasAbap(${!!rawData.abap})`);
76
+ const uaaUrl = typeof uaa.url === 'string' ? uaa.url : '';
77
+ this.log?.debug(`ABAP service key parsed successfully: uaaUrl(${uaaUrl.substring(0, 40)}...), hasAbap(${!!data.abap})`);
65
78
  return rawData;
66
79
  }
67
80
  }
@@ -26,12 +26,12 @@ export declare class XsuaaServiceKeyParser {
26
26
  * @param rawData Raw JSON data from service key file
27
27
  * @returns true if data has direct XSUAA fields (url, clientid, clientsecret) without nested uaa object
28
28
  */
29
- canParse(rawData: any): boolean;
29
+ canParse(rawData: unknown): boolean;
30
30
  /**
31
31
  * Parse raw service key data
32
32
  * @param rawData Raw JSON data from service key file
33
33
  * @returns Parsed service key object (normalized format)
34
34
  * @throws Error if data cannot be parsed or is invalid
35
35
  */
36
- parse(rawData: any): unknown;
36
+ parse(rawData: unknown): unknown;
37
37
  }
@@ -35,15 +35,16 @@ class XsuaaServiceKeyParser {
35
35
  this.log?.debug(`canParse check: invalid type, result(false)`);
36
36
  return false;
37
37
  }
38
+ const data = rawData;
38
39
  // Check for nested uaa object (ABAP format) - should not have it
39
- if (rawData.uaa) {
40
+ if (data.uaa) {
40
41
  this.log?.debug(`canParse check: has nested uaa (ABAP format), result(false)`);
41
42
  return false;
42
43
  }
43
44
  // Check for required XSUAA fields at root level
44
- const hasUrl = typeof rawData.url === 'string' && rawData.url.length > 0;
45
- const hasClientId = typeof rawData.clientid === 'string' && rawData.clientid.length > 0;
46
- const hasClientSecret = typeof rawData.clientsecret === 'string' && rawData.clientsecret.length > 0;
45
+ const hasUrl = typeof data.url === 'string' && data.url.length > 0;
46
+ const hasClientId = typeof data.clientid === 'string' && data.clientid.length > 0;
47
+ const hasClientSecret = typeof data.clientsecret === 'string' && data.clientsecret.length > 0;
47
48
  const result = hasUrl && hasClientId && hasClientSecret;
48
49
  this.log?.debug(`canParse check: url(${hasUrl}), clientid(${hasClientId}), clientsecret(${hasClientSecret}), result(${result})`);
49
50
  return result;
@@ -55,32 +56,39 @@ class XsuaaServiceKeyParser {
55
56
  * @throws Error if data cannot be parsed or is invalid
56
57
  */
57
58
  parse(rawData) {
58
- this.log?.debug(`Parsing XSUAA service key: hasUrl(${!!rawData?.url}), hasClientId(${!!rawData?.clientid}), hasClientSecret(${!!rawData?.clientsecret}), keys(${rawData ? Object.keys(rawData).join(', ') : 'none'})`);
59
+ if (!rawData || typeof rawData !== 'object' || Array.isArray(rawData)) {
60
+ throw new Error('Service key data must be an object');
61
+ }
62
+ const data = rawData;
63
+ this.log?.debug(`Parsing XSUAA service key: hasUrl(${!!data.url}), hasClientId(${!!data.clientid}), hasClientSecret(${!!data.clientsecret}), keys(${Object.keys(data).join(', ')})`);
59
64
  if (!this.canParse(rawData)) {
60
65
  this.log?.error(`Service key does not match XSUAA format: missing required fields at root level`);
61
66
  throw new Error('Service key does not match XSUAA format (missing url, clientid, or clientsecret at root level)');
62
67
  }
68
+ // After canParse, we know url, clientid, and clientsecret exist and are strings
69
+ const uaaUrl = typeof data.url === 'string' ? data.url : '';
70
+ const clientId = typeof data.clientid === 'string' ? data.clientid : '';
71
+ const clientSecret = typeof data.clientsecret === 'string' ? data.clientsecret : '';
63
72
  // Normalize to standard format
64
73
  // For authorization (OAuth2 authorize endpoint), use 'url' (not 'apiurl')
65
74
  // 'apiurl' is for token endpoint, but authorization uses base 'url'
66
- const uaaUrl = rawData.url;
67
75
  const result = {
68
76
  uaa: {
69
77
  url: uaaUrl,
70
- clientid: rawData.clientid,
71
- clientsecret: rawData.clientsecret,
78
+ clientid: clientId,
79
+ clientsecret: clientSecret,
72
80
  },
73
81
  // Preserve abap.url if present
74
- abap: rawData.abap,
82
+ abap: data.abap,
75
83
  // Preserve other optional fields
76
- url: rawData.url, // UAA URL
77
- apiurl: rawData.apiurl, // API URL (prioritized for UAA)
78
- sap_url: rawData.sap_url,
79
- client: rawData.client,
80
- sap_client: rawData.sap_client,
81
- language: rawData.language,
84
+ url: data.url, // UAA URL
85
+ apiurl: data.apiurl, // API URL (prioritized for UAA)
86
+ sap_url: data.sap_url,
87
+ client: data.client,
88
+ sap_client: data.sap_client,
89
+ language: data.language,
82
90
  };
83
- this.log?.debug(`XSUAA service key parsed successfully: uaaUrl(${uaaUrl.substring(0, 40)}...), hasAbap(${!!rawData.abap})`);
91
+ this.log?.debug(`XSUAA service key parsed successfully: uaaUrl(${uaaUrl.substring(0, 40)}...), hasAbap(${!!data.abap})`);
84
92
  return result;
85
93
  }
86
94
  }
@@ -37,8 +37,8 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.loadEnvFile = loadEnvFile;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
42
  const dotenv = __importStar(require("dotenv"));
43
43
  const constants_1 = require("../../utils/constants");
44
44
  /**
@@ -78,7 +78,7 @@ async function loadEnvFile(destination, directory, log) {
78
78
  // If neither is present, it's OK - auth can be set later (e.g., via setAuthorizationConfig)
79
79
  const isBasicAuth = !!(username && password) && (!jwtToken || jwtToken.trim() === '');
80
80
  const isJwtAuth = !!(jwtToken && jwtToken.trim() !== '');
81
- const hasNoAuth = !isBasicAuth && !isJwtAuth;
81
+ const _hasNoAuth = !isBasicAuth && !isJwtAuth;
82
82
  const config = {
83
83
  sapUrl: sapUrl.trim(),
84
84
  };
@@ -102,7 +102,8 @@ async function loadEnvFile(destination, directory, log) {
102
102
  config.sapClient = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT].trim();
103
103
  }
104
104
  if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN]) {
105
- config.refreshToken = parsed[constants_1.ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN].trim();
105
+ config.refreshToken =
106
+ parsed[constants_1.ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN].trim();
106
107
  }
107
108
  if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_URL]) {
108
109
  config.uaaUrl = parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_URL].trim();
@@ -111,7 +112,8 @@ async function loadEnvFile(destination, directory, log) {
111
112
  config.uaaClientId = parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_ID].trim();
112
113
  }
113
114
  if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET]) {
114
- config.uaaClientSecret = parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET].trim();
115
+ config.uaaClientSecret =
116
+ parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET].trim();
115
117
  }
116
118
  if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE]) {
117
119
  config.language = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE].trim();
@@ -37,8 +37,8 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.saveTokenToEnv = saveTokenToEnv;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
42
  const constants_1 = require("../../utils/constants");
43
43
  /**
44
44
  * Save token to {destination}.env file
@@ -131,7 +131,7 @@ async function saveTokenToEnv(destination, savePath, config, log) {
131
131
  : value;
132
132
  envLines.push(`${key}=${escapedValue}`);
133
133
  }
134
- const envContent = envLines.join('\n') + '\n';
134
+ const envContent = `${envLines.join('\n')}\n`;
135
135
  log?.debug(`Writing ${envLines.length} variables to env file: ${Object.keys(config).join(', ')}`);
136
136
  // Write to temp file
137
137
  fs.writeFileSync(tempFilePath, envContent, 'utf8');
@@ -140,5 +140,5 @@ async function saveTokenToEnv(destination, savePath, config, log) {
140
140
  const authInfo = hasBasicAuth
141
141
  ? `basic auth (username: ${config.username})`
142
142
  : `JWT token(${tokenLength} chars)`;
143
- log?.info(`Token saved to ${envFilePath}: ${authInfo}, sapUrl(${config.sapUrl ? config.sapUrl.substring(0, 50) + '...' : 'none'}), variables(${envLines.length})`);
143
+ log?.info(`Token saved to ${envFilePath}: ${authInfo}, sapUrl(${config.sapUrl ? `${config.sapUrl.substring(0, 50)}...` : 'none'}), variables(${envLines.length})`);
144
144
  }
@@ -37,8 +37,8 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.loadXsuaaEnvFile = loadXsuaaEnvFile;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
42
  const dotenv = __importStar(require("dotenv"));
43
43
  const constants_1 = require("../../utils/constants");
44
44
  /**
@@ -62,7 +62,9 @@ async function loadXsuaaEnvFile(destination, directory, log) {
62
62
  const envContent = fs.readFileSync(envFilePath, 'utf8');
63
63
  log?.debug(`XSUAA env file read successfully, size: ${envContent.length} bytes`);
64
64
  const parsed = dotenv.parse(envContent);
65
- log?.debug(`Parsed XSUAA env variables: ${Object.keys(parsed).filter(k => k.startsWith('XSUAA_')).join(', ')}`);
65
+ log?.debug(`Parsed XSUAA env variables: ${Object.keys(parsed)
66
+ .filter((k) => k.startsWith('XSUAA_'))
67
+ .join(', ')}`);
66
68
  // Extract required fields (XSUAA_* variables)
67
69
  const jwtToken = parsed[constants_1.XSUAA_CONNECTION_VARS.AUTHORIZATION_TOKEN];
68
70
  log?.debug(`Extracted fields: hasJwtToken(${jwtToken !== undefined && jwtToken !== null})`);
@@ -77,22 +79,25 @@ async function loadXsuaaEnvFile(destination, directory, log) {
77
79
  };
78
80
  // mcpUrl can be loaded from .env file as additional variable (not part of CONNECTION_VARS, but can be stored)
79
81
  // URL comes from elsewhere (YAML config, parameter, or request header), but can be stored in .env
80
- if (parsed['XSUAA_MCP_URL']) {
81
- config.mcpUrl = parsed['XSUAA_MCP_URL'].trim();
82
+ if (parsed.XSUAA_MCP_URL) {
83
+ config.mcpUrl = parsed.XSUAA_MCP_URL.trim();
82
84
  }
83
85
  if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN]) {
84
- config.refreshToken = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN].trim();
86
+ config.refreshToken =
87
+ parsed[constants_1.XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN].trim();
85
88
  }
86
89
  if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_URL]) {
87
90
  config.uaaUrl = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_URL].trim();
88
91
  }
89
92
  if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID]) {
90
- config.uaaClientId = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID].trim();
93
+ config.uaaClientId =
94
+ parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID].trim();
91
95
  }
92
96
  if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET]) {
93
- config.uaaClientSecret = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET].trim();
97
+ config.uaaClientSecret =
98
+ parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET].trim();
94
99
  }
95
- log?.info(`XSUAA env config loaded from ${envFilePath}: token(${config.jwtToken.length} chars), hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl}), mcpUrl(${config.mcpUrl ? config.mcpUrl.substring(0, 50) + '...' : 'none'})`);
100
+ log?.info(`XSUAA env config loaded from ${envFilePath}: token(${config.jwtToken.length} chars), hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl}), mcpUrl(${config.mcpUrl ? `${config.mcpUrl.substring(0, 50)}...` : 'none'})`);
96
101
  return config;
97
102
  }
98
103
  catch (error) {
@@ -37,8 +37,8 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.saveXsuaaTokenToEnv = saveXsuaaTokenToEnv;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
42
  const constants_1 = require("../../utils/constants");
43
43
  /**
44
44
  * Save XSUAA token to {destination}.env file using XSUAA_* variables
@@ -51,7 +51,7 @@ async function saveXsuaaTokenToEnv(destination, savePath, config, log) {
51
51
  const envFilePath = path.join(savePath, `${destination}.env`);
52
52
  const tempFilePath = `${envFilePath}.tmp`;
53
53
  log?.debug(`Saving XSUAA token to env file: ${envFilePath}`);
54
- log?.debug(`Config to save: token(${config.jwtToken.length} chars), hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl}), mcpUrl(${config.mcpUrl ? config.mcpUrl.substring(0, 50) + '...' : 'none'})`);
54
+ log?.debug(`Config to save: token(${config.jwtToken.length} chars), hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl}), mcpUrl(${config.mcpUrl ? `${config.mcpUrl.substring(0, 50)}...` : 'none'})`);
55
55
  // Ensure directory exists
56
56
  if (!fs.existsSync(savePath)) {
57
57
  log?.debug(`Creating directory: ${savePath}`);
@@ -79,8 +79,13 @@ async function saveXsuaaTokenToEnv(destination, savePath, config, log) {
79
79
  if (match) {
80
80
  const key = match[1].trim();
81
81
  // Skip old SAP_* variables for XSUAA (we use XSUAA_* now)
82
- if (key.startsWith('SAP_') && (key === 'SAP_URL' || key === 'SAP_JWT_TOKEN' || key === 'SAP_REFRESH_TOKEN' ||
83
- key === 'SAP_UAA_URL' || key === 'SAP_UAA_CLIENT_ID' || key === 'SAP_UAA_CLIENT_SECRET')) {
82
+ if (key.startsWith('SAP_') &&
83
+ (key === 'SAP_URL' ||
84
+ key === 'SAP_JWT_TOKEN' ||
85
+ key === 'SAP_REFRESH_TOKEN' ||
86
+ key === 'SAP_UAA_URL' ||
87
+ key === 'SAP_UAA_CLIENT_ID' ||
88
+ key === 'SAP_UAA_CLIENT_SECRET')) {
84
89
  continue; // Don't preserve old SAP_* variables
85
90
  }
86
91
  const value = match[2].trim().replace(/^["']|["']$/g, ''); // Remove quotes
@@ -116,11 +121,11 @@ async function saveXsuaaTokenToEnv(destination, savePath, config, log) {
116
121
  : value;
117
122
  envLines.push(`${key}=${escapedValue}`);
118
123
  }
119
- const envContent = envLines.join('\n') + '\n';
124
+ const envContent = `${envLines.join('\n')}\n`;
120
125
  log?.debug(`Writing ${envLines.length} XSUAA variables to env file: ${Object.keys(config).join(', ')}`);
121
126
  // Write to temp file
122
127
  fs.writeFileSync(tempFilePath, envContent, 'utf8');
123
128
  // Atomic rename
124
129
  fs.renameSync(tempFilePath, envFilePath);
125
- log?.info(`XSUAA token saved to ${envFilePath}: token(${config.jwtToken.length} chars), mcpUrl(${config.mcpUrl ? config.mcpUrl.substring(0, 50) + '...' : 'none'}), variables(${envLines.length})`);
130
+ log?.info(`XSUAA token saved to ${envFilePath}: token(${config.jwtToken.length} chars), mcpUrl(${config.mcpUrl ? `${config.mcpUrl.substring(0, 50)}...` : 'none'}), variables(${envLines.length})`);
126
131
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ABAP Service key store - reads ABAP service keys from {destination}.json files
3
3
  */
4
- import type { IServiceKeyStore, IAuthorizationConfig, IConnectionConfig, IConfig, ILogger } from '@mcp-abap-adt/interfaces';
4
+ import type { IAuthorizationConfig, IConfig, IConnectionConfig, ILogger, IServiceKeyStore } from '@mcp-abap-adt/interfaces';
5
5
  /**
6
6
  * ABAP Service key store implementation
7
7
  *
@@ -37,10 +37,10 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.AbapServiceKeyStore = void 0;
40
- const JsonFileHandler_1 = require("../../utils/JsonFileHandler");
41
- const AbapServiceKeyParser_1 = require("../../parsers/abap/AbapServiceKeyParser");
40
+ const path = __importStar(require("node:path"));
42
41
  const StoreErrors_1 = require("../../errors/StoreErrors");
43
- const path = __importStar(require("path"));
42
+ const AbapServiceKeyParser_1 = require("../../parsers/abap/AbapServiceKeyParser");
43
+ const JsonFileHandler_1 = require("../../utils/JsonFileHandler");
44
44
  /**
45
45
  * ABAP Service key store implementation
46
46
  *
@@ -99,7 +99,10 @@ class AbapServiceKeyStore {
99
99
  }
100
100
  const key = parsed;
101
101
  this.log?.debug(`Parsed service key structure: hasUaa(${!!key.uaa}), uaaKeys(${key.uaa ? Object.keys(key.uaa).join(', ') : 'none'})`);
102
- if (!key.uaa || !key.uaa.url || !key.uaa.clientid || !key.uaa.clientsecret) {
102
+ if (!key.uaa ||
103
+ !key.uaa.url ||
104
+ !key.uaa.clientid ||
105
+ !key.uaa.clientsecret) {
103
106
  this.log?.warn(`Service key for ${destination} missing required UAA fields: url(${!!key.uaa?.url}), clientid(${!!key.uaa?.clientid}), clientsecret(${!!key.uaa?.clientsecret})`);
104
107
  return null;
105
108
  }
@@ -140,7 +143,9 @@ class AbapServiceKeyStore {
140
143
  const key = parsed;
141
144
  this.log?.debug(`Parsed service key structure: hasAbap(${!!key.abap}), hasSapUrl(${!!key.sap_url}), hasUrl(${!!key.url})`);
142
145
  // Service key doesn't have tokens - only URLs and client info
143
- const serviceUrl = key.abap?.url || key.sap_url || (key.url && !key.url.includes('authentication') ? key.url : undefined);
146
+ const serviceUrl = key.abap?.url ||
147
+ key.sap_url ||
148
+ (key.url && !key.url.includes('authentication') ? key.url : undefined);
144
149
  const sapClient = key.abap?.client || key.sap_client || key.client;
145
150
  const language = key.abap?.language || key.language;
146
151
  const result = {
@@ -149,7 +154,7 @@ class AbapServiceKeyStore {
149
154
  sapClient,
150
155
  language,
151
156
  };
152
- this.log?.info(`Connection config loaded from ${filePath}: serviceUrl(${serviceUrl ? serviceUrl.substring(0, 50) + '...' : 'none'}), client(${sapClient || 'none'}), language(${language || 'none'})`);
157
+ this.log?.info(`Connection config loaded from ${filePath}: serviceUrl(${serviceUrl ? `${serviceUrl.substring(0, 50)}...` : 'none'}), client(${sapClient || 'none'}), language(${language || 'none'})`);
153
158
  return result;
154
159
  }
155
160
  catch (error) {
@@ -5,7 +5,7 @@
5
5
  * Stores full ABAP configuration: SAP URL (sapUrl), JWT token, refresh token, UAA config, SAP client, language.
6
6
  * This extends base BTP store by adding sapUrl requirement.
7
7
  */
8
- import type { IAuthorizationConfig, IConnectionConfig, ISessionStore, IConfig, ILogger } from '@mcp-abap-adt/interfaces';
8
+ import type { IAuthorizationConfig, IConfig, IConnectionConfig, ILogger, ISessionStore } from '@mcp-abap-adt/interfaces';
9
9
  /**
10
10
  * ABAP Session store implementation
11
11
  *