Skip to content

Commit a98e609

Browse files
committed
fix(identity): verify org-scoped preservation and no-org dedupe compatibility
1 parent 227cf6b commit a98e609

File tree

2 files changed

+106
-5
lines changed

2 files changed

+106
-5
lines changed

index.ts

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,43 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
782782

783783
const pruneRefreshTokenCollisions = (): void => {
784784
const indicesToRemove = new Set<number>();
785-
const refreshMap = new Map<string, { byOrg: Map<string, number>; fallbackIndex?: number }>();
785+
const refreshMap = new Map<
786+
string,
787+
{ byOrg: Map<string, number>; preferredOrgIndex?: number; fallbackIndex?: number }
788+
>();
789+
790+
const pickPreferredOrgIndex = (
791+
existingIndex: number | undefined,
792+
candidateIndex: number,
793+
): number => {
794+
if (existingIndex === undefined) return candidateIndex;
795+
return pickNewestAccountIndex(existingIndex, candidateIndex);
796+
};
797+
798+
const collapseFallbackIntoPreferredOrg = (entry: {
799+
byOrg: Map<string, number>;
800+
preferredOrgIndex?: number;
801+
fallbackIndex?: number;
802+
}): void => {
803+
if (entry.preferredOrgIndex === undefined || entry.fallbackIndex === undefined) {
804+
return;
805+
}
806+
807+
const preferredOrgIndex = entry.preferredOrgIndex;
808+
const fallbackIndex = entry.fallbackIndex;
809+
if (preferredOrgIndex === fallbackIndex) {
810+
entry.fallbackIndex = undefined;
811+
return;
812+
}
813+
814+
const target = accounts[preferredOrgIndex];
815+
const source = accounts[fallbackIndex];
816+
if (target && source) {
817+
mergeAccountRecords(preferredOrgIndex, fallbackIndex);
818+
indicesToRemove.add(fallbackIndex);
819+
entry.fallbackIndex = undefined;
820+
}
821+
};
786822

787823
for (let i = 0; i < accounts.length; i += 1) {
788824
const account = accounts[i];
@@ -792,7 +828,11 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
792828
const orgKey = account.organizationId?.trim() ?? "";
793829
let entry = refreshMap.get(refreshToken);
794830
if (!entry) {
795-
entry = { byOrg: new Map<string, number>(), fallbackIndex: undefined };
831+
entry = {
832+
byOrg: new Map<string, number>(),
833+
preferredOrgIndex: undefined,
834+
fallbackIndex: undefined,
835+
};
796836
refreshMap.set(refreshToken, entry);
797837
}
798838

@@ -804,9 +844,13 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
804844
mergeAccountRecords(newestIndex, obsoleteIndex);
805845
indicesToRemove.add(obsoleteIndex);
806846
entry.byOrg.set(orgKey, newestIndex);
847+
entry.preferredOrgIndex = pickPreferredOrgIndex(entry.preferredOrgIndex, newestIndex);
848+
collapseFallbackIntoPreferredOrg(entry);
807849
continue;
808850
}
809851
entry.byOrg.set(orgKey, i);
852+
entry.preferredOrgIndex = pickPreferredOrgIndex(entry.preferredOrgIndex, i);
853+
collapseFallbackIntoPreferredOrg(entry);
810854
continue;
811855
}
812856

@@ -817,9 +861,11 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
817861
mergeAccountRecords(newestIndex, obsoleteIndex);
818862
indicesToRemove.add(obsoleteIndex);
819863
entry.fallbackIndex = newestIndex;
864+
collapseFallbackIntoPreferredOrg(entry);
820865
continue;
821866
}
822867
entry.fallbackIndex = i;
868+
collapseFallbackIntoPreferredOrg(entry);
823869
}
824870

825871
if (indicesToRemove.size > 0) {
@@ -893,7 +939,13 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
893939

894940
const clampedActiveIndex = Math.max(0, Math.min(Math.floor(activeIndex), accounts.length - 1));
895941
const activeIndexByFamily: Partial<Record<ModelFamily, number>> = {};
896-
for (const family of MODEL_FAMILIES) {
942+
const familiesToPersist = replaceAll
943+
? []
944+
: MODEL_FAMILIES.filter((family) => {
945+
const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
946+
return typeof storedFamilyIndex === "number" && Number.isFinite(storedFamilyIndex);
947+
});
948+
for (const family of familiesToPersist) {
897949
const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
898950
const remappedFamilyIndex = replaceAll
899951
? undefined

lib/storage.ts

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,46 @@ function mergeAccountRecords<T extends AccountLike>(target: T, source: T): T {
412412
function deduplicateAccountsByRefreshToken<T extends AccountLike>(accounts: T[]): T[] {
413413
const working = [...accounts];
414414
const indicesToRemove = new Set<number>();
415-
const refreshMap = new Map<string, { byOrg: Map<string, number>; fallbackIndex?: number }>();
415+
const refreshMap = new Map<string, {
416+
byOrg: Map<string, number>;
417+
preferredOrgIndex?: number;
418+
fallbackIndex?: number;
419+
}>();
420+
421+
const pickPreferredOrgIndex = (
422+
existingIndex: number | undefined,
423+
candidateIndex: number,
424+
): number => {
425+
if (existingIndex === undefined) return candidateIndex;
426+
return pickNewestAccountIndex(working, existingIndex, candidateIndex);
427+
};
428+
429+
const collapseFallbackIntoPreferredOrg = (
430+
entry: {
431+
byOrg: Map<string, number>;
432+
preferredOrgIndex?: number;
433+
fallbackIndex?: number;
434+
},
435+
): void => {
436+
if (entry.preferredOrgIndex === undefined || entry.fallbackIndex === undefined) {
437+
return;
438+
}
439+
440+
const preferredOrgIndex = entry.preferredOrgIndex;
441+
const fallbackIndex = entry.fallbackIndex;
442+
if (preferredOrgIndex === fallbackIndex) {
443+
entry.fallbackIndex = undefined;
444+
return;
445+
}
446+
447+
const target = working[preferredOrgIndex];
448+
const source = working[fallbackIndex];
449+
if (target && source) {
450+
working[preferredOrgIndex] = mergeAccountRecords(target, source);
451+
indicesToRemove.add(fallbackIndex);
452+
entry.fallbackIndex = undefined;
453+
}
454+
};
416455

417456
for (let i = 0; i < working.length; i += 1) {
418457
const account = working[i];
@@ -424,7 +463,11 @@ function deduplicateAccountsByRefreshToken<T extends AccountLike>(accounts: T[])
424463

425464
let entry = refreshMap.get(refreshToken);
426465
if (!entry) {
427-
entry = { byOrg: new Map<string, number>(), fallbackIndex: undefined };
466+
entry = {
467+
byOrg: new Map<string, number>(),
468+
preferredOrgIndex: undefined,
469+
fallbackIndex: undefined,
470+
};
428471
refreshMap.set(refreshToken, entry);
429472
}
430473

@@ -440,9 +483,13 @@ function deduplicateAccountsByRefreshToken<T extends AccountLike>(accounts: T[])
440483
}
441484
indicesToRemove.add(obsoleteIndex);
442485
entry.byOrg.set(orgKey, newestIndex);
486+
entry.preferredOrgIndex = pickPreferredOrgIndex(entry.preferredOrgIndex, newestIndex);
487+
collapseFallbackIntoPreferredOrg(entry);
443488
continue;
444489
}
445490
entry.byOrg.set(orgKey, i);
491+
entry.preferredOrgIndex = pickPreferredOrgIndex(entry.preferredOrgIndex, i);
492+
collapseFallbackIntoPreferredOrg(entry);
446493
continue;
447494
}
448495

@@ -457,9 +504,11 @@ function deduplicateAccountsByRefreshToken<T extends AccountLike>(accounts: T[])
457504
}
458505
indicesToRemove.add(obsoleteIndex);
459506
entry.fallbackIndex = newestIndex;
507+
collapseFallbackIntoPreferredOrg(entry);
460508
continue;
461509
}
462510
entry.fallbackIndex = i;
511+
collapseFallbackIntoPreferredOrg(entry);
463512
}
464513

465514
const result: T[] = [];

0 commit comments

Comments
 (0)