Skip to content

Commit cd2375f

Browse files
committed
refactor: extract runtime email hydration
1 parent 0a48d42 commit cd2375f

2 files changed

Lines changed: 104 additions & 69 deletions

File tree

index.ts

Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ import {
183183
import { buildCapabilityBoostByAccount } from "./lib/runtime/capability-boost.js";
184184
import { createRuntimeEventHandler } from "./lib/runtime/event-handler.js";
185185
import { createFlaggedVerificationState } from "./lib/runtime/flagged-verify-types.js";
186+
import { hydrateRuntimeEmails } from "./lib/runtime/hydrate-emails.js";
186187
import { ensureRuntimeLiveAccountSync } from "./lib/runtime/live-sync.js";
187188
import { buildManualOAuthFlow } from "./lib/runtime/manual-oauth-flow.js";
188189
import {
@@ -346,75 +347,17 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
346347

347348
const hydrateEmails = async (
348349
storage: AccountStorageV3 | null,
349-
): Promise<AccountStorageV3 | null> => {
350-
if (!storage) return storage;
351-
const skipHydrate =
352-
process.env.VITEST_WORKER_ID !== undefined ||
353-
process.env.NODE_ENV === "test" ||
354-
process.env.CODEX_SKIP_EMAIL_HYDRATE === "1";
355-
if (skipHydrate) return storage;
356-
357-
const accountsCopy = storage.accounts.map((account) =>
358-
account ? { ...account } : account,
359-
);
360-
const accountsToHydrate = accountsCopy.filter(
361-
(account) => account && !account.email,
362-
);
363-
if (accountsToHydrate.length === 0) return storage;
364-
365-
let changed = false;
366-
await Promise.all(
367-
accountsToHydrate.map(async (account) => {
368-
try {
369-
const refreshed = await queuedRefresh(account.refreshToken);
370-
if (refreshed.type !== "success") return;
371-
const id = extractAccountId(refreshed.access);
372-
const email = sanitizeEmail(
373-
extractAccountEmail(refreshed.access, refreshed.idToken),
374-
);
375-
if (
376-
id &&
377-
id !== account.accountId &&
378-
shouldUpdateAccountIdFromToken(
379-
account.accountIdSource,
380-
account.accountId,
381-
)
382-
) {
383-
account.accountId = id;
384-
account.accountIdSource = "token";
385-
changed = true;
386-
}
387-
if (email && email !== account.email) {
388-
account.email = email;
389-
changed = true;
390-
}
391-
if (refreshed.access && refreshed.access !== account.accessToken) {
392-
account.accessToken = refreshed.access;
393-
changed = true;
394-
}
395-
if (
396-
typeof refreshed.expires === "number" &&
397-
refreshed.expires !== account.expiresAt
398-
) {
399-
account.expiresAt = refreshed.expires;
400-
changed = true;
401-
}
402-
if (refreshed.refresh && refreshed.refresh !== account.refreshToken) {
403-
account.refreshToken = refreshed.refresh;
404-
changed = true;
405-
}
406-
} catch {
407-
logWarn(`[${PLUGIN_NAME}] Failed to hydrate email for account`);
408-
}
409-
}),
410-
);
411-
412-
if (changed) {
413-
storage.accounts = accountsCopy;
414-
await saveAccounts(storage);
415-
}
416-
return storage;
417-
};
350+
): Promise<AccountStorageV3 | null> =>
351+
hydrateRuntimeEmails(storage, {
352+
queuedRefresh,
353+
extractAccountId,
354+
sanitizeEmail,
355+
extractAccountEmail,
356+
shouldUpdateAccountIdFromToken,
357+
saveAccounts,
358+
logWarn,
359+
pluginName: PLUGIN_NAME,
360+
});
418361

419362
const applyUiRuntimeFromConfig = (
420363
pluginConfig: ReturnType<typeof loadPluginConfig>,

lib/runtime/hydrate-emails.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import type { AccountStorageV3 } from "../storage.js";
2+
import type { AccountIdSource, TokenResult } from "../types.js";
3+
4+
export async function hydrateRuntimeEmails(
5+
storage: AccountStorageV3 | null,
6+
deps: {
7+
queuedRefresh: (refreshToken: string) => Promise<TokenResult>;
8+
extractAccountId: (accessToken: string | undefined) => string | undefined;
9+
sanitizeEmail: (email: string | undefined) => string | undefined;
10+
extractAccountEmail: (
11+
accessToken: string | undefined,
12+
idToken?: string | undefined,
13+
) => string | undefined;
14+
shouldUpdateAccountIdFromToken: (
15+
accountIdSource: AccountIdSource | undefined,
16+
accountId: string | undefined,
17+
) => boolean;
18+
saveAccounts: (storage: AccountStorageV3) => Promise<void>;
19+
logWarn: (message: string) => void;
20+
pluginName: string;
21+
},
22+
): Promise<AccountStorageV3 | null> {
23+
if (!storage) return storage;
24+
const skipHydrate =
25+
process.env.VITEST_WORKER_ID !== undefined ||
26+
process.env.NODE_ENV === "test" ||
27+
process.env.CODEX_SKIP_EMAIL_HYDRATE === "1";
28+
if (skipHydrate) return storage;
29+
30+
const accountsCopy = storage.accounts.map((account) =>
31+
account ? { ...account } : account,
32+
);
33+
const accountsToHydrate = accountsCopy.filter(
34+
(account) => account && !account.email,
35+
);
36+
if (accountsToHydrate.length === 0) return storage;
37+
38+
let changed = false;
39+
await Promise.all(
40+
accountsToHydrate.map(async (account) => {
41+
try {
42+
const refreshed = await deps.queuedRefresh(account.refreshToken);
43+
if (refreshed.type !== "success") return;
44+
const id = deps.extractAccountId(refreshed.access);
45+
const email = deps.sanitizeEmail(
46+
deps.extractAccountEmail(refreshed.access, refreshed.idToken),
47+
);
48+
if (
49+
id &&
50+
id !== account.accountId &&
51+
deps.shouldUpdateAccountIdFromToken(
52+
account.accountIdSource,
53+
account.accountId,
54+
)
55+
) {
56+
account.accountId = id;
57+
account.accountIdSource = "token";
58+
changed = true;
59+
}
60+
if (email && email !== account.email) {
61+
account.email = email;
62+
changed = true;
63+
}
64+
if (refreshed.access && refreshed.access !== account.accessToken) {
65+
account.accessToken = refreshed.access;
66+
changed = true;
67+
}
68+
if (
69+
typeof refreshed.expires === "number" &&
70+
refreshed.expires !== account.expiresAt
71+
) {
72+
account.expiresAt = refreshed.expires;
73+
changed = true;
74+
}
75+
if (refreshed.refresh && refreshed.refresh !== account.refreshToken) {
76+
account.refreshToken = refreshed.refresh;
77+
changed = true;
78+
}
79+
} catch {
80+
deps.logWarn(
81+
`[${deps.pluginName}] Failed to hydrate email for account`,
82+
);
83+
}
84+
}),
85+
);
86+
87+
if (changed) {
88+
storage.accounts = accountsCopy;
89+
await deps.saveAccounts(storage);
90+
}
91+
return storage;
92+
}

0 commit comments

Comments
 (0)