Skip to content

Commit 9ab3669

Browse files
authored
Fix account support for mutable workspace after login (#117)
Fix account support for mutable workspace after login
2 parents f3c06f8 + 4973a20 commit 9ab3669

3 files changed

Lines changed: 293 additions & 32 deletions

File tree

lib/codex-manager.ts

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
resolveRequestAccountId,
2222
sanitizeEmail,
2323
selectBestAccountCandidate,
24+
shouldUpdateAccountIdFromToken,
2425
} from "./accounts.js";
2526
import { ACCOUNT_LIMITS } from "./constants.js";
2627
import {
@@ -905,6 +906,55 @@ function resolveAccountSelection(tokens: TokenSuccess): TokenSuccessWithAccount
905906
};
906907
}
907908

909+
function resolveStoredAccountIdentity(
910+
storedAccountId: string | undefined,
911+
storedAccountIdSource: AccountIdSource | undefined,
912+
tokenAccountId: string | undefined,
913+
): { accountId?: string; accountIdSource?: AccountIdSource } {
914+
const accountId = resolveRequestAccountId(
915+
storedAccountId,
916+
storedAccountIdSource,
917+
tokenAccountId,
918+
);
919+
if (!accountId) {
920+
return {};
921+
}
922+
923+
if (!shouldUpdateAccountIdFromToken(storedAccountIdSource, storedAccountId)) {
924+
return {
925+
accountId,
926+
accountIdSource: storedAccountIdSource,
927+
};
928+
}
929+
930+
return {
931+
accountId,
932+
accountIdSource: accountId === tokenAccountId ? "token" : storedAccountIdSource,
933+
};
934+
}
935+
936+
function applyTokenAccountIdentity(
937+
account: { accountId?: string; accountIdSource?: AccountIdSource },
938+
tokenAccountId: string | undefined,
939+
): boolean {
940+
const nextIdentity = resolveStoredAccountIdentity(
941+
account.accountId,
942+
account.accountIdSource,
943+
tokenAccountId,
944+
);
945+
if (!nextIdentity.accountId) {
946+
return false;
947+
}
948+
if (nextIdentity.accountId === account.accountId
949+
&& nextIdentity.accountIdSource === account.accountIdSource) {
950+
return false;
951+
}
952+
953+
account.accountId = nextIdentity.accountId;
954+
account.accountIdSource = nextIdentity.accountIdSource;
955+
return true;
956+
}
957+
908958
async function promptManualCallback(state: string): Promise<string | null> {
909959
if (!input.isTTY || !output.isTTY) {
910960
return null;
@@ -1567,9 +1617,7 @@ async function runHealthCheck(options: HealthCheckOptions = {}): Promise<void> {
15671617
account.email = nextEmail;
15681618
changed = true;
15691619
}
1570-
if (tokenAccountId && tokenAccountId !== account.accountId) {
1571-
account.accountId = tokenAccountId;
1572-
account.accountIdSource = "token";
1620+
if (applyTokenAccountIdentity(account, tokenAccountId)) {
15731621
changed = true;
15741622
}
15751623
if (account.enabled === false) {
@@ -2466,7 +2514,9 @@ function upsertRecoveredFlaggedAccount(
24662514
now: number,
24672515
): { restored: boolean; changed: boolean; message: string } {
24682516
const nextEmail = sanitizeEmail(extractAccountEmail(refreshResult.access, refreshResult.idToken)) ?? flagged.email;
2469-
const nextAccountId = extractAccountId(refreshResult.access) ?? flagged.accountId;
2517+
const tokenAccountId = extractAccountId(refreshResult.access);
2518+
const { accountId: nextAccountId, accountIdSource: nextAccountIdSource } =
2519+
resolveStoredAccountIdentity(flagged.accountId, flagged.accountIdSource, tokenAccountId);
24702520
const existingIndex = findExistingAccountIndexForFlagged(
24712521
storage,
24722522
flagged,
@@ -2497,9 +2547,15 @@ function upsertRecoveredFlaggedAccount(
24972547
existing.email = nextEmail;
24982548
changed = true;
24992549
}
2500-
if (nextAccountId && nextAccountId !== existing.accountId) {
2550+
if (
2551+
nextAccountId !== undefined &&
2552+
(
2553+
(nextAccountId !== existing.accountId)
2554+
|| (nextAccountIdSource !== existing.accountIdSource)
2555+
)
2556+
) {
25012557
existing.accountId = nextAccountId;
2502-
existing.accountIdSource = "token";
2558+
existing.accountIdSource = nextAccountIdSource;
25032559
changed = true;
25042560
}
25052561
if (existing.enabled === false) {
@@ -2531,7 +2587,7 @@ function upsertRecoveredFlaggedAccount(
25312587
accessToken: refreshResult.access,
25322588
expiresAt: refreshResult.expires,
25332589
accountId: nextAccountId,
2534-
accountIdSource: nextAccountId ? "token" : flagged.accountIdSource,
2590+
accountIdSource: nextAccountIdSource,
25352591
accountLabel: flagged.accountLabel,
25362592
email: nextEmail,
25372593
addedAt: flagged.addedAt ?? now,
@@ -2617,13 +2673,19 @@ async function runVerifyFlagged(args: string[]): Promise<number> {
26172673
const { index: i, flagged, label, result } = check;
26182674
if (result.type === "success") {
26192675
if (!options.restore) {
2676+
const tokenAccountId = extractAccountId(result.access);
2677+
const nextIdentity = resolveStoredAccountIdentity(
2678+
flagged.accountId,
2679+
flagged.accountIdSource,
2680+
tokenAccountId,
2681+
);
26202682
const nextFlagged: FlaggedAccountMetadataV1 = {
26212683
...flagged,
26222684
refreshToken: result.refresh,
26232685
accessToken: result.access,
26242686
expiresAt: result.expires,
2625-
accountId: extractAccountId(result.access) ?? flagged.accountId,
2626-
accountIdSource: extractAccountId(result.access) ? "token" : flagged.accountIdSource,
2687+
accountId: nextIdentity.accountId,
2688+
accountIdSource: nextIdentity.accountIdSource,
26272689
email: sanitizeEmail(extractAccountEmail(result.access, result.idToken)) ?? flagged.email,
26282690
lastUsed: now,
26292691
lastError: undefined,
@@ -2654,13 +2716,19 @@ async function runVerifyFlagged(args: string[]): Promise<number> {
26542716
continue;
26552717
}
26562718

2719+
const tokenAccountId = extractAccountId(result.access);
2720+
const nextIdentity = resolveStoredAccountIdentity(
2721+
flagged.accountId,
2722+
flagged.accountIdSource,
2723+
tokenAccountId,
2724+
);
26572725
const updatedFlagged: FlaggedAccountMetadataV1 = {
26582726
...flagged,
26592727
refreshToken: result.refresh,
26602728
accessToken: result.access,
26612729
expiresAt: result.expires,
2662-
accountId: extractAccountId(result.access) ?? flagged.accountId,
2663-
accountIdSource: extractAccountId(result.access) ? "token" : flagged.accountIdSource,
2730+
accountId: nextIdentity.accountId,
2731+
accountIdSource: nextIdentity.accountIdSource,
26642732
email: sanitizeEmail(extractAccountEmail(result.access, result.idToken)) ?? flagged.email,
26652733
lastUsed: now,
26662734
lastError: upsertResult.message,
@@ -3613,10 +3681,7 @@ async function runDoctor(args: string[]): Promise<number> {
36133681
activeAccount.refreshToken = refreshResult.refresh;
36143682
activeAccount.expiresAt = refreshResult.expires;
36153683
if (refreshedEmail) activeAccount.email = refreshedEmail;
3616-
if (refreshedAccountId) {
3617-
activeAccount.accountId = refreshedAccountId;
3618-
activeAccount.accountIdSource = "token";
3619-
}
3684+
applyTokenAccountIdentity(activeAccount, refreshedAccountId);
36203685
syncAccessToken = refreshResult.access;
36213686
syncRefreshToken = refreshResult.refresh;
36223687
syncExpiresAt = refreshResult.expires;
@@ -4007,10 +4072,7 @@ async function runSwitch(args: string[]): Promise<number> {
40074072
if (nextEmail && nextEmail !== account.email) {
40084073
account.email = nextEmail;
40094074
}
4010-
if (tokenAccountId && tokenAccountId !== account.accountId) {
4011-
account.accountId = tokenAccountId;
4012-
account.accountIdSource = "token";
4013-
}
4075+
applyTokenAccountIdentity(account, tokenAccountId);
40144076
syncAccessToken = refreshResult.access;
40154077
syncRefreshToken = refreshResult.refresh;
40164078
syncExpiresAt = refreshResult.expires;
@@ -4091,9 +4153,7 @@ export async function autoSyncActiveAccountToCodex(): Promise<boolean> {
40914153
account.email = nextEmail;
40924154
changed = true;
40934155
}
4094-
if (tokenAccountId && tokenAccountId !== account.accountId) {
4095-
account.accountId = tokenAccountId;
4096-
account.accountIdSource = "token";
4156+
if (applyTokenAccountIdentity(account, tokenAccountId)) {
40974157
changed = true;
40984158
}
40994159
syncAccessToken = refreshResult.access;

lib/storage.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,7 @@ function findCompatibleRefreshTokenMatchIndex<T extends AccountLike>(
11661166
matchingAccount = account;
11671167
continue;
11681168
}
1169-
const newest = selectNewestAccount(matchingAccount, account);
1169+
const newest: T = selectNewestAccount(matchingAccount ?? undefined, account);
11701170
if (newest === account) {
11711171
matchingIndex = i;
11721172
matchingAccount = account;
@@ -1939,6 +1939,7 @@ export async function withAccountAndFlaggedStorageTransaction<T>(
19391939
return withStorageLock(async () => {
19401940
const state = {
19411941
snapshot: await loadAccountsInternal(saveAccountsUnlocked),
1942+
active: true,
19421943
};
19431944
const current = state.snapshot;
19441945
const persist = async (

0 commit comments

Comments
 (0)