oc-chatgpt-multi-auth 5.3.4 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +203 -36
- package/dist/index.js.map +1 -1
- package/dist/lib/auth/token-utils.d.ts.map +1 -1
- package/dist/lib/auth/token-utils.js +27 -2
- package/dist/lib/auth/token-utils.js.map +1 -1
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +73 -26
- package/dist/lib/storage.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA+J/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA+J/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MA8yK/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -350,6 +350,93 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
350
350
|
cooldownReason: mergedCooldownReason,
|
|
351
351
|
};
|
|
352
352
|
};
|
|
353
|
+
const normalizeStoredAccountId = (account) => {
|
|
354
|
+
const accountId = account?.accountId?.trim();
|
|
355
|
+
return accountId && accountId.length > 0 ? accountId : undefined;
|
|
356
|
+
};
|
|
357
|
+
const hasDistinctNonEmptyAccountIds = (left, right) => {
|
|
358
|
+
const leftId = normalizeStoredAccountId(left);
|
|
359
|
+
const rightId = normalizeStoredAccountId(right);
|
|
360
|
+
return !!leftId && !!rightId && leftId !== rightId;
|
|
361
|
+
};
|
|
362
|
+
const canCollapseWithCandidateAccountId = (existing, candidateAccountId) => {
|
|
363
|
+
const existingAccountId = normalizeStoredAccountId(existing);
|
|
364
|
+
const normalizedCandidate = candidateAccountId?.trim() || undefined;
|
|
365
|
+
if (!existingAccountId || !normalizedCandidate) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
return existingAccountId === normalizedCandidate;
|
|
369
|
+
};
|
|
370
|
+
const resolveOrganizationMatch = (indexes, organizationId, candidateAccountId) => {
|
|
371
|
+
const matches = indexes.byOrganizationId.get(organizationId);
|
|
372
|
+
if (!matches || matches.length === 0)
|
|
373
|
+
return undefined;
|
|
374
|
+
const candidateId = candidateAccountId?.trim() || undefined;
|
|
375
|
+
let newestNoAccountId;
|
|
376
|
+
let newestExactAccountId;
|
|
377
|
+
let newestAnyNonEmptyAccountId;
|
|
378
|
+
const distinctNonEmptyAccountIds = new Set();
|
|
379
|
+
for (const index of matches) {
|
|
380
|
+
const existing = accounts[index];
|
|
381
|
+
if (!existing)
|
|
382
|
+
continue;
|
|
383
|
+
const existingAccountId = normalizeStoredAccountId(existing);
|
|
384
|
+
if (!existingAccountId) {
|
|
385
|
+
newestNoAccountId =
|
|
386
|
+
typeof newestNoAccountId === "number"
|
|
387
|
+
? pickNewestAccountIndex(newestNoAccountId, index)
|
|
388
|
+
: index;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
distinctNonEmptyAccountIds.add(existingAccountId);
|
|
392
|
+
newestAnyNonEmptyAccountId =
|
|
393
|
+
typeof newestAnyNonEmptyAccountId === "number"
|
|
394
|
+
? pickNewestAccountIndex(newestAnyNonEmptyAccountId, index)
|
|
395
|
+
: index;
|
|
396
|
+
if (candidateId && existingAccountId === candidateId) {
|
|
397
|
+
newestExactAccountId =
|
|
398
|
+
typeof newestExactAccountId === "number"
|
|
399
|
+
? pickNewestAccountIndex(newestExactAccountId, index)
|
|
400
|
+
: index;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (candidateId) {
|
|
404
|
+
return newestExactAccountId ?? newestNoAccountId;
|
|
405
|
+
}
|
|
406
|
+
if (typeof newestNoAccountId === "number") {
|
|
407
|
+
return newestNoAccountId;
|
|
408
|
+
}
|
|
409
|
+
if (distinctNonEmptyAccountIds.size === 1) {
|
|
410
|
+
return newestAnyNonEmptyAccountId;
|
|
411
|
+
}
|
|
412
|
+
return undefined;
|
|
413
|
+
};
|
|
414
|
+
const resolveNoOrgRefreshMatch = (indexes, refreshToken, candidateAccountId) => {
|
|
415
|
+
const candidateId = candidateAccountId?.trim() || undefined;
|
|
416
|
+
const matches = indexes.byRefreshTokenNoOrg.get(refreshToken);
|
|
417
|
+
if (!matches || matches.length === 0)
|
|
418
|
+
return undefined;
|
|
419
|
+
let newestNoAccountId;
|
|
420
|
+
let newestExactAccountId;
|
|
421
|
+
for (const index of matches) {
|
|
422
|
+
const existing = accounts[index];
|
|
423
|
+
const existingAccountId = normalizeStoredAccountId(existing);
|
|
424
|
+
if (!existingAccountId) {
|
|
425
|
+
newestNoAccountId =
|
|
426
|
+
typeof newestNoAccountId === "number"
|
|
427
|
+
? pickNewestAccountIndex(newestNoAccountId, index)
|
|
428
|
+
: index;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (candidateId && existingAccountId === candidateId) {
|
|
432
|
+
newestExactAccountId =
|
|
433
|
+
typeof newestExactAccountId === "number"
|
|
434
|
+
? pickNewestAccountIndex(newestExactAccountId, index)
|
|
435
|
+
: index;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return newestExactAccountId ?? newestNoAccountId;
|
|
439
|
+
};
|
|
353
440
|
const resolveUniqueOrgScopedMatch = (indexes, accountId, refreshToken) => {
|
|
354
441
|
const byAccountId = accountId
|
|
355
442
|
? asUniqueIndex(indexes.byAccountIdOrgScoped.get(accountId))
|
|
@@ -378,12 +465,13 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
378
465
|
const accountId = account.accountId?.trim();
|
|
379
466
|
const refreshToken = account.refreshToken?.trim();
|
|
380
467
|
const email = account.email?.trim();
|
|
381
|
-
//
|
|
382
|
-
|
|
383
|
-
|
|
468
|
+
// Track all refresh-token matches. Callers can require uniqueness
|
|
469
|
+
// so org variants that share a token do not collapse accidentally.
|
|
470
|
+
if (refreshToken) {
|
|
471
|
+
pushIndex(byRefreshTokenGlobal, refreshToken, i);
|
|
384
472
|
}
|
|
385
473
|
if (organizationId) {
|
|
386
|
-
byOrganizationId
|
|
474
|
+
pushIndex(byOrganizationId, organizationId, i);
|
|
387
475
|
if (accountId) {
|
|
388
476
|
pushIndex(byAccountIdOrgScoped, accountId, i);
|
|
389
477
|
}
|
|
@@ -396,7 +484,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
396
484
|
byAccountIdNoOrg.set(accountId, i);
|
|
397
485
|
}
|
|
398
486
|
if (refreshToken) {
|
|
399
|
-
byRefreshTokenNoOrg
|
|
487
|
+
pushIndex(byRefreshTokenNoOrg, refreshToken, i);
|
|
400
488
|
}
|
|
401
489
|
if (email) {
|
|
402
490
|
byEmailNoOrg.set(email, i);
|
|
@@ -425,7 +513,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
425
513
|
const accountEmail = sanitizeEmail(extractAccountEmail(result.access, result.idToken));
|
|
426
514
|
const existingIndex = (() => {
|
|
427
515
|
if (organizationId) {
|
|
428
|
-
return identityIndexes
|
|
516
|
+
return resolveOrganizationMatch(identityIndexes, organizationId, normalizedAccountId);
|
|
429
517
|
}
|
|
430
518
|
if (normalizedAccountId) {
|
|
431
519
|
const byAccountId = identityIndexes.byAccountIdNoOrg.get(normalizedAccountId);
|
|
@@ -433,11 +521,11 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
433
521
|
return byAccountId;
|
|
434
522
|
}
|
|
435
523
|
}
|
|
436
|
-
const byRefreshToken = identityIndexes
|
|
524
|
+
const byRefreshToken = resolveNoOrgRefreshMatch(identityIndexes, result.refresh, normalizedAccountId);
|
|
437
525
|
if (byRefreshToken !== undefined) {
|
|
438
526
|
return byRefreshToken;
|
|
439
527
|
}
|
|
440
|
-
if (accountEmail) {
|
|
528
|
+
if (accountEmail && !normalizedAccountId) {
|
|
441
529
|
const byEmail = identityIndexes.byEmailNoOrg.get(accountEmail);
|
|
442
530
|
if (byEmail !== undefined) {
|
|
443
531
|
return byEmail;
|
|
@@ -446,9 +534,17 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
446
534
|
const orgScoped = resolveUniqueOrgScopedMatch(identityIndexes, normalizedAccountId, result.refresh);
|
|
447
535
|
if (orgScoped !== undefined)
|
|
448
536
|
return orgScoped;
|
|
449
|
-
// Absolute last resort:
|
|
450
|
-
//
|
|
451
|
-
|
|
537
|
+
// Absolute last resort: only collapse when refresh token maps to a
|
|
538
|
+
// single compatible account. Avoids merging distinct workspace variants.
|
|
539
|
+
const globalRefreshMatch = asUniqueIndex(identityIndexes.byRefreshTokenGlobal.get(result.refresh));
|
|
540
|
+
if (globalRefreshMatch === undefined) {
|
|
541
|
+
return undefined;
|
|
542
|
+
}
|
|
543
|
+
const existing = accounts[globalRefreshMatch];
|
|
544
|
+
if (!canCollapseWithCandidateAccountId(existing, normalizedAccountId)) {
|
|
545
|
+
return undefined;
|
|
546
|
+
}
|
|
547
|
+
return globalRefreshMatch;
|
|
452
548
|
})();
|
|
453
549
|
if (existingIndex === undefined) {
|
|
454
550
|
accounts.push({
|
|
@@ -502,6 +598,50 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
502
598
|
const pruneRefreshTokenCollisions = () => {
|
|
503
599
|
const indicesToRemove = new Set();
|
|
504
600
|
const refreshMap = new Map();
|
|
601
|
+
const pickPreferredOrgIndex = (existingIndex, candidateIndex) => {
|
|
602
|
+
if (existingIndex === undefined)
|
|
603
|
+
return candidateIndex;
|
|
604
|
+
return pickNewestAccountIndex(existingIndex, candidateIndex);
|
|
605
|
+
};
|
|
606
|
+
const collapseFallbackIntoPreferredOrg = (entry) => {
|
|
607
|
+
if (entry.preferredOrgIndex === undefined) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const preferredOrgIndex = entry.preferredOrgIndex;
|
|
611
|
+
const collapseFallbackIndex = (fallbackIndex) => {
|
|
612
|
+
if (preferredOrgIndex === fallbackIndex)
|
|
613
|
+
return true;
|
|
614
|
+
const target = accounts[preferredOrgIndex];
|
|
615
|
+
const source = accounts[fallbackIndex];
|
|
616
|
+
if (!target || !source)
|
|
617
|
+
return true;
|
|
618
|
+
const targetAccountId = normalizeStoredAccountId(target);
|
|
619
|
+
const sourceAccountId = normalizeStoredAccountId(source);
|
|
620
|
+
if (!targetAccountId && sourceAccountId) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
if (hasDistinctNonEmptyAccountIds(target, source)) {
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
mergeAccountRecords(preferredOrgIndex, fallbackIndex);
|
|
627
|
+
indicesToRemove.add(fallbackIndex);
|
|
628
|
+
return true;
|
|
629
|
+
};
|
|
630
|
+
if (typeof entry.fallbackNoAccountIdIndex === "number") {
|
|
631
|
+
if (collapseFallbackIndex(entry.fallbackNoAccountIdIndex)) {
|
|
632
|
+
entry.fallbackNoAccountIdIndex = undefined;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const fallbackAccountIdsToDelete = [];
|
|
636
|
+
for (const [accountId, fallbackIndex] of entry.fallbackByAccountId) {
|
|
637
|
+
if (collapseFallbackIndex(fallbackIndex)) {
|
|
638
|
+
fallbackAccountIdsToDelete.push(accountId);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
for (const accountId of fallbackAccountIdsToDelete) {
|
|
642
|
+
entry.fallbackByAccountId.delete(accountId);
|
|
643
|
+
}
|
|
644
|
+
};
|
|
505
645
|
for (let i = 0; i < accounts.length; i += 1) {
|
|
506
646
|
const account = accounts[i];
|
|
507
647
|
if (!account)
|
|
@@ -512,49 +652,70 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
512
652
|
const orgKey = account.organizationId?.trim() ?? "";
|
|
513
653
|
let entry = refreshMap.get(refreshToken);
|
|
514
654
|
if (!entry) {
|
|
515
|
-
entry = {
|
|
655
|
+
entry = {
|
|
656
|
+
byOrg: new Map(),
|
|
657
|
+
preferredOrgIndex: undefined,
|
|
658
|
+
fallbackNoAccountIdIndex: undefined,
|
|
659
|
+
fallbackByAccountId: new Map(),
|
|
660
|
+
};
|
|
516
661
|
refreshMap.set(refreshToken, entry);
|
|
517
662
|
}
|
|
518
663
|
if (orgKey) {
|
|
519
|
-
const
|
|
664
|
+
const orgMatches = entry.byOrg.get(orgKey) ?? [];
|
|
665
|
+
const existingIndex = resolveOrganizationMatch({
|
|
666
|
+
byOrganizationId: new Map([[orgKey, orgMatches]]),
|
|
667
|
+
byAccountIdNoOrg: new Map(),
|
|
668
|
+
byRefreshTokenNoOrg: new Map(),
|
|
669
|
+
byEmailNoOrg: new Map(),
|
|
670
|
+
byAccountIdOrgScoped: new Map(),
|
|
671
|
+
byRefreshTokenOrgScoped: new Map(),
|
|
672
|
+
byRefreshTokenGlobal: new Map(),
|
|
673
|
+
}, orgKey, normalizeStoredAccountId(account));
|
|
520
674
|
if (existingIndex !== undefined) {
|
|
521
675
|
const newestIndex = pickNewestAccountIndex(existingIndex, i);
|
|
522
676
|
const obsoleteIndex = newestIndex === existingIndex ? i : existingIndex;
|
|
523
677
|
mergeAccountRecords(newestIndex, obsoleteIndex);
|
|
524
678
|
indicesToRemove.add(obsoleteIndex);
|
|
525
|
-
|
|
679
|
+
const nextOrgMatches = orgMatches.filter((index) => index !== obsoleteIndex && index !== newestIndex);
|
|
680
|
+
nextOrgMatches.push(newestIndex);
|
|
681
|
+
entry.byOrg.set(orgKey, nextOrgMatches);
|
|
682
|
+
entry.preferredOrgIndex = pickPreferredOrgIndex(entry.preferredOrgIndex, newestIndex);
|
|
683
|
+
collapseFallbackIntoPreferredOrg(entry);
|
|
526
684
|
continue;
|
|
527
685
|
}
|
|
528
|
-
entry.byOrg.set(orgKey, i);
|
|
686
|
+
entry.byOrg.set(orgKey, [...orgMatches, i]);
|
|
687
|
+
entry.preferredOrgIndex = pickPreferredOrgIndex(entry.preferredOrgIndex, i);
|
|
688
|
+
collapseFallbackIntoPreferredOrg(entry);
|
|
529
689
|
continue;
|
|
530
690
|
}
|
|
531
|
-
const
|
|
691
|
+
const fallbackAccountId = normalizeStoredAccountId(account);
|
|
692
|
+
if (fallbackAccountId) {
|
|
693
|
+
const existingFallback = entry.fallbackByAccountId.get(fallbackAccountId);
|
|
694
|
+
if (typeof existingFallback === "number") {
|
|
695
|
+
const newestIndex = pickNewestAccountIndex(existingFallback, i);
|
|
696
|
+
const obsoleteIndex = newestIndex === existingFallback ? i : existingFallback;
|
|
697
|
+
mergeAccountRecords(newestIndex, obsoleteIndex);
|
|
698
|
+
indicesToRemove.add(obsoleteIndex);
|
|
699
|
+
entry.fallbackByAccountId.set(fallbackAccountId, newestIndex);
|
|
700
|
+
collapseFallbackIntoPreferredOrg(entry);
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
entry.fallbackByAccountId.set(fallbackAccountId, i);
|
|
704
|
+
collapseFallbackIntoPreferredOrg(entry);
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
const existingFallback = entry.fallbackNoAccountIdIndex;
|
|
532
708
|
if (typeof existingFallback === "number") {
|
|
533
709
|
const newestIndex = pickNewestAccountIndex(existingFallback, i);
|
|
534
710
|
const obsoleteIndex = newestIndex === existingFallback ? i : existingFallback;
|
|
535
711
|
mergeAccountRecords(newestIndex, obsoleteIndex);
|
|
536
712
|
indicesToRemove.add(obsoleteIndex);
|
|
537
|
-
entry.
|
|
713
|
+
entry.fallbackNoAccountIdIndex = newestIndex;
|
|
714
|
+
collapseFallbackIntoPreferredOrg(entry);
|
|
538
715
|
continue;
|
|
539
716
|
}
|
|
540
|
-
entry.
|
|
541
|
-
|
|
542
|
-
for (const entry of refreshMap.values()) {
|
|
543
|
-
const fallbackIndex = entry.fallbackIndex;
|
|
544
|
-
if (typeof fallbackIndex !== "number")
|
|
545
|
-
continue;
|
|
546
|
-
const orgIndices = Array.from(entry.byOrg.values());
|
|
547
|
-
if (orgIndices.length === 0)
|
|
548
|
-
continue;
|
|
549
|
-
const [firstOrgIndex, ...otherOrgIndices] = orgIndices;
|
|
550
|
-
if (typeof firstOrgIndex !== "number")
|
|
551
|
-
continue;
|
|
552
|
-
let preferredOrgIndex = firstOrgIndex;
|
|
553
|
-
for (const orgIndex of otherOrgIndices) {
|
|
554
|
-
preferredOrgIndex = pickNewestAccountIndex(preferredOrgIndex, orgIndex);
|
|
555
|
-
}
|
|
556
|
-
mergeAccountRecords(preferredOrgIndex, fallbackIndex);
|
|
557
|
-
indicesToRemove.add(fallbackIndex);
|
|
717
|
+
entry.fallbackNoAccountIdIndex = i;
|
|
718
|
+
collapseFallbackIntoPreferredOrg(entry);
|
|
558
719
|
}
|
|
559
720
|
if (indicesToRemove.size > 0) {
|
|
560
721
|
accounts = accounts.filter((_, index) => !indicesToRemove.has(index));
|
|
@@ -621,7 +782,13 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
|
|
|
621
782
|
const activeIndex = remappedActiveIndex ?? fallbackActiveIndex;
|
|
622
783
|
const clampedActiveIndex = Math.max(0, Math.min(Math.floor(activeIndex), accounts.length - 1));
|
|
623
784
|
const activeIndexByFamily = {};
|
|
624
|
-
|
|
785
|
+
const familiesToPersist = replaceAll
|
|
786
|
+
? []
|
|
787
|
+
: MODEL_FAMILIES.filter((family) => {
|
|
788
|
+
const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
|
|
789
|
+
return typeof storedFamilyIndex === "number" && Number.isFinite(storedFamilyIndex);
|
|
790
|
+
});
|
|
791
|
+
for (const family of familiesToPersist) {
|
|
625
792
|
const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
|
|
626
793
|
const remappedFamilyIndex = replaceAll
|
|
627
794
|
? undefined
|