@mcp-abap-adt/auth-stores 0.1.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/LICENSE +22 -0
  3. package/README.md +209 -0
  4. package/dist/index.d.ts +22 -0
  5. package/dist/index.js +53 -0
  6. package/dist/loaders/abap/serviceKeyLoader.d.ts +15 -0
  7. package/dist/loaders/abap/serviceKeyLoader.js +84 -0
  8. package/dist/loaders/xsuaa/xsuaaServiceKeyLoader.d.ts +19 -0
  9. package/dist/loaders/xsuaa/xsuaaServiceKeyLoader.js +80 -0
  10. package/dist/parsers/abap/AbapServiceKeyParser.d.ts +35 -0
  11. package/dist/parsers/abap/AbapServiceKeyParser.js +50 -0
  12. package/dist/parsers/xsuaa/XsuaaServiceKeyParser.d.ts +30 -0
  13. package/dist/parsers/xsuaa/XsuaaServiceKeyParser.js +72 -0
  14. package/dist/storage/abap/envLoader.d.ts +21 -0
  15. package/dist/storage/abap/envLoader.js +94 -0
  16. package/dist/storage/abap/tokenStorage.d.ts +24 -0
  17. package/dist/storage/abap/tokenStorage.js +113 -0
  18. package/dist/storage/xsuaa/xsuaaEnvLoader.d.ts +20 -0
  19. package/dist/storage/xsuaa/xsuaaEnvLoader.js +91 -0
  20. package/dist/storage/xsuaa/xsuaaTokenStorage.d.ts +19 -0
  21. package/dist/storage/xsuaa/xsuaaTokenStorage.js +115 -0
  22. package/dist/stores/abap/AbapServiceKeyStore.d.ts +34 -0
  23. package/dist/stores/abap/AbapServiceKeyStore.js +43 -0
  24. package/dist/stores/abap/AbapSessionStore.d.ts +80 -0
  25. package/dist/stores/abap/AbapSessionStore.js +239 -0
  26. package/dist/stores/abap/SafeAbapSessionStore.d.ts +35 -0
  27. package/dist/stores/abap/SafeAbapSessionStore.js +117 -0
  28. package/dist/stores/abstract/AbstractJsonSessionStore.d.ts +67 -0
  29. package/dist/stores/abstract/AbstractJsonSessionStore.js +99 -0
  30. package/dist/stores/abstract/AbstractSafeSessionStore.d.ts +89 -0
  31. package/dist/stores/abstract/AbstractSafeSessionStore.js +76 -0
  32. package/dist/stores/abstract/AbstractServiceKeyStore.d.ts +66 -0
  33. package/dist/stores/abstract/AbstractServiceKeyStore.js +165 -0
  34. package/dist/stores/btp/BtpServiceKeyStore.d.ts +34 -0
  35. package/dist/stores/btp/BtpServiceKeyStore.js +43 -0
  36. package/dist/stores/btp/BtpSessionStore.d.ts +79 -0
  37. package/dist/stores/btp/BtpSessionStore.js +247 -0
  38. package/dist/stores/btp/SafeBtpSessionStore.d.ts +32 -0
  39. package/dist/stores/btp/SafeBtpSessionStore.js +115 -0
  40. package/dist/stores/xsuaa/SafeXsuaaSessionStore.d.ts +34 -0
  41. package/dist/stores/xsuaa/SafeXsuaaSessionStore.js +117 -0
  42. package/dist/stores/xsuaa/XsuaaServiceKeyStore.d.ts +36 -0
  43. package/dist/stores/xsuaa/XsuaaServiceKeyStore.js +49 -0
  44. package/dist/stores/xsuaa/XsuaaSessionStore.d.ts +54 -0
  45. package/dist/stores/xsuaa/XsuaaSessionStore.js +223 -0
  46. package/dist/utils/constants.d.ts +83 -0
  47. package/dist/utils/constants.js +86 -0
  48. package/dist/utils/pathResolver.d.ts +20 -0
  49. package/dist/utils/pathResolver.js +105 -0
  50. package/package.json +63 -0
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * XSUAA Service Key Parser
4
+ *
5
+ * Parses direct XSUAA service key format from BTP (without nested uaa object):
6
+ * {
7
+ * "url": "https://...authentication...hana.ondemand.com",
8
+ * "clientid": "...",
9
+ * "clientsecret": "...",
10
+ * "tenantmode": "shared",
11
+ * ...
12
+ * }
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.XsuaaServiceKeyParser = void 0;
16
+ /**
17
+ * Parser for direct XSUAA service key format from BTP
18
+ */
19
+ class XsuaaServiceKeyParser {
20
+ /**
21
+ * Check if this parser can handle the given raw service key data
22
+ * @param rawData Raw JSON data from service key file
23
+ * @returns true if data has direct XSUAA fields (url, clientid, clientsecret) without nested uaa object
24
+ */
25
+ canParse(rawData) {
26
+ if (!rawData || typeof rawData !== 'object' || Array.isArray(rawData)) {
27
+ return false;
28
+ }
29
+ // Check for nested uaa object (ABAP format) - should not have it
30
+ if (rawData.uaa) {
31
+ return false;
32
+ }
33
+ // Check for required XSUAA fields at root level
34
+ return (typeof rawData.url === 'string' &&
35
+ typeof rawData.clientid === 'string' &&
36
+ typeof rawData.clientsecret === 'string' &&
37
+ rawData.url.length > 0 &&
38
+ rawData.clientid.length > 0 &&
39
+ rawData.clientsecret.length > 0);
40
+ }
41
+ /**
42
+ * Parse raw service key data
43
+ * @param rawData Raw JSON data from service key file
44
+ * @returns Parsed service key object (normalized format)
45
+ * @throws Error if data cannot be parsed or is invalid
46
+ */
47
+ parse(rawData) {
48
+ if (!this.canParse(rawData)) {
49
+ throw new Error('Service key does not match XSUAA format (missing url, clientid, or clientsecret at root level)');
50
+ }
51
+ // Normalize to standard format
52
+ // Prioritize apiurl over url for UAA authorization (if present)
53
+ const uaaUrl = rawData.apiurl || rawData.url;
54
+ return {
55
+ uaa: {
56
+ url: uaaUrl,
57
+ clientid: rawData.clientid,
58
+ clientsecret: rawData.clientsecret,
59
+ },
60
+ // Preserve abap.url if present
61
+ abap: rawData.abap,
62
+ // Preserve other optional fields
63
+ url: rawData.url, // UAA URL
64
+ apiurl: rawData.apiurl, // API URL (prioritized for UAA)
65
+ sap_url: rawData.sap_url,
66
+ client: rawData.client,
67
+ sap_client: rawData.sap_client,
68
+ language: rawData.language,
69
+ };
70
+ }
71
+ }
72
+ exports.XsuaaServiceKeyParser = XsuaaServiceKeyParser;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Environment file loader - loads .env files by destination name for ABAP
3
+ */
4
+ interface EnvConfig {
5
+ sapUrl: string;
6
+ sapClient?: string;
7
+ jwtToken: string;
8
+ refreshToken?: string;
9
+ uaaUrl?: string;
10
+ uaaClientId?: string;
11
+ uaaClientSecret?: string;
12
+ language?: string;
13
+ }
14
+ /**
15
+ * Load environment configuration from {destination}.env file
16
+ * @param destination Destination name
17
+ * @param searchPaths Array of paths to search for the file
18
+ * @returns EnvConfig object or null if file not found
19
+ */
20
+ export declare function loadEnvFile(destination: string, searchPaths: string[]): Promise<EnvConfig | null>;
21
+ export {};
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ /**
3
+ * Environment file loader - loads .env files by destination name for ABAP
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.loadEnvFile = loadEnvFile;
40
+ const fs = __importStar(require("fs"));
41
+ const dotenv = __importStar(require("dotenv"));
42
+ const pathResolver_1 = require("../../utils/pathResolver");
43
+ const constants_1 = require("../../utils/constants");
44
+ /**
45
+ * Load environment configuration from {destination}.env file
46
+ * @param destination Destination name
47
+ * @param searchPaths Array of paths to search for the file
48
+ * @returns EnvConfig object or null if file not found
49
+ */
50
+ async function loadEnvFile(destination, searchPaths) {
51
+ const fileName = `${destination}.env`;
52
+ const envFilePath = (0, pathResolver_1.findFileInPaths)(fileName, searchPaths);
53
+ if (!envFilePath) {
54
+ return null;
55
+ }
56
+ try {
57
+ // Read and parse .env file
58
+ const envContent = fs.readFileSync(envFilePath, 'utf8');
59
+ const parsed = dotenv.parse(envContent);
60
+ // Extract required fields
61
+ const sapUrl = parsed[constants_1.ABAP_CONNECTION_VARS.SERVICE_URL];
62
+ const jwtToken = parsed[constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN];
63
+ if (!sapUrl || !jwtToken) {
64
+ return null;
65
+ }
66
+ const config = {
67
+ sapUrl: sapUrl.trim(),
68
+ jwtToken: jwtToken.trim(),
69
+ };
70
+ // Optional fields
71
+ if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT]) {
72
+ config.sapClient = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT].trim();
73
+ }
74
+ if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN]) {
75
+ config.refreshToken = parsed[constants_1.ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN].trim();
76
+ }
77
+ if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_URL]) {
78
+ config.uaaUrl = parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_URL].trim();
79
+ }
80
+ if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_ID]) {
81
+ config.uaaClientId = parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_ID].trim();
82
+ }
83
+ if (parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET]) {
84
+ config.uaaClientSecret = parsed[constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET].trim();
85
+ }
86
+ if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE]) {
87
+ config.language = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE].trim();
88
+ }
89
+ return config;
90
+ }
91
+ catch (error) {
92
+ throw new Error(`Failed to load environment file for destination "${destination}": ${error instanceof Error ? error.message : String(error)}`);
93
+ }
94
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Token storage - saves tokens to .env files for ABAP
3
+ */
4
+ interface EnvConfig {
5
+ sapUrl: string;
6
+ sapClient?: string;
7
+ jwtToken: string;
8
+ refreshToken?: string;
9
+ uaaUrl?: string;
10
+ uaaClientId?: string;
11
+ uaaClientSecret?: string;
12
+ language?: string;
13
+ }
14
+ /**
15
+ * Save token to {destination}.env file
16
+ * @param destination Destination name
17
+ * @param savePath Path where to save the file
18
+ * @param config Configuration to save
19
+ */
20
+ export declare function saveTokenToEnv(destination: string, savePath: string, config: Partial<EnvConfig> & {
21
+ sapUrl?: string;
22
+ jwtToken: string;
23
+ }): Promise<void>;
24
+ export {};
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * Token storage - saves tokens to .env files for ABAP
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.saveTokenToEnv = saveTokenToEnv;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const constants_1 = require("../../utils/constants");
43
+ /**
44
+ * Save token to {destination}.env file
45
+ * @param destination Destination name
46
+ * @param savePath Path where to save the file
47
+ * @param config Configuration to save
48
+ */
49
+ async function saveTokenToEnv(destination, savePath, config) {
50
+ // Ensure directory exists
51
+ if (!fs.existsSync(savePath)) {
52
+ fs.mkdirSync(savePath, { recursive: true });
53
+ }
54
+ const envFilePath = path.join(savePath, `${destination}.env`);
55
+ const tempFilePath = `${envFilePath}.tmp`;
56
+ // Read existing .env file if it exists
57
+ let existingContent = '';
58
+ if (fs.existsSync(envFilePath)) {
59
+ existingContent = fs.readFileSync(envFilePath, 'utf8');
60
+ }
61
+ // Parse existing content to preserve other values
62
+ const lines = existingContent.split('\n');
63
+ const existingVars = new Map();
64
+ for (const line of lines) {
65
+ const trimmed = line.trim();
66
+ if (!trimmed || trimmed.startsWith('#')) {
67
+ continue;
68
+ }
69
+ const match = trimmed.match(/^([^=]+)=(.*)$/);
70
+ if (match) {
71
+ const key = match[1].trim();
72
+ const value = match[2].trim().replace(/^["']|["']$/g, ''); // Remove quotes
73
+ existingVars.set(key, value);
74
+ }
75
+ }
76
+ // Update with new values
77
+ if (config.sapUrl) {
78
+ existingVars.set(constants_1.ABAP_CONNECTION_VARS.SERVICE_URL, config.sapUrl);
79
+ }
80
+ existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, config.jwtToken);
81
+ if (config.sapClient) {
82
+ existingVars.set(constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT, config.sapClient);
83
+ }
84
+ if (config.language) {
85
+ existingVars.set(constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE, config.language);
86
+ }
87
+ if (config.refreshToken) {
88
+ existingVars.set(constants_1.ABAP_AUTHORIZATION_VARS.REFRESH_TOKEN, config.refreshToken);
89
+ }
90
+ if (config.uaaUrl) {
91
+ existingVars.set(constants_1.ABAP_AUTHORIZATION_VARS.UAA_URL, config.uaaUrl);
92
+ }
93
+ if (config.uaaClientId) {
94
+ existingVars.set(constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_ID, config.uaaClientId);
95
+ }
96
+ if (config.uaaClientSecret) {
97
+ existingVars.set(constants_1.ABAP_AUTHORIZATION_VARS.UAA_CLIENT_SECRET, config.uaaClientSecret);
98
+ }
99
+ // Write to temporary file first (atomic write)
100
+ const envLines = [];
101
+ for (const [key, value] of existingVars.entries()) {
102
+ // Escape value if it contains spaces or special characters
103
+ const escapedValue = value.includes(' ') || value.includes('=') || value.includes('#')
104
+ ? `"${value.replace(/"/g, '\\"')}"`
105
+ : value;
106
+ envLines.push(`${key}=${escapedValue}`);
107
+ }
108
+ const envContent = envLines.join('\n') + '\n';
109
+ // Write to temp file
110
+ fs.writeFileSync(tempFilePath, envContent, 'utf8');
111
+ // Atomic rename
112
+ fs.renameSync(tempFilePath, envFilePath);
113
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * XSUAA Environment file loader - loads .env files with XSUAA_* variables for XSUAA
3
+ */
4
+ interface XsuaaSessionConfig {
5
+ mcpUrl?: string;
6
+ jwtToken: string;
7
+ refreshToken?: string;
8
+ uaaUrl?: string;
9
+ uaaClientId?: string;
10
+ uaaClientSecret?: string;
11
+ }
12
+ /**
13
+ * Load XSUAA environment configuration from {destination}.env file
14
+ * Reads XSUAA_* variables instead of SAP_* variables
15
+ * @param destination Destination name
16
+ * @param searchPaths Array of paths to search for the file
17
+ * @returns XsuaaSessionConfig object or null if file not found
18
+ */
19
+ export declare function loadXsuaaEnvFile(destination: string, searchPaths: string[]): Promise<XsuaaSessionConfig | null>;
20
+ export {};
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * XSUAA Environment file loader - loads .env files with XSUAA_* variables for XSUAA
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.loadXsuaaEnvFile = loadXsuaaEnvFile;
40
+ const fs = __importStar(require("fs"));
41
+ const dotenv = __importStar(require("dotenv"));
42
+ const pathResolver_1 = require("../../utils/pathResolver");
43
+ const constants_1 = require("../../utils/constants");
44
+ /**
45
+ * Load XSUAA environment configuration from {destination}.env file
46
+ * Reads XSUAA_* variables instead of SAP_* variables
47
+ * @param destination Destination name
48
+ * @param searchPaths Array of paths to search for the file
49
+ * @returns XsuaaSessionConfig object or null if file not found
50
+ */
51
+ async function loadXsuaaEnvFile(destination, searchPaths) {
52
+ const fileName = `${destination}.env`;
53
+ const envFilePath = (0, pathResolver_1.findFileInPaths)(fileName, searchPaths);
54
+ if (!envFilePath) {
55
+ return null;
56
+ }
57
+ try {
58
+ // Read and parse .env file
59
+ const envContent = fs.readFileSync(envFilePath, 'utf8');
60
+ const parsed = dotenv.parse(envContent);
61
+ // Extract required fields (XSUAA_* variables)
62
+ const jwtToken = parsed[constants_1.XSUAA_CONNECTION_VARS.AUTHORIZATION_TOKEN];
63
+ if (!jwtToken) {
64
+ return null;
65
+ }
66
+ const config = {
67
+ jwtToken: jwtToken.trim(),
68
+ };
69
+ // mcpUrl can be loaded from .env file as additional variable (not part of CONNECTION_VARS, but can be stored)
70
+ // URL comes from elsewhere (YAML config, parameter, or request header), but can be stored in .env
71
+ if (parsed['XSUAA_MCP_URL']) {
72
+ config.mcpUrl = parsed['XSUAA_MCP_URL'].trim();
73
+ }
74
+ if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN]) {
75
+ config.refreshToken = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN].trim();
76
+ }
77
+ if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_URL]) {
78
+ config.uaaUrl = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_URL].trim();
79
+ }
80
+ if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID]) {
81
+ config.uaaClientId = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID].trim();
82
+ }
83
+ if (parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET]) {
84
+ config.uaaClientSecret = parsed[constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET].trim();
85
+ }
86
+ return config;
87
+ }
88
+ catch (error) {
89
+ throw new Error(`Failed to load XSUAA environment file for destination "${destination}": ${error instanceof Error ? error.message : String(error)}`);
90
+ }
91
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * XSUAA Token storage - saves tokens to .env files with XSUAA_* variables
3
+ */
4
+ interface XsuaaSessionConfig {
5
+ mcpUrl?: string;
6
+ jwtToken: string;
7
+ refreshToken?: string;
8
+ uaaUrl?: string;
9
+ uaaClientId?: string;
10
+ uaaClientSecret?: string;
11
+ }
12
+ /**
13
+ * Save XSUAA token to {destination}.env file using XSUAA_* variables
14
+ * @param destination Destination name
15
+ * @param savePath Path where to save the file
16
+ * @param config XSUAA session configuration to save
17
+ */
18
+ export declare function saveXsuaaTokenToEnv(destination: string, savePath: string, config: XsuaaSessionConfig): Promise<void>;
19
+ export {};
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ /**
3
+ * XSUAA Token storage - saves tokens to .env files with XSUAA_* variables
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.saveXsuaaTokenToEnv = saveXsuaaTokenToEnv;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const constants_1 = require("../../utils/constants");
43
+ /**
44
+ * Save XSUAA token to {destination}.env file using XSUAA_* variables
45
+ * @param destination Destination name
46
+ * @param savePath Path where to save the file
47
+ * @param config XSUAA session configuration to save
48
+ */
49
+ async function saveXsuaaTokenToEnv(destination, savePath, config) {
50
+ // Ensure directory exists
51
+ if (!fs.existsSync(savePath)) {
52
+ fs.mkdirSync(savePath, { recursive: true });
53
+ }
54
+ const envFilePath = path.join(savePath, `${destination}.env`);
55
+ const tempFilePath = `${envFilePath}.tmp`;
56
+ // Read existing .env file if it exists
57
+ let existingContent = '';
58
+ if (fs.existsSync(envFilePath)) {
59
+ existingContent = fs.readFileSync(envFilePath, 'utf8');
60
+ }
61
+ // Parse existing content to preserve other values
62
+ // Remove old SAP_* variables for XSUAA (use XSUAA_* instead)
63
+ const lines = existingContent.split('\n');
64
+ const existingVars = new Map();
65
+ for (const line of lines) {
66
+ const trimmed = line.trim();
67
+ if (!trimmed || trimmed.startsWith('#')) {
68
+ continue;
69
+ }
70
+ const match = trimmed.match(/^([^=]+)=(.*)$/);
71
+ if (match) {
72
+ const key = match[1].trim();
73
+ // Skip old SAP_* variables for XSUAA (we use XSUAA_* now)
74
+ if (key.startsWith('SAP_') && (key === 'SAP_URL' || key === 'SAP_JWT_TOKEN' || key === 'SAP_REFRESH_TOKEN' ||
75
+ key === 'SAP_UAA_URL' || key === 'SAP_UAA_CLIENT_ID' || key === 'SAP_UAA_CLIENT_SECRET')) {
76
+ continue; // Don't preserve old SAP_* variables
77
+ }
78
+ const value = match[2].trim().replace(/^["']|["']$/g, ''); // Remove quotes
79
+ existingVars.set(key, value);
80
+ }
81
+ }
82
+ // Update with new values (XSUAA_* variables)
83
+ // mcpUrl can be saved as additional variable (not part of CONNECTION_VARS, but can be stored for convenience)
84
+ // URL comes from elsewhere (YAML config, parameter, or request header), but can be stored in .env
85
+ if (config.mcpUrl) {
86
+ existingVars.set('XSUAA_MCP_URL', config.mcpUrl); // Store as additional variable (not in CONNECTION_VARS)
87
+ }
88
+ existingVars.set(constants_1.XSUAA_CONNECTION_VARS.AUTHORIZATION_TOKEN, config.jwtToken);
89
+ if (config.refreshToken) {
90
+ existingVars.set(constants_1.XSUAA_AUTHORIZATION_VARS.REFRESH_TOKEN, config.refreshToken);
91
+ }
92
+ if (config.uaaUrl) {
93
+ existingVars.set(constants_1.XSUAA_AUTHORIZATION_VARS.UAA_URL, config.uaaUrl);
94
+ }
95
+ if (config.uaaClientId) {
96
+ existingVars.set(constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_ID, config.uaaClientId);
97
+ }
98
+ if (config.uaaClientSecret) {
99
+ existingVars.set(constants_1.XSUAA_AUTHORIZATION_VARS.UAA_CLIENT_SECRET, config.uaaClientSecret);
100
+ }
101
+ // Write to temporary file first (atomic write)
102
+ const envLines = [];
103
+ for (const [key, value] of existingVars.entries()) {
104
+ // Escape value if it contains spaces or special characters
105
+ const escapedValue = value.includes(' ') || value.includes('=') || value.includes('#')
106
+ ? `"${value.replace(/"/g, '\\"')}"`
107
+ : value;
108
+ envLines.push(`${key}=${escapedValue}`);
109
+ }
110
+ const envContent = envLines.join('\n') + '\n';
111
+ // Write to temp file
112
+ fs.writeFileSync(tempFilePath, envContent, 'utf8');
113
+ // Atomic rename
114
+ fs.renameSync(tempFilePath, envFilePath);
115
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * ABAP Service key store - reads ABAP service keys from {destination}.json files
3
+ *
4
+ * Uses AbstractServiceKeyStore for file I/O and AbapServiceKeyParser for parsing.
5
+ * This extends base BTP by supporting ABAP service key format with nested uaa object.
6
+ */
7
+ import type { IServiceKeyStore } from '@mcp-abap-adt/auth-broker';
8
+ import { AbstractServiceKeyStore } from '../abstract/AbstractServiceKeyStore';
9
+ /**
10
+ * ABAP Service key store implementation
11
+ *
12
+ * Uses AbstractServiceKeyStore for file operations and AbapServiceKeyParser for parsing.
13
+ * Search paths priority:
14
+ * 1. Constructor parameter (highest)
15
+ * 2. AUTH_BROKER_PATH environment variable
16
+ * 3. Current working directory (lowest)
17
+ */
18
+ export declare class AbapServiceKeyStore extends AbstractServiceKeyStore implements IServiceKeyStore {
19
+ private parser;
20
+ /**
21
+ * Create a new AbapServiceKeyStore instance
22
+ * @param searchPaths Optional search paths for .json files.
23
+ * Can be a single path (string) or array of paths.
24
+ * If not provided, uses AUTH_BROKER_PATH env var or current working directory.
25
+ */
26
+ constructor(searchPaths?: string | string[]);
27
+ /**
28
+ * Parse raw JSON data using AbapServiceKeyParser
29
+ * @param rawData Raw JSON data from service key file
30
+ * @returns Parsed service key object
31
+ * @throws Error if data cannot be parsed or is invalid
32
+ */
33
+ protected parse(rawData: any): unknown;
34
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * ABAP Service key store - reads ABAP service keys from {destination}.json files
4
+ *
5
+ * Uses AbstractServiceKeyStore for file I/O and AbapServiceKeyParser for parsing.
6
+ * This extends base BTP by supporting ABAP service key format with nested uaa object.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AbapServiceKeyStore = void 0;
10
+ const AbstractServiceKeyStore_1 = require("../abstract/AbstractServiceKeyStore");
11
+ const AbapServiceKeyParser_1 = require("../../parsers/abap/AbapServiceKeyParser");
12
+ /**
13
+ * ABAP Service key store implementation
14
+ *
15
+ * Uses AbstractServiceKeyStore for file operations and AbapServiceKeyParser for parsing.
16
+ * Search paths priority:
17
+ * 1. Constructor parameter (highest)
18
+ * 2. AUTH_BROKER_PATH environment variable
19
+ * 3. Current working directory (lowest)
20
+ */
21
+ class AbapServiceKeyStore extends AbstractServiceKeyStore_1.AbstractServiceKeyStore {
22
+ parser;
23
+ /**
24
+ * Create a new AbapServiceKeyStore instance
25
+ * @param searchPaths Optional search paths for .json files.
26
+ * Can be a single path (string) or array of paths.
27
+ * If not provided, uses AUTH_BROKER_PATH env var or current working directory.
28
+ */
29
+ constructor(searchPaths) {
30
+ super(searchPaths);
31
+ this.parser = new AbapServiceKeyParser_1.AbapServiceKeyParser();
32
+ }
33
+ /**
34
+ * Parse raw JSON data using AbapServiceKeyParser
35
+ * @param rawData Raw JSON data from service key file
36
+ * @returns Parsed service key object
37
+ * @throws Error if data cannot be parsed or is invalid
38
+ */
39
+ parse(rawData) {
40
+ return this.parser.parse(rawData);
41
+ }
42
+ }
43
+ exports.AbapServiceKeyStore = AbapServiceKeyStore;