@mcp-abap-adt/auth-broker 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,12 +9,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the complete list.
11
11
 
12
- ## [0.1.0] - 2025-01-XX
12
+ ## [0.1.2] - 2025-11-30
13
+
14
+ ### Added
15
+ - **Storage Interfaces** - New interfaces for custom storage implementations
16
+ - `ServiceKeyStore` interface - for reading service keys
17
+ - `SessionStore` interface - for reading/writing session data (tokens, configuration)
18
+ - `FileServiceKeyStore` - default file-based implementation for service keys
19
+ - `FileSessionStore` - default file-based implementation for sessions
20
+ - **Dependency Injection Support** - AuthBroker now accepts custom stores via constructor
21
+ - Can provide custom `ServiceKeyStore` and `SessionStore` implementations
22
+ - Default to file-based stores if not provided (backward compatible)
23
+ - Enables custom storage backends (database, cloud, etc.) without creating new packages
24
+ - New API: constructor accepts object with `serviceKeyStore` and `sessionStore` properties
25
+ - Backward compatible: still accepts `searchPaths` as first parameter (string/array)
26
+
27
+ ### Technical Details
28
+ - Storage abstraction allows consumers to provide custom implementations
29
+ - No breaking changes - existing code continues to work
30
+ - File-based stores remain the default implementation
31
+
32
+ ## [0.1.1] - 2025-11-30
33
+
34
+ ### Added
35
+ - **AuthBroker.getSapUrl()** - New method to get SAP URL for destination
36
+ - Loads URL from `.env` file first, then from service key
37
+ - Returns `undefined` if URL not found
38
+ - Useful for destination-based authentication where URL comes from destination, not headers
39
+
40
+ ## [0.1.0] - 2025-11-30
13
41
 
14
42
  ### Added
15
43
  - **AuthBroker class** - Main class for managing JWT authentication tokens
16
44
  - `getToken(destination)` - Get token for destination (loads, validates, refreshes if needed)
17
45
  - `refreshToken(destination)` - Force refresh token using service key or browser authentication
46
+ - `getSapUrl(destination)` - Get SAP URL for destination (loads from .env or service key)
18
47
  - `clearCache(destination)` - Clear cached token for specific destination
19
48
  - `clearAllCache()` - Clear all cached tokens
20
49
  - **Multi-path file search** - Configurable search paths for `.env` and `.json` files
@@ -2,6 +2,7 @@
2
2
  * Main AuthBroker class for managing JWT tokens based on destinations
3
3
  */
4
4
  import { Logger } from './logger';
5
+ import { ServiceKeyStore, SessionStore } from './stores/interfaces';
5
6
  /**
6
7
  * AuthBroker manages JWT authentication tokens for destinations
7
8
  */
@@ -9,26 +10,33 @@ export declare class AuthBroker {
9
10
  private searchPaths;
10
11
  private browser;
11
12
  private logger;
13
+ private serviceKeyStore;
14
+ private sessionStore;
12
15
  /**
13
16
  * Create a new AuthBroker instance
14
- * @param searchPaths Optional search paths for .env and .json files.
15
- * Can be a single path (string) or array of paths.
16
- * Priority:
17
- * 1. Constructor parameter (highest)
18
- * 2. AUTH_BROKER_PATH environment variable (colon/semicolon-separated)
19
- * 3. Current working directory (lowest)
17
+ * @param searchPathsOrStores Optional search paths for .env and .json files (backward compatibility),
18
+ * OR object with custom stores.
19
+ * If string/array: creates default file-based stores with these paths.
20
+ * If object: uses provided stores (searchPaths ignored).
21
+ * Priority for searchPaths:
22
+ * 1. Constructor parameter (highest)
23
+ * 2. AUTH_BROKER_PATH environment variable (colon/semicolon-separated)
24
+ * 3. Current working directory (lowest)
20
25
  * @param browser Optional browser name for authentication (chrome, edge, firefox, system, none).
21
26
  * Default: 'system' (system default browser).
22
27
  * Use 'none' to print URL instead of opening browser.
23
28
  * @param logger Optional logger instance. If not provided, uses default logger.
24
29
  */
25
- constructor(searchPaths?: string | string[], browser?: string, logger?: Logger);
30
+ constructor(searchPathsOrStores?: string | string[] | {
31
+ serviceKeyStore?: ServiceKeyStore;
32
+ sessionStore?: SessionStore;
33
+ }, browser?: string, logger?: Logger);
26
34
  /**
27
35
  * Get authentication token for destination.
28
- * Tries to load from .env file, validates it, and refreshes if needed.
36
+ * Tries to load from session store, validates it, and refreshes if needed.
29
37
  * @param destination Destination name (e.g., "TRIAL")
30
38
  * @returns Promise that resolves to JWT token string
31
- * @throws Error if neither .env file nor service key found
39
+ * @throws Error if neither session data nor service key found
32
40
  */
33
41
  getToken(destination: string): Promise<string>;
34
42
  /**
@@ -39,16 +47,17 @@ export declare class AuthBroker {
39
47
  */
40
48
  refreshToken(destination: string): Promise<string>;
41
49
  /**
42
- * Save token to {destination}.env file
43
- * Creates .env file similar to sap-abap-auth utility format
50
+ * Internal refresh token implementation
44
51
  * @private
45
52
  */
46
- private saveTokenToEnv;
53
+ private refreshTokenInternal;
47
54
  /**
48
- * Get token expiry information from JWT token
49
- * @private
55
+ * Get SAP URL for destination.
56
+ * Tries to load from session store first, then from service key store.
57
+ * @param destination Destination name (e.g., "TRIAL")
58
+ * @returns Promise that resolves to SAP URL string, or undefined if not found
50
59
  */
51
- private getTokenExpiry;
60
+ getSapUrl(destination: string): Promise<string | undefined>;
52
61
  /**
53
62
  * Clear cached token for specific destination
54
63
  * @param destination Destination name
@@ -58,5 +67,10 @@ export declare class AuthBroker {
58
67
  * Clear all cached tokens
59
68
  */
60
69
  clearAllCache(): void;
70
+ /**
71
+ * Get search paths for error messages (from file stores if available)
72
+ * @private
73
+ */
74
+ private getSearchPathsForError;
61
75
  }
62
76
  //# sourceMappingURL=AuthBroker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,EAAE,MAAM,EAAiB,MAAM,UAAU,CAAC;AAIjD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;;;;;;;;;OAYG;gBACS,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAM9E;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKpD;;;;;OAKG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKxD;;;;OAIG;YACW,cAAc;IA6E5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAyCtB;;;OAGG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACH,aAAa,IAAI,IAAI;CAGtB"}
1
+ {"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,EAAE,MAAM,EAAiB,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGpE;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAe;IAEnC;;;;;;;;;;;;;;OAcG;gBAED,mBAAmB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG;QAAE,eAAe,CAAC,EAAE,eAAe,CAAC;QAAC,YAAY,CAAC,EAAE,YAAY,CAAA;KAAE,EAC5G,OAAO,CAAC,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM;IAmBjB;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgDpD;;;;;OAKG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmBxD;;;OAGG;YACW,oBAAoB;IAuDlC;;;;;OAKG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAiBjE;;;OAGG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;CAW/B"}
@@ -2,48 +2,15 @@
2
2
  /**
3
3
  * Main AuthBroker class for managing JWT tokens based on destinations
4
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
5
  Object.defineProperty(exports, "__esModule", { value: true });
39
6
  exports.AuthBroker = void 0;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
7
+ const tokenValidator_1 = require("./tokenValidator");
8
+ const tokenRefresher_1 = require("./tokenRefresher");
9
+ const browserAuth_1 = require("./browserAuth");
42
10
  const cache_1 = require("./cache");
43
11
  const pathResolver_1 = require("./pathResolver");
44
12
  const logger_1 = require("./logger");
45
- const refreshToken_1 = require("./refreshToken");
46
- const getToken_1 = require("./getToken");
13
+ const stores_1 = require("./stores");
47
14
  /**
48
15
  * AuthBroker manages JWT authentication tokens for destinations
49
16
  */
@@ -51,34 +18,88 @@ class AuthBroker {
51
18
  searchPaths;
52
19
  browser;
53
20
  logger;
21
+ serviceKeyStore;
22
+ sessionStore;
54
23
  /**
55
24
  * Create a new AuthBroker instance
56
- * @param searchPaths Optional search paths for .env and .json files.
57
- * Can be a single path (string) or array of paths.
58
- * Priority:
59
- * 1. Constructor parameter (highest)
60
- * 2. AUTH_BROKER_PATH environment variable (colon/semicolon-separated)
61
- * 3. Current working directory (lowest)
25
+ * @param searchPathsOrStores Optional search paths for .env and .json files (backward compatibility),
26
+ * OR object with custom stores.
27
+ * If string/array: creates default file-based stores with these paths.
28
+ * If object: uses provided stores (searchPaths ignored).
29
+ * Priority for searchPaths:
30
+ * 1. Constructor parameter (highest)
31
+ * 2. AUTH_BROKER_PATH environment variable (colon/semicolon-separated)
32
+ * 3. Current working directory (lowest)
62
33
  * @param browser Optional browser name for authentication (chrome, edge, firefox, system, none).
63
34
  * Default: 'system' (system default browser).
64
35
  * Use 'none' to print URL instead of opening browser.
65
36
  * @param logger Optional logger instance. If not provided, uses default logger.
66
37
  */
67
- constructor(searchPaths, browser, logger) {
68
- this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(searchPaths);
38
+ constructor(searchPathsOrStores, browser, logger) {
39
+ // Handle backward compatibility: if first param is string/array, treat as searchPaths
40
+ if (typeof searchPathsOrStores === 'string' || Array.isArray(searchPathsOrStores) || searchPathsOrStores === undefined) {
41
+ this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(searchPathsOrStores);
42
+ // Create default file-based stores
43
+ this.serviceKeyStore = new stores_1.FileServiceKeyStore(this.searchPaths);
44
+ this.sessionStore = new stores_1.FileSessionStore(this.searchPaths);
45
+ }
46
+ else {
47
+ // New API: stores provided
48
+ this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(undefined); // Still resolve for backward compatibility in internal functions
49
+ this.serviceKeyStore = searchPathsOrStores.serviceKeyStore || new stores_1.FileServiceKeyStore();
50
+ this.sessionStore = searchPathsOrStores.sessionStore || new stores_1.FileSessionStore();
51
+ }
69
52
  this.browser = browser || 'system';
70
53
  this.logger = logger || logger_1.defaultLogger;
71
54
  }
72
55
  /**
73
56
  * Get authentication token for destination.
74
- * Tries to load from .env file, validates it, and refreshes if needed.
57
+ * Tries to load from session store, validates it, and refreshes if needed.
75
58
  * @param destination Destination name (e.g., "TRIAL")
76
59
  * @returns Promise that resolves to JWT token string
77
- * @throws Error if neither .env file nor service key found
60
+ * @throws Error if neither session data nor service key found
78
61
  */
79
62
  async getToken(destination) {
80
- // Use getToken function with logger
81
- return (0, getToken_1.getToken)(destination, this.searchPaths, this.logger);
63
+ // Check cache first
64
+ const cachedToken = (0, cache_1.getCachedToken)(destination);
65
+ if (cachedToken) {
66
+ // Validate cached token
67
+ const envConfig = await this.sessionStore.loadSession(destination);
68
+ if (envConfig) {
69
+ const isValid = await (0, tokenValidator_1.validateToken)(cachedToken, envConfig.sapUrl);
70
+ if (isValid) {
71
+ return cachedToken;
72
+ }
73
+ // Token expired, remove from cache
74
+ }
75
+ }
76
+ // Load from session store
77
+ const envConfig = await this.sessionStore.loadSession(destination);
78
+ if (envConfig && envConfig.jwtToken) {
79
+ // Validate token
80
+ const isValid = await (0, tokenValidator_1.validateToken)(envConfig.jwtToken, envConfig.sapUrl);
81
+ if (isValid) {
82
+ (0, cache_1.setCachedToken)(destination, envConfig.jwtToken);
83
+ return envConfig.jwtToken;
84
+ }
85
+ }
86
+ // Token not found or expired, check if we have service key for browser auth
87
+ const serviceKey = await this.serviceKeyStore.getServiceKey(destination);
88
+ if (!serviceKey) {
89
+ // No service key and no valid token - throw error with helpful message
90
+ const searchPaths = this.getSearchPathsForError();
91
+ const searchedPaths = searchPaths.map(p => ` - ${p}`).join('\n');
92
+ throw new Error(`No authentication found for destination "${destination}". ` +
93
+ `Neither ${destination}.env file nor ${destination}.json service key found.\n` +
94
+ `Please create one of:\n` +
95
+ ` - ${destination}.env (with SAP_JWT_TOKEN)\n` +
96
+ ` - ${destination}.json (service key)\n` +
97
+ `Searched in:\n${searchedPaths}`);
98
+ }
99
+ // Try to refresh (will use browser auth if no refresh token)
100
+ const newToken = await this.refreshTokenInternal(destination, serviceKey, envConfig);
101
+ (0, cache_1.setCachedToken)(destination, newToken);
102
+ return newToken;
82
103
  }
83
104
  /**
84
105
  * Force refresh token for destination using service key.
@@ -87,120 +108,81 @@ class AuthBroker {
87
108
  * @returns Promise that resolves to new JWT token string
88
109
  */
89
110
  async refreshToken(destination) {
90
- // Use refreshToken function with logger and browser
91
- return (0, refreshToken_1.refreshToken)(destination, this.searchPaths, this.logger);
111
+ // Load service key
112
+ const serviceKey = await this.serviceKeyStore.getServiceKey(destination);
113
+ if (!serviceKey) {
114
+ const searchPaths = this.getSearchPathsForError();
115
+ const searchedPaths = searchPaths.map(p => ` - ${p}`).join('\n');
116
+ throw new Error(`Service key file not found for destination "${destination}".\n` +
117
+ `Please create file: ${destination}.json\n` +
118
+ `Searched in:\n${searchedPaths}`);
119
+ }
120
+ // Load existing session (for refresh token)
121
+ const envConfig = await this.sessionStore.loadSession(destination);
122
+ return this.refreshTokenInternal(destination, serviceKey, envConfig);
92
123
  }
93
124
  /**
94
- * Save token to {destination}.env file
95
- * Creates .env file similar to sap-abap-auth utility format
125
+ * Internal refresh token implementation
96
126
  * @private
97
127
  */
98
- async saveTokenToEnv(destination, savePath, config) {
99
- // Ensure directory exists
100
- if (!fs.existsSync(savePath)) {
101
- fs.mkdirSync(savePath, { recursive: true });
102
- }
103
- const envFilePath = path.join(savePath, `${destination}.env`);
104
- const tempFilePath = `${envFilePath}.tmp`;
105
- // Write to temporary file first (atomic write)
106
- // Format similar to sap-abap-auth utility - always create fresh file
107
- const envLines = [];
108
- // Add token expiry information if we can decode JWT
109
- const jwtExpiry = this.getTokenExpiry(config.jwtToken);
110
- const refreshExpiry = config.refreshToken ? this.getTokenExpiry(config.refreshToken) : null;
111
- if (jwtExpiry || refreshExpiry) {
112
- envLines.push('# Token Expiry Information (auto-generated)');
113
- if (jwtExpiry) {
114
- envLines.push(`# JWT Token expires: ${jwtExpiry.readableDate} (UTC)`);
115
- envLines.push(`# JWT Token expires at: ${jwtExpiry.dateString}`);
116
- }
117
- else {
118
- envLines.push('# JWT Token expiry: Unable to determine (token may not be a standard JWT)');
119
- }
120
- if (refreshExpiry) {
121
- envLines.push(`# Refresh Token expires: ${refreshExpiry.readableDate} (UTC)`);
122
- envLines.push(`# Refresh Token expires at: ${refreshExpiry.dateString}`);
123
- }
124
- else if (config.refreshToken) {
125
- envLines.push('# Refresh Token expiry: Unable to determine (token may not be a standard JWT)');
126
- }
127
- envLines.push('');
128
+ async refreshTokenInternal(destination, serviceKey, envConfig) {
129
+ // Extract UAA configuration
130
+ const { url: uaaUrl, clientid: clientId, clientsecret: clientSecret } = serviceKey.uaa;
131
+ if (!uaaUrl || !clientId || !clientSecret) {
132
+ throw new Error(`Invalid service key for destination "${destination}". ` +
133
+ `Missing required UAA fields: url, clientid, clientsecret`);
128
134
  }
129
- // Write JWT auth parameters (similar to sap-abap-auth format)
130
- // Required fields
131
- envLines.push(`SAP_URL=${config.sapUrl}`);
132
- if (config.sapClient) {
133
- envLines.push(`SAP_CLIENT=${config.sapClient}`);
135
+ // Validate SAP URL early (before starting browser auth or refresh)
136
+ const sapUrl = serviceKey.url || serviceKey.abap?.url || serviceKey.sap_url;
137
+ if (!sapUrl) {
138
+ throw new Error(`Service key for destination "${destination}" does not contain SAP URL. ` +
139
+ `Expected field: url, abap.url, or sap_url`);
134
140
  }
135
- if (config.language) {
136
- envLines.push(`SAP_LANGUAGE=${config.language}`);
141
+ // Try to load existing refresh token from session store
142
+ let refreshTokenValue = envConfig?.refreshToken;
143
+ let result;
144
+ // If no refresh token, start browser authentication flow
145
+ if (!refreshTokenValue) {
146
+ this.logger.debug(`No refresh token found for destination "${destination}". Starting browser authentication...`);
147
+ result = await (0, browserAuth_1.startBrowserAuth)(serviceKey, this.browser || 'system', this.logger);
137
148
  }
138
- envLines.push('TLS_REJECT_UNAUTHORIZED=0');
139
- envLines.push('SAP_AUTH_TYPE=jwt');
140
- envLines.push(`SAP_JWT_TOKEN=${config.jwtToken}`);
141
- if (config.refreshToken) {
142
- envLines.push(`SAP_REFRESH_TOKEN=${config.refreshToken}`);
149
+ else {
150
+ // Refresh token using refresh token
151
+ result = await (0, tokenRefresher_1.refreshJwtToken)(refreshTokenValue, uaaUrl, clientId, clientSecret);
143
152
  }
144
- if (config.uaaUrl) {
145
- envLines.push(`SAP_UAA_URL=${config.uaaUrl}`);
146
- }
147
- if (config.uaaClientId) {
148
- envLines.push(`SAP_UAA_CLIENT_ID=${config.uaaClientId}`);
149
- }
150
- if (config.uaaClientSecret) {
151
- envLines.push(`SAP_UAA_CLIENT_SECRET=${config.uaaClientSecret}`);
152
- }
153
- envLines.push('');
154
- envLines.push('# For JWT authentication');
155
- envLines.push('# SAP_USERNAME=your_username');
156
- envLines.push('# SAP_PASSWORD=your_password');
157
- const envContent = envLines.join('\n') + '\n';
158
- // Write to temp file
159
- fs.writeFileSync(tempFilePath, envContent, 'utf8');
160
- // Atomic rename
161
- fs.renameSync(tempFilePath, envFilePath);
153
+ // Save new token to session store
154
+ await this.sessionStore.saveSession(destination, {
155
+ sapUrl,
156
+ jwtToken: result.accessToken,
157
+ refreshToken: result.refreshToken || refreshTokenValue,
158
+ uaaUrl,
159
+ uaaClientId: clientId,
160
+ uaaClientSecret: clientSecret,
161
+ sapClient: envConfig?.sapClient,
162
+ language: envConfig?.language,
163
+ });
164
+ // Update cache with new token
165
+ (0, cache_1.setCachedToken)(destination, result.accessToken);
166
+ return result.accessToken;
162
167
  }
163
168
  /**
164
- * Get token expiry information from JWT token
165
- * @private
169
+ * Get SAP URL for destination.
170
+ * Tries to load from session store first, then from service key store.
171
+ * @param destination Destination name (e.g., "TRIAL")
172
+ * @returns Promise that resolves to SAP URL string, or undefined if not found
166
173
  */
167
- getTokenExpiry(token) {
168
- try {
169
- // JWT tokens have format: header.payload.signature
170
- const parts = token.split('.');
171
- if (parts.length !== 3) {
172
- return null;
173
- }
174
- // Decode payload (base64url)
175
- const payload = parts[1];
176
- // Add padding if needed
177
- const padded = payload + '='.repeat((4 - payload.length % 4) % 4);
178
- const decoded = Buffer.from(padded.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8');
179
- const parsed = JSON.parse(decoded);
180
- // Check for exp claim
181
- if (parsed.exp) {
182
- const expiryDate = new Date(parsed.exp * 1000);
183
- const readableDate = expiryDate.toLocaleString('en-US', {
184
- weekday: 'long',
185
- year: 'numeric',
186
- month: 'long',
187
- day: 'numeric',
188
- hour: '2-digit',
189
- minute: '2-digit',
190
- second: '2-digit',
191
- timeZone: 'UTC',
192
- timeZoneName: 'short',
193
- });
194
- return {
195
- dateString: expiryDate.toISOString(),
196
- readableDate: readableDate,
197
- };
198
- }
199
- return null;
174
+ async getSapUrl(destination) {
175
+ // Try to load from session store first
176
+ const envConfig = await this.sessionStore.loadSession(destination);
177
+ if (envConfig?.sapUrl) {
178
+ return envConfig.sapUrl;
200
179
  }
201
- catch {
202
- return null;
180
+ // Try service key store
181
+ const serviceKey = await this.serviceKeyStore.getServiceKey(destination);
182
+ if (serviceKey) {
183
+ return serviceKey.url || serviceKey.abap?.url || serviceKey.sap_url;
203
184
  }
185
+ return undefined;
204
186
  }
205
187
  /**
206
188
  * Clear cached token for specific destination
@@ -215,5 +197,20 @@ class AuthBroker {
215
197
  clearAllCache() {
216
198
  (0, cache_1.clearAllCache)();
217
199
  }
200
+ /**
201
+ * Get search paths for error messages (from file stores if available)
202
+ * @private
203
+ */
204
+ getSearchPathsForError() {
205
+ // Try to get search paths from file stores
206
+ if (this.serviceKeyStore instanceof stores_1.FileServiceKeyStore) {
207
+ return this.serviceKeyStore.getSearchPaths();
208
+ }
209
+ if (this.sessionStore instanceof stores_1.FileSessionStore) {
210
+ return this.sessionStore.getSearchPaths();
211
+ }
212
+ // Fallback to stored searchPaths (for backward compatibility)
213
+ return this.searchPaths;
214
+ }
218
215
  }
219
216
  exports.AuthBroker = AuthBroker;
package/dist/index.d.ts CHANGED
@@ -5,4 +5,6 @@
5
5
  export { AuthBroker } from './AuthBroker';
6
6
  export type { EnvConfig, ServiceKey } from './types';
7
7
  export { resolveSearchPaths, findFileInPaths } from './pathResolver';
8
+ export { ServiceKeyStore, SessionStore } from './stores/interfaces';
9
+ export { FileServiceKeyStore, FileSessionStore } from './stores';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGrE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -4,9 +4,12 @@
4
4
  * JWT authentication broker for MCP ABAP ADT server
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.findFileInPaths = exports.resolveSearchPaths = exports.AuthBroker = void 0;
7
+ exports.FileSessionStore = exports.FileServiceKeyStore = exports.findFileInPaths = exports.resolveSearchPaths = exports.AuthBroker = void 0;
8
8
  var AuthBroker_1 = require("./AuthBroker");
9
9
  Object.defineProperty(exports, "AuthBroker", { enumerable: true, get: function () { return AuthBroker_1.AuthBroker; } });
10
10
  var pathResolver_1 = require("./pathResolver");
11
11
  Object.defineProperty(exports, "resolveSearchPaths", { enumerable: true, get: function () { return pathResolver_1.resolveSearchPaths; } });
12
12
  Object.defineProperty(exports, "findFileInPaths", { enumerable: true, get: function () { return pathResolver_1.findFileInPaths; } });
13
+ var stores_1 = require("./stores");
14
+ Object.defineProperty(exports, "FileServiceKeyStore", { enumerable: true, get: function () { return stores_1.FileServiceKeyStore; } });
15
+ Object.defineProperty(exports, "FileSessionStore", { enumerable: true, get: function () { return stores_1.FileSessionStore; } });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * File-based implementation of ServiceKeyStore
3
+ *
4
+ * Reads service keys from {destination}.json files in search paths.
5
+ */
6
+ import { ServiceKeyStore } from './interfaces';
7
+ import { ServiceKey } from '../types';
8
+ /**
9
+ * File-based service key store implementation
10
+ *
11
+ * Searches for {destination}.json files in configured search paths.
12
+ * Search paths priority:
13
+ * 1. Constructor parameter (highest)
14
+ * 2. AUTH_BROKER_PATH environment variable
15
+ * 3. Current working directory (lowest)
16
+ */
17
+ export declare class FileServiceKeyStore implements ServiceKeyStore {
18
+ private searchPaths;
19
+ /**
20
+ * Create a new FileServiceKeyStore instance
21
+ * @param searchPaths Optional search paths for .json files.
22
+ * Can be a single path (string) or array of paths.
23
+ * If not provided, uses AUTH_BROKER_PATH env var or current working directory.
24
+ */
25
+ constructor(searchPaths?: string | string[]);
26
+ /**
27
+ * Get service key for destination
28
+ * @param destination Destination name (e.g., "TRIAL")
29
+ * @returns ServiceKey object or null if not found
30
+ */
31
+ getServiceKey(destination: string): Promise<ServiceKey | null>;
32
+ /**
33
+ * Get search paths (for error messages)
34
+ * @returns Array of search paths
35
+ */
36
+ getSearchPaths(): string[];
37
+ }
38
+ //# sourceMappingURL=FileServiceKeyStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileServiceKeyStore.d.ts","sourceRoot":"","sources":["../../src/stores/FileServiceKeyStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,WAAW,CAAW;IAE9B;;;;;OAKG;gBACS,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAI3C;;;;OAIG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAIpE;;;OAGG;IACH,cAAc,IAAI,MAAM,EAAE;CAG3B"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * File-based implementation of ServiceKeyStore
4
+ *
5
+ * Reads service keys from {destination}.json files in search paths.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.FileServiceKeyStore = void 0;
9
+ const serviceKeyLoader_1 = require("../serviceKeyLoader");
10
+ const pathResolver_1 = require("../pathResolver");
11
+ /**
12
+ * File-based service key store implementation
13
+ *
14
+ * Searches for {destination}.json files in configured search paths.
15
+ * Search paths priority:
16
+ * 1. Constructor parameter (highest)
17
+ * 2. AUTH_BROKER_PATH environment variable
18
+ * 3. Current working directory (lowest)
19
+ */
20
+ class FileServiceKeyStore {
21
+ searchPaths;
22
+ /**
23
+ * Create a new FileServiceKeyStore instance
24
+ * @param searchPaths Optional search paths for .json files.
25
+ * Can be a single path (string) or array of paths.
26
+ * If not provided, uses AUTH_BROKER_PATH env var or current working directory.
27
+ */
28
+ constructor(searchPaths) {
29
+ this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(searchPaths);
30
+ }
31
+ /**
32
+ * Get service key for destination
33
+ * @param destination Destination name (e.g., "TRIAL")
34
+ * @returns ServiceKey object or null if not found
35
+ */
36
+ async getServiceKey(destination) {
37
+ return (0, serviceKeyLoader_1.loadServiceKey)(destination, this.searchPaths);
38
+ }
39
+ /**
40
+ * Get search paths (for error messages)
41
+ * @returns Array of search paths
42
+ */
43
+ getSearchPaths() {
44
+ return [...this.searchPaths];
45
+ }
46
+ }
47
+ exports.FileServiceKeyStore = FileServiceKeyStore;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * File-based implementation of SessionStore
3
+ *
4
+ * Reads/writes session data from/to {destination}.env files in search paths.
5
+ */
6
+ import { SessionStore } from './interfaces';
7
+ import { EnvConfig } from '../types';
8
+ /**
9
+ * File-based session store implementation
10
+ *
11
+ * Searches for {destination}.env files in configured search paths.
12
+ * Writes to first search path (highest priority).
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 FileSessionStore implements SessionStore {
19
+ private searchPaths;
20
+ /**
21
+ * Create a new FileSessionStore instance
22
+ * @param searchPaths Optional search paths for .env 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
+ * Load session configuration for destination
29
+ * @param destination Destination name (e.g., "TRIAL")
30
+ * @returns EnvConfig object or null if not found
31
+ */
32
+ loadSession(destination: string): Promise<EnvConfig | null>;
33
+ /**
34
+ * Save session configuration for destination
35
+ * @param destination Destination name (e.g., "TRIAL")
36
+ * @param config Session configuration to save
37
+ */
38
+ saveSession(destination: string, config: EnvConfig): Promise<void>;
39
+ /**
40
+ * Delete session for destination
41
+ * @param destination Destination name (e.g., "TRIAL")
42
+ */
43
+ deleteSession(destination: string): Promise<void>;
44
+ /**
45
+ * Get search paths (for error messages)
46
+ * @returns Array of search paths
47
+ */
48
+ getSearchPaths(): string[];
49
+ }
50
+ //# sourceMappingURL=FileSessionStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileSessionStore.d.ts","sourceRoot":"","sources":["../../src/stores/FileSessionStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAKrC;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,WAAW,CAAW;IAE9B;;;;;OAKG;gBACS,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAI3C;;;;OAIG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAIjE;;;;OAIG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxE;;;OAGG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvD;;;OAGG;IACH,cAAc,IAAI,MAAM,EAAE;CAG3B"}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * File-based implementation of SessionStore
4
+ *
5
+ * Reads/writes session data from/to {destination}.env files in search paths.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.FileSessionStore = void 0;
42
+ const envLoader_1 = require("../envLoader");
43
+ const tokenStorage_1 = require("../tokenStorage");
44
+ const pathResolver_1 = require("../pathResolver");
45
+ /**
46
+ * File-based session store implementation
47
+ *
48
+ * Searches for {destination}.env files in configured search paths.
49
+ * Writes to first search path (highest priority).
50
+ * Search paths priority:
51
+ * 1. Constructor parameter (highest)
52
+ * 2. AUTH_BROKER_PATH environment variable
53
+ * 3. Current working directory (lowest)
54
+ */
55
+ class FileSessionStore {
56
+ searchPaths;
57
+ /**
58
+ * Create a new FileSessionStore instance
59
+ * @param searchPaths Optional search paths for .env files.
60
+ * Can be a single path (string) or array of paths.
61
+ * If not provided, uses AUTH_BROKER_PATH env var or current working directory.
62
+ */
63
+ constructor(searchPaths) {
64
+ this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(searchPaths);
65
+ }
66
+ /**
67
+ * Load session configuration for destination
68
+ * @param destination Destination name (e.g., "TRIAL")
69
+ * @returns EnvConfig object or null if not found
70
+ */
71
+ async loadSession(destination) {
72
+ return (0, envLoader_1.loadEnvFile)(destination, this.searchPaths);
73
+ }
74
+ /**
75
+ * Save session configuration for destination
76
+ * @param destination Destination name (e.g., "TRIAL")
77
+ * @param config Session configuration to save
78
+ */
79
+ async saveSession(destination, config) {
80
+ // Save to first search path (highest priority)
81
+ const savePath = this.searchPaths[0];
82
+ // Convert EnvConfig to format expected by saveTokenToEnv
83
+ await (0, tokenStorage_1.saveTokenToEnv)(destination, savePath, {
84
+ sapUrl: config.sapUrl,
85
+ jwtToken: config.jwtToken,
86
+ refreshToken: config.refreshToken,
87
+ uaaUrl: config.uaaUrl,
88
+ uaaClientId: config.uaaClientId,
89
+ uaaClientSecret: config.uaaClientSecret,
90
+ sapClient: config.sapClient,
91
+ language: config.language,
92
+ });
93
+ }
94
+ /**
95
+ * Delete session for destination
96
+ * @param destination Destination name (e.g., "TRIAL")
97
+ */
98
+ async deleteSession(destination) {
99
+ // Find .env file in search paths
100
+ const fileName = `${destination}.env`;
101
+ const { findFileInPaths } = await Promise.resolve().then(() => __importStar(require('../pathResolver')));
102
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
103
+ const envFilePath = findFileInPaths(fileName, this.searchPaths);
104
+ if (envFilePath && fs.existsSync(envFilePath)) {
105
+ fs.unlinkSync(envFilePath);
106
+ }
107
+ }
108
+ /**
109
+ * Get search paths (for error messages)
110
+ * @returns Array of search paths
111
+ */
112
+ getSearchPaths() {
113
+ return [...this.searchPaths];
114
+ }
115
+ }
116
+ exports.FileSessionStore = FileSessionStore;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Storage implementations for AuthBroker
3
+ */
4
+ export { ServiceKeyStore, SessionStore } from './interfaces';
5
+ export { FileServiceKeyStore } from './FileServiceKeyStore';
6
+ export { FileSessionStore } from './FileSessionStore';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * Storage implementations for AuthBroker
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileSessionStore = exports.FileServiceKeyStore = void 0;
7
+ var FileServiceKeyStore_1 = require("./FileServiceKeyStore");
8
+ Object.defineProperty(exports, "FileServiceKeyStore", { enumerable: true, get: function () { return FileServiceKeyStore_1.FileServiceKeyStore; } });
9
+ var FileSessionStore_1 = require("./FileSessionStore");
10
+ Object.defineProperty(exports, "FileSessionStore", { enumerable: true, get: function () { return FileSessionStore_1.FileSessionStore; } });
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Storage interfaces for AuthBroker
3
+ *
4
+ * These interfaces allow consumers to provide custom storage implementations
5
+ * for service keys and session data (tokens, configuration).
6
+ */
7
+ import { ServiceKey, EnvConfig } from '../types';
8
+ /**
9
+ * Interface for storing and retrieving service keys
10
+ *
11
+ * Service keys contain UAA credentials and SAP URL for a destination.
12
+ * Default implementation: FileServiceKeyStore (reads from {destination}.json files)
13
+ */
14
+ export interface ServiceKeyStore {
15
+ /**
16
+ * Get service key for destination
17
+ * @param destination Destination name (e.g., "TRIAL")
18
+ * @returns ServiceKey object or null if not found
19
+ */
20
+ getServiceKey(destination: string): Promise<ServiceKey | null>;
21
+ }
22
+ /**
23
+ * Interface for storing and retrieving session data (tokens, configuration)
24
+ *
25
+ * Session data contains JWT tokens, refresh tokens, UAA config, and SAP URL.
26
+ * Default implementation: FileSessionStore (reads/writes {destination}.env files)
27
+ */
28
+ export interface SessionStore {
29
+ /**
30
+ * Load session configuration for destination
31
+ * @param destination Destination name (e.g., "TRIAL")
32
+ * @returns EnvConfig object or null if not found
33
+ */
34
+ loadSession(destination: string): Promise<EnvConfig | null>;
35
+ /**
36
+ * Save session configuration for destination
37
+ * @param destination Destination name (e.g., "TRIAL")
38
+ * @param config Session configuration to save
39
+ */
40
+ saveSession(destination: string, config: EnvConfig): Promise<void>;
41
+ /**
42
+ * Delete session for destination (optional)
43
+ * @param destination Destination name (e.g., "TRIAL")
44
+ */
45
+ deleteSession?(destination: string): Promise<void>;
46
+ }
47
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/stores/interfaces.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAChE;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAE5D;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnE;;;OAGG;IACH,aAAa,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Storage interfaces for AuthBroker
4
+ *
5
+ * These interfaces allow consumers to provide custom storage implementations
6
+ * for service keys and session data (tokens, configuration).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/auth-broker",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "JWT authentication broker for MCP ABAP ADT - manages tokens based on destination headers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",