@everworker/oneringai 0.4.2 → 0.4.4
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/README.md +132 -13
- package/dist/{IProvider-CNJqZItJ.d.cts → IProvider-B8sqUzJG.d.cts} +36 -6
- package/dist/{IProvider-B6hqVVq8.d.ts → IProvider-CxDUGl6n.d.ts} +36 -6
- package/dist/{ImageModel-B64HX3lN.d.cts → ImageModel-Ds5_6sf7.d.cts} +1 -1
- package/dist/{ImageModel-DU-y_WOb.d.ts → ImageModel-OWbA277F.d.ts} +1 -1
- package/dist/capabilities/agents/index.d.cts +2 -2
- package/dist/capabilities/agents/index.d.ts +2 -2
- package/dist/capabilities/images/index.cjs +251 -106
- package/dist/capabilities/images/index.cjs.map +1 -1
- package/dist/capabilities/images/index.d.cts +2 -2
- package/dist/capabilities/images/index.d.ts +2 -2
- package/dist/capabilities/images/index.js +251 -106
- package/dist/capabilities/images/index.js.map +1 -1
- package/dist/index-DmYrHH7d.d.cts +2556 -0
- package/dist/index-Dyl6pHfq.d.ts +2556 -0
- package/dist/index.cjs +4141 -444
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +825 -945
- package/dist/index.d.ts +825 -945
- package/dist/index.js +4107 -429
- package/dist/index.js.map +1 -1
- package/dist/shared/index.cjs +9 -0
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.js +9 -0
- package/dist/shared/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/index-9VOnAX17.d.ts +0 -1397
- package/dist/index-BMjyFNJQ.d.cts +0 -1397
|
@@ -119,6 +119,12 @@ var MemoryStorage = class {
|
|
|
119
119
|
size() {
|
|
120
120
|
return this.tokens.size;
|
|
121
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* List all storage keys (for account enumeration)
|
|
124
|
+
*/
|
|
125
|
+
async listKeys() {
|
|
126
|
+
return Array.from(this.tokens.keys());
|
|
127
|
+
}
|
|
122
128
|
};
|
|
123
129
|
|
|
124
130
|
// src/connectors/oauth/domain/TokenStore.ts
|
|
@@ -130,14 +136,23 @@ var TokenStore = class {
|
|
|
130
136
|
this.storage = storage || new MemoryStorage();
|
|
131
137
|
}
|
|
132
138
|
/**
|
|
133
|
-
* Get user-scoped storage key
|
|
134
|
-
*
|
|
135
|
-
*
|
|
139
|
+
* Get user-scoped (and optionally account-scoped) storage key
|
|
140
|
+
*
|
|
141
|
+
* Key format (backward compatible):
|
|
142
|
+
* - No userId, no accountId → baseKey
|
|
143
|
+
* - userId only → baseKey:userId
|
|
144
|
+
* - userId + accountId → baseKey:userId:accountId
|
|
145
|
+
* - accountId only → baseKey:default:accountId
|
|
136
146
|
*
|
|
137
147
|
* @param userId - User identifier (optional, defaults to single-user mode)
|
|
138
|
-
* @
|
|
148
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
149
|
+
* @returns Storage key scoped to user and account
|
|
139
150
|
*/
|
|
140
|
-
getScopedKey(userId) {
|
|
151
|
+
getScopedKey(userId, accountId) {
|
|
152
|
+
if (accountId) {
|
|
153
|
+
const userPart = userId && userId !== "default" ? userId : "default";
|
|
154
|
+
return `${this.baseStorageKey}:${userPart}:${accountId}`;
|
|
155
|
+
}
|
|
141
156
|
if (!userId || userId === "default") {
|
|
142
157
|
return this.baseStorageKey;
|
|
143
158
|
}
|
|
@@ -147,8 +162,9 @@ var TokenStore = class {
|
|
|
147
162
|
* Store token (encrypted by storage layer)
|
|
148
163
|
* @param tokenResponse - Token response from OAuth provider
|
|
149
164
|
* @param userId - Optional user identifier for multi-user support
|
|
165
|
+
* @param accountId - Optional account alias for multi-account support
|
|
150
166
|
*/
|
|
151
|
-
async storeToken(tokenResponse, userId) {
|
|
167
|
+
async storeToken(tokenResponse, userId, accountId) {
|
|
152
168
|
if (!tokenResponse.access_token) {
|
|
153
169
|
throw new Error("OAuth response missing required access_token field");
|
|
154
170
|
}
|
|
@@ -166,39 +182,46 @@ var TokenStore = class {
|
|
|
166
182
|
scope: tokenResponse.scope,
|
|
167
183
|
obtained_at: Date.now()
|
|
168
184
|
};
|
|
169
|
-
const key = this.getScopedKey(userId);
|
|
185
|
+
const key = this.getScopedKey(userId, accountId);
|
|
170
186
|
await this.storage.storeToken(key, token);
|
|
171
187
|
}
|
|
172
188
|
/**
|
|
173
189
|
* Get access token
|
|
174
190
|
* @param userId - Optional user identifier for multi-user support
|
|
191
|
+
* @param accountId - Optional account alias for multi-account support
|
|
175
192
|
*/
|
|
176
|
-
async getAccessToken(userId) {
|
|
177
|
-
const key = this.getScopedKey(userId);
|
|
193
|
+
async getAccessToken(userId, accountId) {
|
|
194
|
+
const key = this.getScopedKey(userId, accountId);
|
|
178
195
|
const token = await this.storage.getToken(key);
|
|
179
196
|
if (!token) {
|
|
180
|
-
|
|
197
|
+
const userLabel = userId ? `user: ${userId}` : "default user";
|
|
198
|
+
const accountLabel = accountId ? `, account: ${accountId}` : "";
|
|
199
|
+
throw new Error(`No token stored for ${userLabel}${accountLabel}`);
|
|
181
200
|
}
|
|
182
201
|
return token.access_token;
|
|
183
202
|
}
|
|
184
203
|
/**
|
|
185
204
|
* Get refresh token
|
|
186
205
|
* @param userId - Optional user identifier for multi-user support
|
|
206
|
+
* @param accountId - Optional account alias for multi-account support
|
|
187
207
|
*/
|
|
188
|
-
async getRefreshToken(userId) {
|
|
189
|
-
const key = this.getScopedKey(userId);
|
|
208
|
+
async getRefreshToken(userId, accountId) {
|
|
209
|
+
const key = this.getScopedKey(userId, accountId);
|
|
190
210
|
const token = await this.storage.getToken(key);
|
|
191
211
|
if (!token?.refresh_token) {
|
|
192
|
-
|
|
212
|
+
const userLabel = userId ? `user: ${userId}` : "default user";
|
|
213
|
+
const accountLabel = accountId ? `, account: ${accountId}` : "";
|
|
214
|
+
throw new Error(`No refresh token available for ${userLabel}${accountLabel}`);
|
|
193
215
|
}
|
|
194
216
|
return token.refresh_token;
|
|
195
217
|
}
|
|
196
218
|
/**
|
|
197
219
|
* Check if has refresh token
|
|
198
220
|
* @param userId - Optional user identifier for multi-user support
|
|
221
|
+
* @param accountId - Optional account alias for multi-account support
|
|
199
222
|
*/
|
|
200
|
-
async hasRefreshToken(userId) {
|
|
201
|
-
const key = this.getScopedKey(userId);
|
|
223
|
+
async hasRefreshToken(userId, accountId) {
|
|
224
|
+
const key = this.getScopedKey(userId, accountId);
|
|
202
225
|
const token = await this.storage.getToken(key);
|
|
203
226
|
return !!token?.refresh_token;
|
|
204
227
|
}
|
|
@@ -207,9 +230,10 @@ var TokenStore = class {
|
|
|
207
230
|
*
|
|
208
231
|
* @param bufferSeconds - Refresh this many seconds before expiry (default: 300 = 5 min)
|
|
209
232
|
* @param userId - Optional user identifier for multi-user support
|
|
233
|
+
* @param accountId - Optional account alias for multi-account support
|
|
210
234
|
*/
|
|
211
|
-
async isValid(bufferSeconds = 300, userId) {
|
|
212
|
-
const key = this.getScopedKey(userId);
|
|
235
|
+
async isValid(bufferSeconds = 300, userId, accountId) {
|
|
236
|
+
const key = this.getScopedKey(userId, accountId);
|
|
213
237
|
const token = await this.storage.getToken(key);
|
|
214
238
|
if (!token) {
|
|
215
239
|
return false;
|
|
@@ -221,19 +245,46 @@ var TokenStore = class {
|
|
|
221
245
|
/**
|
|
222
246
|
* Clear stored token
|
|
223
247
|
* @param userId - Optional user identifier for multi-user support
|
|
248
|
+
* @param accountId - Optional account alias for multi-account support
|
|
224
249
|
*/
|
|
225
|
-
async clear(userId) {
|
|
226
|
-
const key = this.getScopedKey(userId);
|
|
250
|
+
async clear(userId, accountId) {
|
|
251
|
+
const key = this.getScopedKey(userId, accountId);
|
|
227
252
|
await this.storage.deleteToken(key);
|
|
228
253
|
}
|
|
229
254
|
/**
|
|
230
255
|
* Get full token info
|
|
231
256
|
* @param userId - Optional user identifier for multi-user support
|
|
257
|
+
* @param accountId - Optional account alias for multi-account support
|
|
232
258
|
*/
|
|
233
|
-
async getTokenInfo(userId) {
|
|
234
|
-
const key = this.getScopedKey(userId);
|
|
259
|
+
async getTokenInfo(userId, accountId) {
|
|
260
|
+
const key = this.getScopedKey(userId, accountId);
|
|
235
261
|
return this.storage.getToken(key);
|
|
236
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* List account aliases for a user on this connector.
|
|
265
|
+
* Returns account IDs that have stored tokens.
|
|
266
|
+
*
|
|
267
|
+
* @param userId - Optional user identifier
|
|
268
|
+
* @returns Array of account aliases (e.g., ['work', 'personal'])
|
|
269
|
+
*/
|
|
270
|
+
async listAccounts(userId) {
|
|
271
|
+
if (!this.storage.listKeys) {
|
|
272
|
+
return [];
|
|
273
|
+
}
|
|
274
|
+
const allKeys = await this.storage.listKeys();
|
|
275
|
+
const userPart = userId && userId !== "default" ? userId : "default";
|
|
276
|
+
const prefix = `${this.baseStorageKey}:${userPart}:`;
|
|
277
|
+
const accounts = [];
|
|
278
|
+
for (const key of allKeys) {
|
|
279
|
+
if (key.startsWith(prefix)) {
|
|
280
|
+
const accountId = key.slice(prefix.length);
|
|
281
|
+
if (accountId && !accountId.includes(":")) {
|
|
282
|
+
accounts.push(accountId);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return accounts;
|
|
287
|
+
}
|
|
237
288
|
};
|
|
238
289
|
function generatePKCE() {
|
|
239
290
|
const codeVerifier = base64URLEncode(crypto__namespace.randomBytes(32));
|
|
@@ -259,20 +310,28 @@ var AuthCodePKCEFlow = class {
|
|
|
259
310
|
this.tokenStore = new TokenStore(storageKey, config.storage);
|
|
260
311
|
}
|
|
261
312
|
tokenStore;
|
|
262
|
-
// Store PKCE data per user with timestamps for cleanup
|
|
313
|
+
// Store PKCE data per user+account with timestamps for cleanup
|
|
263
314
|
codeVerifiers = /* @__PURE__ */ new Map();
|
|
264
315
|
states = /* @__PURE__ */ new Map();
|
|
265
|
-
// Store refresh locks per user to prevent concurrent refresh
|
|
316
|
+
// Store refresh locks per user+account to prevent concurrent refresh
|
|
266
317
|
refreshLocks = /* @__PURE__ */ new Map();
|
|
267
318
|
// PKCE data TTL: 15 minutes (auth flows should complete within this time)
|
|
268
319
|
PKCE_TTL = 15 * 60 * 1e3;
|
|
320
|
+
/**
|
|
321
|
+
* Build a map key from userId and accountId for internal PKCE/state/lock maps.
|
|
322
|
+
*/
|
|
323
|
+
getMapKey(userId, accountId) {
|
|
324
|
+
const userPart = userId || "default";
|
|
325
|
+
return accountId ? `${userPart}:${accountId}` : userPart;
|
|
326
|
+
}
|
|
269
327
|
/**
|
|
270
328
|
* Generate authorization URL for user to visit
|
|
271
329
|
* Opens browser or redirects user to this URL
|
|
272
330
|
*
|
|
273
331
|
* @param userId - User identifier for multi-user support (optional)
|
|
332
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
274
333
|
*/
|
|
275
|
-
async getAuthorizationUrl(userId) {
|
|
334
|
+
async getAuthorizationUrl(userId, accountId) {
|
|
276
335
|
if (!this.config.authorizationUrl) {
|
|
277
336
|
throw new Error("authorizationUrl is required for authorization_code flow");
|
|
278
337
|
}
|
|
@@ -280,11 +339,11 @@ var AuthCodePKCEFlow = class {
|
|
|
280
339
|
throw new Error("redirectUri is required for authorization_code flow");
|
|
281
340
|
}
|
|
282
341
|
this.cleanupExpiredPKCE();
|
|
283
|
-
const
|
|
342
|
+
const mapKey = this.getMapKey(userId, accountId);
|
|
284
343
|
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
285
|
-
this.codeVerifiers.set(
|
|
344
|
+
this.codeVerifiers.set(mapKey, { verifier: codeVerifier, timestamp: Date.now() });
|
|
286
345
|
const state = generateState();
|
|
287
|
-
this.states.set(
|
|
346
|
+
this.states.set(mapKey, { state, timestamp: Date.now() });
|
|
288
347
|
const params = new URLSearchParams({
|
|
289
348
|
response_type: "code",
|
|
290
349
|
client_id: this.config.clientId,
|
|
@@ -298,33 +357,48 @@ var AuthCodePKCEFlow = class {
|
|
|
298
357
|
params.append("code_challenge", codeChallenge);
|
|
299
358
|
params.append("code_challenge_method", "S256");
|
|
300
359
|
}
|
|
301
|
-
|
|
302
|
-
|
|
360
|
+
let stateWithMetadata = state;
|
|
361
|
+
if (userId || accountId) {
|
|
362
|
+
stateWithMetadata = `${state}::${userId || ""}`;
|
|
363
|
+
if (accountId) {
|
|
364
|
+
stateWithMetadata += `::${accountId}`;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
params.set("state", stateWithMetadata);
|
|
303
368
|
return `${this.config.authorizationUrl}?${params.toString()}`;
|
|
304
369
|
}
|
|
305
370
|
/**
|
|
306
371
|
* Exchange authorization code for access token
|
|
307
372
|
*
|
|
308
373
|
* @param code - Authorization code from callback
|
|
309
|
-
* @param state - State parameter from callback (for CSRF verification, may include userId)
|
|
374
|
+
* @param state - State parameter from callback (for CSRF verification, may include userId/accountId)
|
|
310
375
|
* @param userId - User identifier (optional, can be extracted from state)
|
|
376
|
+
* @param accountId - Account alias (optional, can be extracted from state)
|
|
311
377
|
*/
|
|
312
|
-
async exchangeCode(code, state, userId) {
|
|
378
|
+
async exchangeCode(code, state, userId, accountId) {
|
|
313
379
|
let actualState = state;
|
|
314
380
|
let actualUserId = userId;
|
|
381
|
+
let actualAccountId = accountId;
|
|
315
382
|
if (state.includes("::")) {
|
|
316
383
|
const parts = state.split("::");
|
|
317
384
|
actualState = parts[0];
|
|
318
|
-
actualUserId
|
|
385
|
+
if (!actualUserId && parts[1]) {
|
|
386
|
+
actualUserId = parts[1];
|
|
387
|
+
}
|
|
388
|
+
if (!actualAccountId && parts[2]) {
|
|
389
|
+
actualAccountId = parts[2];
|
|
390
|
+
}
|
|
319
391
|
}
|
|
320
|
-
const
|
|
321
|
-
const stateData = this.states.get(
|
|
392
|
+
const mapKey = this.getMapKey(actualUserId, actualAccountId);
|
|
393
|
+
const stateData = this.states.get(mapKey);
|
|
322
394
|
if (!stateData) {
|
|
323
|
-
|
|
395
|
+
const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
|
|
396
|
+
throw new Error(`No PKCE state found for ${label}. Authorization flow may have expired (15 min TTL).`);
|
|
324
397
|
}
|
|
325
398
|
const expectedState = stateData.state;
|
|
326
399
|
if (actualState !== expectedState) {
|
|
327
|
-
|
|
400
|
+
const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
|
|
401
|
+
throw new Error(`State mismatch for ${label} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
|
|
328
402
|
}
|
|
329
403
|
if (!this.config.redirectUri) {
|
|
330
404
|
throw new Error("redirectUri is required");
|
|
@@ -338,7 +412,7 @@ var AuthCodePKCEFlow = class {
|
|
|
338
412
|
if (this.config.clientSecret) {
|
|
339
413
|
params.append("client_secret", this.config.clientSecret);
|
|
340
414
|
}
|
|
341
|
-
const verifierData = this.codeVerifiers.get(
|
|
415
|
+
const verifierData = this.codeVerifiers.get(mapKey);
|
|
342
416
|
if (this.config.usePKCE !== false && verifierData) {
|
|
343
417
|
params.append("code_verifier", verifierData.verifier);
|
|
344
418
|
}
|
|
@@ -372,39 +446,43 @@ var AuthCodePKCEFlow = class {
|
|
|
372
446
|
throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${error}`);
|
|
373
447
|
}
|
|
374
448
|
const data = await response.json();
|
|
375
|
-
await this.tokenStore.storeToken(data, actualUserId);
|
|
376
|
-
this.codeVerifiers.delete(
|
|
377
|
-
this.states.delete(
|
|
449
|
+
await this.tokenStore.storeToken(data, actualUserId, actualAccountId);
|
|
450
|
+
this.codeVerifiers.delete(mapKey);
|
|
451
|
+
this.states.delete(mapKey);
|
|
378
452
|
}
|
|
379
453
|
/**
|
|
380
454
|
* Get valid token (auto-refreshes if needed)
|
|
381
455
|
* @param userId - User identifier for multi-user support
|
|
456
|
+
* @param accountId - Account alias for multi-account support
|
|
382
457
|
*/
|
|
383
|
-
async getToken(userId) {
|
|
384
|
-
const
|
|
385
|
-
if (this.refreshLocks.has(
|
|
386
|
-
return this.refreshLocks.get(
|
|
458
|
+
async getToken(userId, accountId) {
|
|
459
|
+
const mapKey = this.getMapKey(userId, accountId);
|
|
460
|
+
if (this.refreshLocks.has(mapKey)) {
|
|
461
|
+
return this.refreshLocks.get(mapKey);
|
|
387
462
|
}
|
|
388
|
-
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId)) {
|
|
389
|
-
return this.tokenStore.getAccessToken(userId);
|
|
463
|
+
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
|
|
464
|
+
return this.tokenStore.getAccessToken(userId, accountId);
|
|
390
465
|
}
|
|
391
|
-
if (await this.tokenStore.hasRefreshToken(userId)) {
|
|
392
|
-
const refreshPromise = this.refreshToken(userId);
|
|
393
|
-
this.refreshLocks.set(
|
|
466
|
+
if (await this.tokenStore.hasRefreshToken(userId, accountId)) {
|
|
467
|
+
const refreshPromise = this.refreshToken(userId, accountId);
|
|
468
|
+
this.refreshLocks.set(mapKey, refreshPromise);
|
|
394
469
|
try {
|
|
395
470
|
return await refreshPromise;
|
|
396
471
|
} finally {
|
|
397
|
-
this.refreshLocks.delete(
|
|
472
|
+
this.refreshLocks.delete(mapKey);
|
|
398
473
|
}
|
|
399
474
|
}
|
|
400
|
-
|
|
475
|
+
const userLabel = userId ? `user: ${userId}` : "default user";
|
|
476
|
+
const accountLabel = accountId ? `, account: ${accountId}` : "";
|
|
477
|
+
throw new Error(`No valid token available for ${userLabel}${accountLabel}. User needs to authorize (call startAuthFlow).`);
|
|
401
478
|
}
|
|
402
479
|
/**
|
|
403
480
|
* Refresh access token using refresh token
|
|
404
481
|
* @param userId - User identifier for multi-user support
|
|
482
|
+
* @param accountId - Account alias for multi-account support
|
|
405
483
|
*/
|
|
406
|
-
async refreshToken(userId) {
|
|
407
|
-
const refreshToken = await this.tokenStore.getRefreshToken(userId);
|
|
484
|
+
async refreshToken(userId, accountId) {
|
|
485
|
+
const refreshToken = await this.tokenStore.getRefreshToken(userId, accountId);
|
|
408
486
|
const params = new URLSearchParams({
|
|
409
487
|
grant_type: "refresh_token",
|
|
410
488
|
refresh_token: refreshToken,
|
|
@@ -443,28 +521,30 @@ var AuthCodePKCEFlow = class {
|
|
|
443
521
|
throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${error}`);
|
|
444
522
|
}
|
|
445
523
|
const data = await response.json();
|
|
446
|
-
await this.tokenStore.storeToken(data, userId);
|
|
524
|
+
await this.tokenStore.storeToken(data, userId, accountId);
|
|
447
525
|
return data.access_token;
|
|
448
526
|
}
|
|
449
527
|
/**
|
|
450
528
|
* Check if token is valid
|
|
451
529
|
* @param userId - User identifier for multi-user support
|
|
530
|
+
* @param accountId - Account alias for multi-account support
|
|
452
531
|
*/
|
|
453
|
-
async isTokenValid(userId) {
|
|
454
|
-
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId);
|
|
532
|
+
async isTokenValid(userId, accountId) {
|
|
533
|
+
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
|
|
455
534
|
}
|
|
456
535
|
/**
|
|
457
536
|
* Revoke token (if supported by provider)
|
|
458
537
|
* @param revocationUrl - Optional revocation endpoint
|
|
459
538
|
* @param userId - User identifier for multi-user support
|
|
539
|
+
* @param accountId - Account alias for multi-account support
|
|
460
540
|
*/
|
|
461
|
-
async revokeToken(revocationUrl, userId) {
|
|
541
|
+
async revokeToken(revocationUrl, userId, accountId) {
|
|
462
542
|
if (!revocationUrl) {
|
|
463
|
-
await this.tokenStore.clear(userId);
|
|
543
|
+
await this.tokenStore.clear(userId, accountId);
|
|
464
544
|
return;
|
|
465
545
|
}
|
|
466
546
|
try {
|
|
467
|
-
const token = await this.tokenStore.getAccessToken(userId);
|
|
547
|
+
const token = await this.tokenStore.getAccessToken(userId, accountId);
|
|
468
548
|
await fetch(revocationUrl, {
|
|
469
549
|
method: "POST",
|
|
470
550
|
headers: {
|
|
@@ -476,9 +556,16 @@ var AuthCodePKCEFlow = class {
|
|
|
476
556
|
})
|
|
477
557
|
});
|
|
478
558
|
} finally {
|
|
479
|
-
await this.tokenStore.clear(userId);
|
|
559
|
+
await this.tokenStore.clear(userId, accountId);
|
|
480
560
|
}
|
|
481
561
|
}
|
|
562
|
+
/**
|
|
563
|
+
* List account aliases for a user.
|
|
564
|
+
* @param userId - User identifier (optional)
|
|
565
|
+
*/
|
|
566
|
+
async listAccounts(userId) {
|
|
567
|
+
return this.tokenStore.listAccounts(userId);
|
|
568
|
+
}
|
|
482
569
|
/**
|
|
483
570
|
* Clean up expired PKCE data to prevent memory leaks
|
|
484
571
|
* Removes verifiers and states older than PKCE_TTL (15 minutes)
|
|
@@ -508,17 +595,19 @@ var ClientCredentialsFlow = class {
|
|
|
508
595
|
tokenStore;
|
|
509
596
|
/**
|
|
510
597
|
* Get token using client credentials
|
|
598
|
+
* @param userId - User identifier for multi-user support (optional, rarely used for client_credentials)
|
|
599
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
511
600
|
*/
|
|
512
|
-
async getToken() {
|
|
513
|
-
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
|
|
514
|
-
return this.tokenStore.getAccessToken();
|
|
601
|
+
async getToken(userId, accountId) {
|
|
602
|
+
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
|
|
603
|
+
return this.tokenStore.getAccessToken(userId, accountId);
|
|
515
604
|
}
|
|
516
|
-
return this.requestToken();
|
|
605
|
+
return this.requestToken(userId, accountId);
|
|
517
606
|
}
|
|
518
607
|
/**
|
|
519
608
|
* Request a new token from the authorization server
|
|
520
609
|
*/
|
|
521
|
-
async requestToken() {
|
|
610
|
+
async requestToken(userId, accountId) {
|
|
522
611
|
const auth = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString(
|
|
523
612
|
"base64"
|
|
524
613
|
);
|
|
@@ -541,22 +630,26 @@ var ClientCredentialsFlow = class {
|
|
|
541
630
|
throw new Error(`Token request failed: ${response.status} ${response.statusText} - ${error}`);
|
|
542
631
|
}
|
|
543
632
|
const data = await response.json();
|
|
544
|
-
await this.tokenStore.storeToken(data);
|
|
633
|
+
await this.tokenStore.storeToken(data, userId, accountId);
|
|
545
634
|
return data.access_token;
|
|
546
635
|
}
|
|
547
636
|
/**
|
|
548
637
|
* Refresh token (client credentials don't use refresh tokens)
|
|
549
638
|
* Just requests a new token
|
|
639
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
640
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
550
641
|
*/
|
|
551
|
-
async refreshToken() {
|
|
552
|
-
await this.tokenStore.clear();
|
|
553
|
-
return this.requestToken();
|
|
642
|
+
async refreshToken(userId, accountId) {
|
|
643
|
+
await this.tokenStore.clear(userId, accountId);
|
|
644
|
+
return this.requestToken(userId, accountId);
|
|
554
645
|
}
|
|
555
646
|
/**
|
|
556
647
|
* Check if token is valid
|
|
648
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
649
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
557
650
|
*/
|
|
558
|
-
async isTokenValid() {
|
|
559
|
-
return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
|
|
651
|
+
async isTokenValid(userId, accountId) {
|
|
652
|
+
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
|
|
560
653
|
}
|
|
561
654
|
};
|
|
562
655
|
var JWTBearerFlow = class {
|
|
@@ -592,17 +685,19 @@ var JWTBearerFlow = class {
|
|
|
592
685
|
}
|
|
593
686
|
/**
|
|
594
687
|
* Get token using JWT Bearer assertion
|
|
688
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
689
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
595
690
|
*/
|
|
596
|
-
async getToken() {
|
|
597
|
-
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
|
|
598
|
-
return this.tokenStore.getAccessToken();
|
|
691
|
+
async getToken(userId, accountId) {
|
|
692
|
+
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
|
|
693
|
+
return this.tokenStore.getAccessToken(userId, accountId);
|
|
599
694
|
}
|
|
600
|
-
return this.requestToken();
|
|
695
|
+
return this.requestToken(userId, accountId);
|
|
601
696
|
}
|
|
602
697
|
/**
|
|
603
698
|
* Request token using JWT assertion
|
|
604
699
|
*/
|
|
605
|
-
async requestToken() {
|
|
700
|
+
async requestToken(userId, accountId) {
|
|
606
701
|
const assertion = await this.generateJWT();
|
|
607
702
|
const params = new URLSearchParams({
|
|
608
703
|
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
@@ -620,21 +715,25 @@ var JWTBearerFlow = class {
|
|
|
620
715
|
throw new Error(`JWT Bearer token request failed: ${response.status} ${response.statusText} - ${error}`);
|
|
621
716
|
}
|
|
622
717
|
const data = await response.json();
|
|
623
|
-
await this.tokenStore.storeToken(data);
|
|
718
|
+
await this.tokenStore.storeToken(data, userId, accountId);
|
|
624
719
|
return data.access_token;
|
|
625
720
|
}
|
|
626
721
|
/**
|
|
627
722
|
* Refresh token (generate new JWT and request new token)
|
|
723
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
724
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
628
725
|
*/
|
|
629
|
-
async refreshToken() {
|
|
630
|
-
await this.tokenStore.clear();
|
|
631
|
-
return this.requestToken();
|
|
726
|
+
async refreshToken(userId, accountId) {
|
|
727
|
+
await this.tokenStore.clear(userId, accountId);
|
|
728
|
+
return this.requestToken(userId, accountId);
|
|
632
729
|
}
|
|
633
730
|
/**
|
|
634
731
|
* Check if token is valid
|
|
732
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
733
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
635
734
|
*/
|
|
636
|
-
async isTokenValid() {
|
|
637
|
-
return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
|
|
735
|
+
async isTokenValid(userId, accountId) {
|
|
736
|
+
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
|
|
638
737
|
}
|
|
639
738
|
};
|
|
640
739
|
|
|
@@ -700,25 +799,28 @@ var OAuthManager = class {
|
|
|
700
799
|
* Automatically refreshes if expired
|
|
701
800
|
*
|
|
702
801
|
* @param userId - User identifier for multi-user support (optional)
|
|
802
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
703
803
|
*/
|
|
704
|
-
async getToken(userId) {
|
|
705
|
-
return this.flow.getToken(userId);
|
|
804
|
+
async getToken(userId, accountId) {
|
|
805
|
+
return this.flow.getToken(userId, accountId);
|
|
706
806
|
}
|
|
707
807
|
/**
|
|
708
808
|
* Force refresh the token
|
|
709
809
|
*
|
|
710
810
|
* @param userId - User identifier for multi-user support (optional)
|
|
811
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
711
812
|
*/
|
|
712
|
-
async refreshToken(userId) {
|
|
713
|
-
return this.flow.refreshToken(userId);
|
|
813
|
+
async refreshToken(userId, accountId) {
|
|
814
|
+
return this.flow.refreshToken(userId, accountId);
|
|
714
815
|
}
|
|
715
816
|
/**
|
|
716
817
|
* Check if current token is valid
|
|
717
818
|
*
|
|
718
819
|
* @param userId - User identifier for multi-user support (optional)
|
|
820
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
719
821
|
*/
|
|
720
|
-
async isTokenValid(userId) {
|
|
721
|
-
return this.flow.isTokenValid(userId);
|
|
822
|
+
async isTokenValid(userId, accountId) {
|
|
823
|
+
return this.flow.isTokenValid(userId, accountId);
|
|
722
824
|
}
|
|
723
825
|
// ==================== Authorization Code Flow Methods ====================
|
|
724
826
|
/**
|
|
@@ -726,13 +828,14 @@ var OAuthManager = class {
|
|
|
726
828
|
* Returns URL for user to visit
|
|
727
829
|
*
|
|
728
830
|
* @param userId - User identifier for multi-user support (optional)
|
|
831
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
729
832
|
* @returns Authorization URL for the user to visit
|
|
730
833
|
*/
|
|
731
|
-
async startAuthFlow(userId) {
|
|
834
|
+
async startAuthFlow(userId, accountId) {
|
|
732
835
|
if (!(this.flow instanceof AuthCodePKCEFlow)) {
|
|
733
836
|
throw new Error("startAuthFlow() is only available for authorization_code flow");
|
|
734
837
|
}
|
|
735
|
-
return this.flow.getAuthorizationUrl(userId);
|
|
838
|
+
return this.flow.getAuthorizationUrl(userId, accountId);
|
|
736
839
|
}
|
|
737
840
|
/**
|
|
738
841
|
* Handle OAuth callback (Authorization Code only)
|
|
@@ -740,8 +843,9 @@ var OAuthManager = class {
|
|
|
740
843
|
*
|
|
741
844
|
* @param callbackUrl - Full callback URL with code and state parameters
|
|
742
845
|
* @param userId - Optional user identifier (can be extracted from state if embedded)
|
|
846
|
+
* @param accountId - Optional account alias (can be extracted from state if embedded)
|
|
743
847
|
*/
|
|
744
|
-
async handleCallback(callbackUrl, userId) {
|
|
848
|
+
async handleCallback(callbackUrl, userId, accountId) {
|
|
745
849
|
if (!(this.flow instanceof AuthCodePKCEFlow)) {
|
|
746
850
|
throw new Error("handleCallback() is only available for authorization_code flow");
|
|
747
851
|
}
|
|
@@ -754,21 +858,34 @@ var OAuthManager = class {
|
|
|
754
858
|
if (!state) {
|
|
755
859
|
throw new Error("Missing state parameter in callback URL");
|
|
756
860
|
}
|
|
757
|
-
await this.flow.exchangeCode(code, state, userId);
|
|
861
|
+
await this.flow.exchangeCode(code, state, userId, accountId);
|
|
758
862
|
}
|
|
759
863
|
/**
|
|
760
864
|
* Revoke token (if supported by provider)
|
|
761
865
|
*
|
|
762
866
|
* @param revocationUrl - Optional revocation endpoint URL
|
|
763
867
|
* @param userId - User identifier for multi-user support (optional)
|
|
868
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
764
869
|
*/
|
|
765
|
-
async revokeToken(revocationUrl, userId) {
|
|
870
|
+
async revokeToken(revocationUrl, userId, accountId) {
|
|
766
871
|
if (this.flow instanceof AuthCodePKCEFlow) {
|
|
767
|
-
await this.flow.revokeToken(revocationUrl, userId);
|
|
872
|
+
await this.flow.revokeToken(revocationUrl, userId, accountId);
|
|
768
873
|
} else {
|
|
769
874
|
throw new Error("Token revocation not implemented for this flow");
|
|
770
875
|
}
|
|
771
876
|
}
|
|
877
|
+
/**
|
|
878
|
+
* List account aliases for a user (Authorization Code only)
|
|
879
|
+
*
|
|
880
|
+
* @param userId - User identifier (optional)
|
|
881
|
+
* @returns Array of account aliases (e.g., ['work', 'personal'])
|
|
882
|
+
*/
|
|
883
|
+
async listAccounts(userId) {
|
|
884
|
+
if (this.flow instanceof AuthCodePKCEFlow) {
|
|
885
|
+
return this.flow.listAccounts(userId);
|
|
886
|
+
}
|
|
887
|
+
return [];
|
|
888
|
+
}
|
|
772
889
|
// ==================== Validation ====================
|
|
773
890
|
validateConfig(config) {
|
|
774
891
|
if (!config.flow) {
|
|
@@ -1884,46 +2001,59 @@ var Connector = class _Connector {
|
|
|
1884
2001
|
/**
|
|
1885
2002
|
* Get the current access token (for OAuth, JWT, or API key)
|
|
1886
2003
|
* Handles automatic refresh if needed
|
|
2004
|
+
*
|
|
2005
|
+
* @param userId - Optional user identifier for multi-user support
|
|
2006
|
+
* @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
|
|
1887
2007
|
*/
|
|
1888
|
-
async getToken(userId) {
|
|
2008
|
+
async getToken(userId, accountId) {
|
|
1889
2009
|
if (this.config.auth.type === "api_key") {
|
|
1890
2010
|
return this.config.auth.apiKey;
|
|
1891
2011
|
}
|
|
1892
2012
|
if (!this.oauthManager) {
|
|
1893
2013
|
throw new Error(`OAuth manager not initialized for connector '${this.name}'`);
|
|
1894
2014
|
}
|
|
1895
|
-
return this.oauthManager.getToken(userId);
|
|
2015
|
+
return this.oauthManager.getToken(userId, accountId);
|
|
1896
2016
|
}
|
|
1897
2017
|
/**
|
|
1898
2018
|
* Start OAuth authorization flow
|
|
1899
2019
|
* Returns the URL to redirect the user to
|
|
2020
|
+
*
|
|
2021
|
+
* @param userId - Optional user identifier for multi-user support
|
|
2022
|
+
* @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
|
|
1900
2023
|
*/
|
|
1901
|
-
async startAuth(userId) {
|
|
2024
|
+
async startAuth(userId, accountId) {
|
|
1902
2025
|
if (!this.oauthManager) {
|
|
1903
2026
|
throw new Error(`Connector '${this.name}' is not an OAuth connector`);
|
|
1904
2027
|
}
|
|
1905
|
-
return this.oauthManager.startAuthFlow(userId);
|
|
2028
|
+
return this.oauthManager.startAuthFlow(userId, accountId);
|
|
1906
2029
|
}
|
|
1907
2030
|
/**
|
|
1908
2031
|
* Handle OAuth callback
|
|
1909
2032
|
* Call this after user is redirected back from OAuth provider
|
|
2033
|
+
*
|
|
2034
|
+
* @param callbackUrl - Full callback URL with code and state parameters
|
|
2035
|
+
* @param userId - Optional user identifier (can be extracted from state if embedded)
|
|
2036
|
+
* @param accountId - Optional account alias (can be extracted from state if embedded)
|
|
1910
2037
|
*/
|
|
1911
|
-
async handleCallback(callbackUrl, userId) {
|
|
2038
|
+
async handleCallback(callbackUrl, userId, accountId) {
|
|
1912
2039
|
if (!this.oauthManager) {
|
|
1913
2040
|
throw new Error(`Connector '${this.name}' is not an OAuth connector`);
|
|
1914
2041
|
}
|
|
1915
|
-
await this.oauthManager.handleCallback(callbackUrl, userId);
|
|
2042
|
+
await this.oauthManager.handleCallback(callbackUrl, userId, accountId);
|
|
1916
2043
|
}
|
|
1917
2044
|
/**
|
|
1918
2045
|
* Check if the connector has a valid token
|
|
2046
|
+
*
|
|
2047
|
+
* @param userId - Optional user identifier for multi-user support
|
|
2048
|
+
* @param accountId - Optional account alias for multi-account support
|
|
1919
2049
|
*/
|
|
1920
|
-
async hasValidToken(userId) {
|
|
2050
|
+
async hasValidToken(userId, accountId) {
|
|
1921
2051
|
try {
|
|
1922
2052
|
if (this.config.auth.type === "api_key") {
|
|
1923
2053
|
return true;
|
|
1924
2054
|
}
|
|
1925
2055
|
if (this.oauthManager) {
|
|
1926
|
-
const token = await this.oauthManager.getToken(userId);
|
|
2056
|
+
const token = await this.oauthManager.getToken(userId, accountId);
|
|
1927
2057
|
return !!token;
|
|
1928
2058
|
}
|
|
1929
2059
|
return false;
|
|
@@ -1931,6 +2061,19 @@ var Connector = class _Connector {
|
|
|
1931
2061
|
return false;
|
|
1932
2062
|
}
|
|
1933
2063
|
}
|
|
2064
|
+
/**
|
|
2065
|
+
* List account aliases for a user on this connector.
|
|
2066
|
+
* Only applicable for OAuth connectors with multi-account support.
|
|
2067
|
+
*
|
|
2068
|
+
* @param userId - Optional user identifier
|
|
2069
|
+
* @returns Array of account aliases (e.g., ['work', 'personal'])
|
|
2070
|
+
*/
|
|
2071
|
+
async listAccounts(userId) {
|
|
2072
|
+
if (!this.oauthManager) {
|
|
2073
|
+
return [];
|
|
2074
|
+
}
|
|
2075
|
+
return this.oauthManager.listAccounts(userId);
|
|
2076
|
+
}
|
|
1934
2077
|
/**
|
|
1935
2078
|
* Get vendor-specific options from config
|
|
1936
2079
|
*/
|
|
@@ -1974,9 +2117,10 @@ var Connector = class _Connector {
|
|
|
1974
2117
|
* @param endpoint - API endpoint (relative to baseURL) or full URL
|
|
1975
2118
|
* @param options - Fetch options with connector-specific settings
|
|
1976
2119
|
* @param userId - Optional user ID for multi-user OAuth
|
|
2120
|
+
* @param accountId - Optional account alias for multi-account OAuth
|
|
1977
2121
|
* @returns Fetch Response
|
|
1978
2122
|
*/
|
|
1979
|
-
async fetch(endpoint, options, userId) {
|
|
2123
|
+
async fetch(endpoint, options, userId, accountId) {
|
|
1980
2124
|
if (this.disposed) {
|
|
1981
2125
|
throw new Error(`Connector '${this.name}' has been disposed`);
|
|
1982
2126
|
}
|
|
@@ -1995,7 +2139,7 @@ var Connector = class _Connector {
|
|
|
1995
2139
|
this.logRequest(url, options);
|
|
1996
2140
|
}
|
|
1997
2141
|
const doFetch = async () => {
|
|
1998
|
-
const token = await this.getToken(userId);
|
|
2142
|
+
const token = await this.getToken(userId, accountId);
|
|
1999
2143
|
const auth = this.config.auth;
|
|
2000
2144
|
let headerName = "Authorization";
|
|
2001
2145
|
let headerValue = `Bearer ${token}`;
|
|
@@ -2107,10 +2251,11 @@ var Connector = class _Connector {
|
|
|
2107
2251
|
* @param endpoint - API endpoint (relative to baseURL) or full URL
|
|
2108
2252
|
* @param options - Fetch options with connector-specific settings
|
|
2109
2253
|
* @param userId - Optional user ID for multi-user OAuth
|
|
2254
|
+
* @param accountId - Optional account alias for multi-account OAuth
|
|
2110
2255
|
* @returns Parsed JSON response
|
|
2111
2256
|
*/
|
|
2112
|
-
async fetchJSON(endpoint, options, userId) {
|
|
2113
|
-
const response = await this.fetch(endpoint, options, userId);
|
|
2257
|
+
async fetchJSON(endpoint, options, userId, accountId) {
|
|
2258
|
+
const response = await this.fetch(endpoint, options, userId, accountId);
|
|
2114
2259
|
const text = await response.text();
|
|
2115
2260
|
let data;
|
|
2116
2261
|
try {
|