@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.
@@ -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
- * For multi-user support, keys are scoped per user: "provider:userId"
135
- * For single-user (backward compatible), userId is omitted or "default"
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
- * @returns Storage key scoped to user
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
- throw new Error(`No token stored for ${userId ? `user: ${userId}` : "default user"}`);
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
- throw new Error(`No refresh token available for ${userId ? `user: ${userId}` : "default user"}`);
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 userKey = userId || "default";
342
+ const mapKey = this.getMapKey(userId, accountId);
284
343
  const { codeVerifier, codeChallenge } = generatePKCE();
285
- this.codeVerifiers.set(userKey, { verifier: codeVerifier, timestamp: Date.now() });
344
+ this.codeVerifiers.set(mapKey, { verifier: codeVerifier, timestamp: Date.now() });
286
345
  const state = generateState();
287
- this.states.set(userKey, { state, timestamp: Date.now() });
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
- const stateWithUser = userId ? `${state}::${userId}` : state;
302
- params.set("state", stateWithUser);
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 = parts[1];
385
+ if (!actualUserId && parts[1]) {
386
+ actualUserId = parts[1];
387
+ }
388
+ if (!actualAccountId && parts[2]) {
389
+ actualAccountId = parts[2];
390
+ }
319
391
  }
320
- const userKey = actualUserId || "default";
321
- const stateData = this.states.get(userKey);
392
+ const mapKey = this.getMapKey(actualUserId, actualAccountId);
393
+ const stateData = this.states.get(mapKey);
322
394
  if (!stateData) {
323
- throw new Error(`No PKCE state found for user ${actualUserId}. Authorization flow may have expired (15 min TTL).`);
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
- throw new Error(`State mismatch for user ${actualUserId} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
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(userKey);
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(userKey);
377
- this.states.delete(userKey);
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 key = userId || "default";
385
- if (this.refreshLocks.has(key)) {
386
- return this.refreshLocks.get(key);
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(key, refreshPromise);
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(key);
472
+ this.refreshLocks.delete(mapKey);
398
473
  }
399
474
  }
400
- throw new Error(`No valid token available for ${userId ? `user: ${userId}` : "default user"}. User needs to authorize (call startAuthFlow).`);
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 {