@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.
@@ -92,6 +92,12 @@ var MemoryStorage = class {
92
92
  size() {
93
93
  return this.tokens.size;
94
94
  }
95
+ /**
96
+ * List all storage keys (for account enumeration)
97
+ */
98
+ async listKeys() {
99
+ return Array.from(this.tokens.keys());
100
+ }
95
101
  };
96
102
 
97
103
  // src/connectors/oauth/domain/TokenStore.ts
@@ -103,14 +109,23 @@ var TokenStore = class {
103
109
  this.storage = storage || new MemoryStorage();
104
110
  }
105
111
  /**
106
- * Get user-scoped storage key
107
- * For multi-user support, keys are scoped per user: "provider:userId"
108
- * For single-user (backward compatible), userId is omitted or "default"
112
+ * Get user-scoped (and optionally account-scoped) storage key
113
+ *
114
+ * Key format (backward compatible):
115
+ * - No userId, no accountId → baseKey
116
+ * - userId only → baseKey:userId
117
+ * - userId + accountId → baseKey:userId:accountId
118
+ * - accountId only → baseKey:default:accountId
109
119
  *
110
120
  * @param userId - User identifier (optional, defaults to single-user mode)
111
- * @returns Storage key scoped to user
121
+ * @param accountId - Account alias for multi-account support (optional)
122
+ * @returns Storage key scoped to user and account
112
123
  */
113
- getScopedKey(userId) {
124
+ getScopedKey(userId, accountId) {
125
+ if (accountId) {
126
+ const userPart = userId && userId !== "default" ? userId : "default";
127
+ return `${this.baseStorageKey}:${userPart}:${accountId}`;
128
+ }
114
129
  if (!userId || userId === "default") {
115
130
  return this.baseStorageKey;
116
131
  }
@@ -120,8 +135,9 @@ var TokenStore = class {
120
135
  * Store token (encrypted by storage layer)
121
136
  * @param tokenResponse - Token response from OAuth provider
122
137
  * @param userId - Optional user identifier for multi-user support
138
+ * @param accountId - Optional account alias for multi-account support
123
139
  */
124
- async storeToken(tokenResponse, userId) {
140
+ async storeToken(tokenResponse, userId, accountId) {
125
141
  if (!tokenResponse.access_token) {
126
142
  throw new Error("OAuth response missing required access_token field");
127
143
  }
@@ -139,39 +155,46 @@ var TokenStore = class {
139
155
  scope: tokenResponse.scope,
140
156
  obtained_at: Date.now()
141
157
  };
142
- const key = this.getScopedKey(userId);
158
+ const key = this.getScopedKey(userId, accountId);
143
159
  await this.storage.storeToken(key, token);
144
160
  }
145
161
  /**
146
162
  * Get access token
147
163
  * @param userId - Optional user identifier for multi-user support
164
+ * @param accountId - Optional account alias for multi-account support
148
165
  */
149
- async getAccessToken(userId) {
150
- const key = this.getScopedKey(userId);
166
+ async getAccessToken(userId, accountId) {
167
+ const key = this.getScopedKey(userId, accountId);
151
168
  const token = await this.storage.getToken(key);
152
169
  if (!token) {
153
- throw new Error(`No token stored for ${userId ? `user: ${userId}` : "default user"}`);
170
+ const userLabel = userId ? `user: ${userId}` : "default user";
171
+ const accountLabel = accountId ? `, account: ${accountId}` : "";
172
+ throw new Error(`No token stored for ${userLabel}${accountLabel}`);
154
173
  }
155
174
  return token.access_token;
156
175
  }
157
176
  /**
158
177
  * Get refresh token
159
178
  * @param userId - Optional user identifier for multi-user support
179
+ * @param accountId - Optional account alias for multi-account support
160
180
  */
161
- async getRefreshToken(userId) {
162
- const key = this.getScopedKey(userId);
181
+ async getRefreshToken(userId, accountId) {
182
+ const key = this.getScopedKey(userId, accountId);
163
183
  const token = await this.storage.getToken(key);
164
184
  if (!token?.refresh_token) {
165
- throw new Error(`No refresh token available for ${userId ? `user: ${userId}` : "default user"}`);
185
+ const userLabel = userId ? `user: ${userId}` : "default user";
186
+ const accountLabel = accountId ? `, account: ${accountId}` : "";
187
+ throw new Error(`No refresh token available for ${userLabel}${accountLabel}`);
166
188
  }
167
189
  return token.refresh_token;
168
190
  }
169
191
  /**
170
192
  * Check if has refresh token
171
193
  * @param userId - Optional user identifier for multi-user support
194
+ * @param accountId - Optional account alias for multi-account support
172
195
  */
173
- async hasRefreshToken(userId) {
174
- const key = this.getScopedKey(userId);
196
+ async hasRefreshToken(userId, accountId) {
197
+ const key = this.getScopedKey(userId, accountId);
175
198
  const token = await this.storage.getToken(key);
176
199
  return !!token?.refresh_token;
177
200
  }
@@ -180,9 +203,10 @@ var TokenStore = class {
180
203
  *
181
204
  * @param bufferSeconds - Refresh this many seconds before expiry (default: 300 = 5 min)
182
205
  * @param userId - Optional user identifier for multi-user support
206
+ * @param accountId - Optional account alias for multi-account support
183
207
  */
184
- async isValid(bufferSeconds = 300, userId) {
185
- const key = this.getScopedKey(userId);
208
+ async isValid(bufferSeconds = 300, userId, accountId) {
209
+ const key = this.getScopedKey(userId, accountId);
186
210
  const token = await this.storage.getToken(key);
187
211
  if (!token) {
188
212
  return false;
@@ -194,19 +218,46 @@ var TokenStore = class {
194
218
  /**
195
219
  * Clear stored token
196
220
  * @param userId - Optional user identifier for multi-user support
221
+ * @param accountId - Optional account alias for multi-account support
197
222
  */
198
- async clear(userId) {
199
- const key = this.getScopedKey(userId);
223
+ async clear(userId, accountId) {
224
+ const key = this.getScopedKey(userId, accountId);
200
225
  await this.storage.deleteToken(key);
201
226
  }
202
227
  /**
203
228
  * Get full token info
204
229
  * @param userId - Optional user identifier for multi-user support
230
+ * @param accountId - Optional account alias for multi-account support
205
231
  */
206
- async getTokenInfo(userId) {
207
- const key = this.getScopedKey(userId);
232
+ async getTokenInfo(userId, accountId) {
233
+ const key = this.getScopedKey(userId, accountId);
208
234
  return this.storage.getToken(key);
209
235
  }
236
+ /**
237
+ * List account aliases for a user on this connector.
238
+ * Returns account IDs that have stored tokens.
239
+ *
240
+ * @param userId - Optional user identifier
241
+ * @returns Array of account aliases (e.g., ['work', 'personal'])
242
+ */
243
+ async listAccounts(userId) {
244
+ if (!this.storage.listKeys) {
245
+ return [];
246
+ }
247
+ const allKeys = await this.storage.listKeys();
248
+ const userPart = userId && userId !== "default" ? userId : "default";
249
+ const prefix = `${this.baseStorageKey}:${userPart}:`;
250
+ const accounts = [];
251
+ for (const key of allKeys) {
252
+ if (key.startsWith(prefix)) {
253
+ const accountId = key.slice(prefix.length);
254
+ if (accountId && !accountId.includes(":")) {
255
+ accounts.push(accountId);
256
+ }
257
+ }
258
+ }
259
+ return accounts;
260
+ }
210
261
  };
211
262
  function generatePKCE() {
212
263
  const codeVerifier = base64URLEncode(crypto.randomBytes(32));
@@ -232,20 +283,28 @@ var AuthCodePKCEFlow = class {
232
283
  this.tokenStore = new TokenStore(storageKey, config.storage);
233
284
  }
234
285
  tokenStore;
235
- // Store PKCE data per user with timestamps for cleanup
286
+ // Store PKCE data per user+account with timestamps for cleanup
236
287
  codeVerifiers = /* @__PURE__ */ new Map();
237
288
  states = /* @__PURE__ */ new Map();
238
- // Store refresh locks per user to prevent concurrent refresh
289
+ // Store refresh locks per user+account to prevent concurrent refresh
239
290
  refreshLocks = /* @__PURE__ */ new Map();
240
291
  // PKCE data TTL: 15 minutes (auth flows should complete within this time)
241
292
  PKCE_TTL = 15 * 60 * 1e3;
293
+ /**
294
+ * Build a map key from userId and accountId for internal PKCE/state/lock maps.
295
+ */
296
+ getMapKey(userId, accountId) {
297
+ const userPart = userId || "default";
298
+ return accountId ? `${userPart}:${accountId}` : userPart;
299
+ }
242
300
  /**
243
301
  * Generate authorization URL for user to visit
244
302
  * Opens browser or redirects user to this URL
245
303
  *
246
304
  * @param userId - User identifier for multi-user support (optional)
305
+ * @param accountId - Account alias for multi-account support (optional)
247
306
  */
248
- async getAuthorizationUrl(userId) {
307
+ async getAuthorizationUrl(userId, accountId) {
249
308
  if (!this.config.authorizationUrl) {
250
309
  throw new Error("authorizationUrl is required for authorization_code flow");
251
310
  }
@@ -253,11 +312,11 @@ var AuthCodePKCEFlow = class {
253
312
  throw new Error("redirectUri is required for authorization_code flow");
254
313
  }
255
314
  this.cleanupExpiredPKCE();
256
- const userKey = userId || "default";
315
+ const mapKey = this.getMapKey(userId, accountId);
257
316
  const { codeVerifier, codeChallenge } = generatePKCE();
258
- this.codeVerifiers.set(userKey, { verifier: codeVerifier, timestamp: Date.now() });
317
+ this.codeVerifiers.set(mapKey, { verifier: codeVerifier, timestamp: Date.now() });
259
318
  const state = generateState();
260
- this.states.set(userKey, { state, timestamp: Date.now() });
319
+ this.states.set(mapKey, { state, timestamp: Date.now() });
261
320
  const params = new URLSearchParams({
262
321
  response_type: "code",
263
322
  client_id: this.config.clientId,
@@ -271,33 +330,48 @@ var AuthCodePKCEFlow = class {
271
330
  params.append("code_challenge", codeChallenge);
272
331
  params.append("code_challenge_method", "S256");
273
332
  }
274
- const stateWithUser = userId ? `${state}::${userId}` : state;
275
- params.set("state", stateWithUser);
333
+ let stateWithMetadata = state;
334
+ if (userId || accountId) {
335
+ stateWithMetadata = `${state}::${userId || ""}`;
336
+ if (accountId) {
337
+ stateWithMetadata += `::${accountId}`;
338
+ }
339
+ }
340
+ params.set("state", stateWithMetadata);
276
341
  return `${this.config.authorizationUrl}?${params.toString()}`;
277
342
  }
278
343
  /**
279
344
  * Exchange authorization code for access token
280
345
  *
281
346
  * @param code - Authorization code from callback
282
- * @param state - State parameter from callback (for CSRF verification, may include userId)
347
+ * @param state - State parameter from callback (for CSRF verification, may include userId/accountId)
283
348
  * @param userId - User identifier (optional, can be extracted from state)
349
+ * @param accountId - Account alias (optional, can be extracted from state)
284
350
  */
285
- async exchangeCode(code, state, userId) {
351
+ async exchangeCode(code, state, userId, accountId) {
286
352
  let actualState = state;
287
353
  let actualUserId = userId;
354
+ let actualAccountId = accountId;
288
355
  if (state.includes("::")) {
289
356
  const parts = state.split("::");
290
357
  actualState = parts[0];
291
- actualUserId = parts[1];
358
+ if (!actualUserId && parts[1]) {
359
+ actualUserId = parts[1];
360
+ }
361
+ if (!actualAccountId && parts[2]) {
362
+ actualAccountId = parts[2];
363
+ }
292
364
  }
293
- const userKey = actualUserId || "default";
294
- const stateData = this.states.get(userKey);
365
+ const mapKey = this.getMapKey(actualUserId, actualAccountId);
366
+ const stateData = this.states.get(mapKey);
295
367
  if (!stateData) {
296
- throw new Error(`No PKCE state found for user ${actualUserId}. Authorization flow may have expired (15 min TTL).`);
368
+ const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
369
+ throw new Error(`No PKCE state found for ${label}. Authorization flow may have expired (15 min TTL).`);
297
370
  }
298
371
  const expectedState = stateData.state;
299
372
  if (actualState !== expectedState) {
300
- throw new Error(`State mismatch for user ${actualUserId} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
373
+ const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
374
+ throw new Error(`State mismatch for ${label} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
301
375
  }
302
376
  if (!this.config.redirectUri) {
303
377
  throw new Error("redirectUri is required");
@@ -311,7 +385,7 @@ var AuthCodePKCEFlow = class {
311
385
  if (this.config.clientSecret) {
312
386
  params.append("client_secret", this.config.clientSecret);
313
387
  }
314
- const verifierData = this.codeVerifiers.get(userKey);
388
+ const verifierData = this.codeVerifiers.get(mapKey);
315
389
  if (this.config.usePKCE !== false && verifierData) {
316
390
  params.append("code_verifier", verifierData.verifier);
317
391
  }
@@ -345,39 +419,43 @@ var AuthCodePKCEFlow = class {
345
419
  throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${error}`);
346
420
  }
347
421
  const data = await response.json();
348
- await this.tokenStore.storeToken(data, actualUserId);
349
- this.codeVerifiers.delete(userKey);
350
- this.states.delete(userKey);
422
+ await this.tokenStore.storeToken(data, actualUserId, actualAccountId);
423
+ this.codeVerifiers.delete(mapKey);
424
+ this.states.delete(mapKey);
351
425
  }
352
426
  /**
353
427
  * Get valid token (auto-refreshes if needed)
354
428
  * @param userId - User identifier for multi-user support
429
+ * @param accountId - Account alias for multi-account support
355
430
  */
356
- async getToken(userId) {
357
- const key = userId || "default";
358
- if (this.refreshLocks.has(key)) {
359
- return this.refreshLocks.get(key);
431
+ async getToken(userId, accountId) {
432
+ const mapKey = this.getMapKey(userId, accountId);
433
+ if (this.refreshLocks.has(mapKey)) {
434
+ return this.refreshLocks.get(mapKey);
360
435
  }
361
- if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId)) {
362
- return this.tokenStore.getAccessToken(userId);
436
+ if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
437
+ return this.tokenStore.getAccessToken(userId, accountId);
363
438
  }
364
- if (await this.tokenStore.hasRefreshToken(userId)) {
365
- const refreshPromise = this.refreshToken(userId);
366
- this.refreshLocks.set(key, refreshPromise);
439
+ if (await this.tokenStore.hasRefreshToken(userId, accountId)) {
440
+ const refreshPromise = this.refreshToken(userId, accountId);
441
+ this.refreshLocks.set(mapKey, refreshPromise);
367
442
  try {
368
443
  return await refreshPromise;
369
444
  } finally {
370
- this.refreshLocks.delete(key);
445
+ this.refreshLocks.delete(mapKey);
371
446
  }
372
447
  }
373
- throw new Error(`No valid token available for ${userId ? `user: ${userId}` : "default user"}. User needs to authorize (call startAuthFlow).`);
448
+ const userLabel = userId ? `user: ${userId}` : "default user";
449
+ const accountLabel = accountId ? `, account: ${accountId}` : "";
450
+ throw new Error(`No valid token available for ${userLabel}${accountLabel}. User needs to authorize (call startAuthFlow).`);
374
451
  }
375
452
  /**
376
453
  * Refresh access token using refresh token
377
454
  * @param userId - User identifier for multi-user support
455
+ * @param accountId - Account alias for multi-account support
378
456
  */
379
- async refreshToken(userId) {
380
- const refreshToken = await this.tokenStore.getRefreshToken(userId);
457
+ async refreshToken(userId, accountId) {
458
+ const refreshToken = await this.tokenStore.getRefreshToken(userId, accountId);
381
459
  const params = new URLSearchParams({
382
460
  grant_type: "refresh_token",
383
461
  refresh_token: refreshToken,
@@ -416,28 +494,30 @@ var AuthCodePKCEFlow = class {
416
494
  throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${error}`);
417
495
  }
418
496
  const data = await response.json();
419
- await this.tokenStore.storeToken(data, userId);
497
+ await this.tokenStore.storeToken(data, userId, accountId);
420
498
  return data.access_token;
421
499
  }
422
500
  /**
423
501
  * Check if token is valid
424
502
  * @param userId - User identifier for multi-user support
503
+ * @param accountId - Account alias for multi-account support
425
504
  */
426
- async isTokenValid(userId) {
427
- return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId);
505
+ async isTokenValid(userId, accountId) {
506
+ return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
428
507
  }
429
508
  /**
430
509
  * Revoke token (if supported by provider)
431
510
  * @param revocationUrl - Optional revocation endpoint
432
511
  * @param userId - User identifier for multi-user support
512
+ * @param accountId - Account alias for multi-account support
433
513
  */
434
- async revokeToken(revocationUrl, userId) {
514
+ async revokeToken(revocationUrl, userId, accountId) {
435
515
  if (!revocationUrl) {
436
- await this.tokenStore.clear(userId);
516
+ await this.tokenStore.clear(userId, accountId);
437
517
  return;
438
518
  }
439
519
  try {
440
- const token = await this.tokenStore.getAccessToken(userId);
520
+ const token = await this.tokenStore.getAccessToken(userId, accountId);
441
521
  await fetch(revocationUrl, {
442
522
  method: "POST",
443
523
  headers: {
@@ -449,9 +529,16 @@ var AuthCodePKCEFlow = class {
449
529
  })
450
530
  });
451
531
  } finally {
452
- await this.tokenStore.clear(userId);
532
+ await this.tokenStore.clear(userId, accountId);
453
533
  }
454
534
  }
535
+ /**
536
+ * List account aliases for a user.
537
+ * @param userId - User identifier (optional)
538
+ */
539
+ async listAccounts(userId) {
540
+ return this.tokenStore.listAccounts(userId);
541
+ }
455
542
  /**
456
543
  * Clean up expired PKCE data to prevent memory leaks
457
544
  * Removes verifiers and states older than PKCE_TTL (15 minutes)
@@ -481,17 +568,19 @@ var ClientCredentialsFlow = class {
481
568
  tokenStore;
482
569
  /**
483
570
  * Get token using client credentials
571
+ * @param userId - User identifier for multi-user support (optional, rarely used for client_credentials)
572
+ * @param accountId - Account alias for multi-account support (optional)
484
573
  */
485
- async getToken() {
486
- if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
487
- return this.tokenStore.getAccessToken();
574
+ async getToken(userId, accountId) {
575
+ if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
576
+ return this.tokenStore.getAccessToken(userId, accountId);
488
577
  }
489
- return this.requestToken();
578
+ return this.requestToken(userId, accountId);
490
579
  }
491
580
  /**
492
581
  * Request a new token from the authorization server
493
582
  */
494
- async requestToken() {
583
+ async requestToken(userId, accountId) {
495
584
  const auth = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString(
496
585
  "base64"
497
586
  );
@@ -514,22 +603,26 @@ var ClientCredentialsFlow = class {
514
603
  throw new Error(`Token request failed: ${response.status} ${response.statusText} - ${error}`);
515
604
  }
516
605
  const data = await response.json();
517
- await this.tokenStore.storeToken(data);
606
+ await this.tokenStore.storeToken(data, userId, accountId);
518
607
  return data.access_token;
519
608
  }
520
609
  /**
521
610
  * Refresh token (client credentials don't use refresh tokens)
522
611
  * Just requests a new token
612
+ * @param userId - User identifier for multi-user support (optional)
613
+ * @param accountId - Account alias for multi-account support (optional)
523
614
  */
524
- async refreshToken() {
525
- await this.tokenStore.clear();
526
- return this.requestToken();
615
+ async refreshToken(userId, accountId) {
616
+ await this.tokenStore.clear(userId, accountId);
617
+ return this.requestToken(userId, accountId);
527
618
  }
528
619
  /**
529
620
  * Check if token is valid
621
+ * @param userId - User identifier for multi-user support (optional)
622
+ * @param accountId - Account alias for multi-account support (optional)
530
623
  */
531
- async isTokenValid() {
532
- return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
624
+ async isTokenValid(userId, accountId) {
625
+ return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
533
626
  }
534
627
  };
535
628
  var JWTBearerFlow = class {
@@ -565,17 +658,19 @@ var JWTBearerFlow = class {
565
658
  }
566
659
  /**
567
660
  * Get token using JWT Bearer assertion
661
+ * @param userId - User identifier for multi-user support (optional)
662
+ * @param accountId - Account alias for multi-account support (optional)
568
663
  */
569
- async getToken() {
570
- if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
571
- return this.tokenStore.getAccessToken();
664
+ async getToken(userId, accountId) {
665
+ if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
666
+ return this.tokenStore.getAccessToken(userId, accountId);
572
667
  }
573
- return this.requestToken();
668
+ return this.requestToken(userId, accountId);
574
669
  }
575
670
  /**
576
671
  * Request token using JWT assertion
577
672
  */
578
- async requestToken() {
673
+ async requestToken(userId, accountId) {
579
674
  const assertion = await this.generateJWT();
580
675
  const params = new URLSearchParams({
581
676
  grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
@@ -593,21 +688,25 @@ var JWTBearerFlow = class {
593
688
  throw new Error(`JWT Bearer token request failed: ${response.status} ${response.statusText} - ${error}`);
594
689
  }
595
690
  const data = await response.json();
596
- await this.tokenStore.storeToken(data);
691
+ await this.tokenStore.storeToken(data, userId, accountId);
597
692
  return data.access_token;
598
693
  }
599
694
  /**
600
695
  * Refresh token (generate new JWT and request new token)
696
+ * @param userId - User identifier for multi-user support (optional)
697
+ * @param accountId - Account alias for multi-account support (optional)
601
698
  */
602
- async refreshToken() {
603
- await this.tokenStore.clear();
604
- return this.requestToken();
699
+ async refreshToken(userId, accountId) {
700
+ await this.tokenStore.clear(userId, accountId);
701
+ return this.requestToken(userId, accountId);
605
702
  }
606
703
  /**
607
704
  * Check if token is valid
705
+ * @param userId - User identifier for multi-user support (optional)
706
+ * @param accountId - Account alias for multi-account support (optional)
608
707
  */
609
- async isTokenValid() {
610
- return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
708
+ async isTokenValid(userId, accountId) {
709
+ return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
611
710
  }
612
711
  };
613
712
 
@@ -673,25 +772,28 @@ var OAuthManager = class {
673
772
  * Automatically refreshes if expired
674
773
  *
675
774
  * @param userId - User identifier for multi-user support (optional)
775
+ * @param accountId - Account alias for multi-account support (optional)
676
776
  */
677
- async getToken(userId) {
678
- return this.flow.getToken(userId);
777
+ async getToken(userId, accountId) {
778
+ return this.flow.getToken(userId, accountId);
679
779
  }
680
780
  /**
681
781
  * Force refresh the token
682
782
  *
683
783
  * @param userId - User identifier for multi-user support (optional)
784
+ * @param accountId - Account alias for multi-account support (optional)
684
785
  */
685
- async refreshToken(userId) {
686
- return this.flow.refreshToken(userId);
786
+ async refreshToken(userId, accountId) {
787
+ return this.flow.refreshToken(userId, accountId);
687
788
  }
688
789
  /**
689
790
  * Check if current token is valid
690
791
  *
691
792
  * @param userId - User identifier for multi-user support (optional)
793
+ * @param accountId - Account alias for multi-account support (optional)
692
794
  */
693
- async isTokenValid(userId) {
694
- return this.flow.isTokenValid(userId);
795
+ async isTokenValid(userId, accountId) {
796
+ return this.flow.isTokenValid(userId, accountId);
695
797
  }
696
798
  // ==================== Authorization Code Flow Methods ====================
697
799
  /**
@@ -699,13 +801,14 @@ var OAuthManager = class {
699
801
  * Returns URL for user to visit
700
802
  *
701
803
  * @param userId - User identifier for multi-user support (optional)
804
+ * @param accountId - Account alias for multi-account support (optional)
702
805
  * @returns Authorization URL for the user to visit
703
806
  */
704
- async startAuthFlow(userId) {
807
+ async startAuthFlow(userId, accountId) {
705
808
  if (!(this.flow instanceof AuthCodePKCEFlow)) {
706
809
  throw new Error("startAuthFlow() is only available for authorization_code flow");
707
810
  }
708
- return this.flow.getAuthorizationUrl(userId);
811
+ return this.flow.getAuthorizationUrl(userId, accountId);
709
812
  }
710
813
  /**
711
814
  * Handle OAuth callback (Authorization Code only)
@@ -713,8 +816,9 @@ var OAuthManager = class {
713
816
  *
714
817
  * @param callbackUrl - Full callback URL with code and state parameters
715
818
  * @param userId - Optional user identifier (can be extracted from state if embedded)
819
+ * @param accountId - Optional account alias (can be extracted from state if embedded)
716
820
  */
717
- async handleCallback(callbackUrl, userId) {
821
+ async handleCallback(callbackUrl, userId, accountId) {
718
822
  if (!(this.flow instanceof AuthCodePKCEFlow)) {
719
823
  throw new Error("handleCallback() is only available for authorization_code flow");
720
824
  }
@@ -727,21 +831,34 @@ var OAuthManager = class {
727
831
  if (!state) {
728
832
  throw new Error("Missing state parameter in callback URL");
729
833
  }
730
- await this.flow.exchangeCode(code, state, userId);
834
+ await this.flow.exchangeCode(code, state, userId, accountId);
731
835
  }
732
836
  /**
733
837
  * Revoke token (if supported by provider)
734
838
  *
735
839
  * @param revocationUrl - Optional revocation endpoint URL
736
840
  * @param userId - User identifier for multi-user support (optional)
841
+ * @param accountId - Account alias for multi-account support (optional)
737
842
  */
738
- async revokeToken(revocationUrl, userId) {
843
+ async revokeToken(revocationUrl, userId, accountId) {
739
844
  if (this.flow instanceof AuthCodePKCEFlow) {
740
- await this.flow.revokeToken(revocationUrl, userId);
845
+ await this.flow.revokeToken(revocationUrl, userId, accountId);
741
846
  } else {
742
847
  throw new Error("Token revocation not implemented for this flow");
743
848
  }
744
849
  }
850
+ /**
851
+ * List account aliases for a user (Authorization Code only)
852
+ *
853
+ * @param userId - User identifier (optional)
854
+ * @returns Array of account aliases (e.g., ['work', 'personal'])
855
+ */
856
+ async listAccounts(userId) {
857
+ if (this.flow instanceof AuthCodePKCEFlow) {
858
+ return this.flow.listAccounts(userId);
859
+ }
860
+ return [];
861
+ }
745
862
  // ==================== Validation ====================
746
863
  validateConfig(config) {
747
864
  if (!config.flow) {
@@ -1857,46 +1974,59 @@ var Connector = class _Connector {
1857
1974
  /**
1858
1975
  * Get the current access token (for OAuth, JWT, or API key)
1859
1976
  * Handles automatic refresh if needed
1977
+ *
1978
+ * @param userId - Optional user identifier for multi-user support
1979
+ * @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
1860
1980
  */
1861
- async getToken(userId) {
1981
+ async getToken(userId, accountId) {
1862
1982
  if (this.config.auth.type === "api_key") {
1863
1983
  return this.config.auth.apiKey;
1864
1984
  }
1865
1985
  if (!this.oauthManager) {
1866
1986
  throw new Error(`OAuth manager not initialized for connector '${this.name}'`);
1867
1987
  }
1868
- return this.oauthManager.getToken(userId);
1988
+ return this.oauthManager.getToken(userId, accountId);
1869
1989
  }
1870
1990
  /**
1871
1991
  * Start OAuth authorization flow
1872
1992
  * Returns the URL to redirect the user to
1993
+ *
1994
+ * @param userId - Optional user identifier for multi-user support
1995
+ * @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
1873
1996
  */
1874
- async startAuth(userId) {
1997
+ async startAuth(userId, accountId) {
1875
1998
  if (!this.oauthManager) {
1876
1999
  throw new Error(`Connector '${this.name}' is not an OAuth connector`);
1877
2000
  }
1878
- return this.oauthManager.startAuthFlow(userId);
2001
+ return this.oauthManager.startAuthFlow(userId, accountId);
1879
2002
  }
1880
2003
  /**
1881
2004
  * Handle OAuth callback
1882
2005
  * Call this after user is redirected back from OAuth provider
2006
+ *
2007
+ * @param callbackUrl - Full callback URL with code and state parameters
2008
+ * @param userId - Optional user identifier (can be extracted from state if embedded)
2009
+ * @param accountId - Optional account alias (can be extracted from state if embedded)
1883
2010
  */
1884
- async handleCallback(callbackUrl, userId) {
2011
+ async handleCallback(callbackUrl, userId, accountId) {
1885
2012
  if (!this.oauthManager) {
1886
2013
  throw new Error(`Connector '${this.name}' is not an OAuth connector`);
1887
2014
  }
1888
- await this.oauthManager.handleCallback(callbackUrl, userId);
2015
+ await this.oauthManager.handleCallback(callbackUrl, userId, accountId);
1889
2016
  }
1890
2017
  /**
1891
2018
  * Check if the connector has a valid token
2019
+ *
2020
+ * @param userId - Optional user identifier for multi-user support
2021
+ * @param accountId - Optional account alias for multi-account support
1892
2022
  */
1893
- async hasValidToken(userId) {
2023
+ async hasValidToken(userId, accountId) {
1894
2024
  try {
1895
2025
  if (this.config.auth.type === "api_key") {
1896
2026
  return true;
1897
2027
  }
1898
2028
  if (this.oauthManager) {
1899
- const token = await this.oauthManager.getToken(userId);
2029
+ const token = await this.oauthManager.getToken(userId, accountId);
1900
2030
  return !!token;
1901
2031
  }
1902
2032
  return false;
@@ -1904,6 +2034,19 @@ var Connector = class _Connector {
1904
2034
  return false;
1905
2035
  }
1906
2036
  }
2037
+ /**
2038
+ * List account aliases for a user on this connector.
2039
+ * Only applicable for OAuth connectors with multi-account support.
2040
+ *
2041
+ * @param userId - Optional user identifier
2042
+ * @returns Array of account aliases (e.g., ['work', 'personal'])
2043
+ */
2044
+ async listAccounts(userId) {
2045
+ if (!this.oauthManager) {
2046
+ return [];
2047
+ }
2048
+ return this.oauthManager.listAccounts(userId);
2049
+ }
1907
2050
  /**
1908
2051
  * Get vendor-specific options from config
1909
2052
  */
@@ -1947,9 +2090,10 @@ var Connector = class _Connector {
1947
2090
  * @param endpoint - API endpoint (relative to baseURL) or full URL
1948
2091
  * @param options - Fetch options with connector-specific settings
1949
2092
  * @param userId - Optional user ID for multi-user OAuth
2093
+ * @param accountId - Optional account alias for multi-account OAuth
1950
2094
  * @returns Fetch Response
1951
2095
  */
1952
- async fetch(endpoint, options, userId) {
2096
+ async fetch(endpoint, options, userId, accountId) {
1953
2097
  if (this.disposed) {
1954
2098
  throw new Error(`Connector '${this.name}' has been disposed`);
1955
2099
  }
@@ -1968,7 +2112,7 @@ var Connector = class _Connector {
1968
2112
  this.logRequest(url, options);
1969
2113
  }
1970
2114
  const doFetch = async () => {
1971
- const token = await this.getToken(userId);
2115
+ const token = await this.getToken(userId, accountId);
1972
2116
  const auth = this.config.auth;
1973
2117
  let headerName = "Authorization";
1974
2118
  let headerValue = `Bearer ${token}`;
@@ -2080,10 +2224,11 @@ var Connector = class _Connector {
2080
2224
  * @param endpoint - API endpoint (relative to baseURL) or full URL
2081
2225
  * @param options - Fetch options with connector-specific settings
2082
2226
  * @param userId - Optional user ID for multi-user OAuth
2227
+ * @param accountId - Optional account alias for multi-account OAuth
2083
2228
  * @returns Parsed JSON response
2084
2229
  */
2085
- async fetchJSON(endpoint, options, userId) {
2086
- const response = await this.fetch(endpoint, options, userId);
2230
+ async fetchJSON(endpoint, options, userId, accountId) {
2231
+ const response = await this.fetch(endpoint, options, userId, accountId);
2087
2232
  const text = await response.text();
2088
2233
  let data;
2089
2234
  try {