@@ -122,7 +122,6 @@ import {
122122 getCodexInstructions ,
123123 getModelFamily ,
124124 MODEL_FAMILIES ,
125- type ModelFamily ,
126125 prewarmCodexInstructions ,
127126} from "./lib/prompts/codex.js" ;
128127import { prewarmHostCodexPrompt } from "./lib/prompts/host-codex-prompt.js" ;
@@ -161,6 +160,7 @@ import { applyFastSessionDefaults } from "./lib/request/request-transformer.js";
161160import { isEmptyResponse } from "./lib/request/response-handler.js" ;
162161import { withStreamingFailover } from "./lib/request/stream-failover.js" ;
163162import { addJitter } from "./lib/rotation.js" ;
163+ import { persistAccountPool } from "./lib/runtime/account-pool.js" ;
164164import {
165165 resolveAccountSelection ,
166166 type TokenSuccessWithAccount ,
@@ -292,182 +292,18 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
292292 logWarn : ( message ) => logWarn ( `[${ PLUGIN_NAME } ] ${ message } ` ) ,
293293 } ) ;
294294
295- const persistAccountPool = async (
295+ const persistAccounts = async (
296296 results : TokenSuccessWithAccount [ ] ,
297297 replaceAll : boolean = false ,
298- ) : Promise < void > => {
299- if ( results . length === 0 ) return ;
300- await withAccountStorageTransaction ( async ( loadedStorage , persist ) => {
301- const now = Date . now ( ) ;
302- const stored = replaceAll ? null : loadedStorage ;
303- const accounts = stored ?. accounts ? [ ...stored . accounts ] : [ ] ;
304-
305- for ( const result of results ) {
306- const accountId =
307- result . accountIdOverride ?? extractAccountId ( result . access ) ;
308- const accountIdSource = accountId
309- ? ( result . accountIdSource ??
310- ( result . accountIdOverride ? "manual" : "token" ) )
311- : undefined ;
312- const accountLabel = result . accountLabel ;
313- const accountEmail = sanitizeEmail (
314- extractAccountEmail ( result . access , result . idToken ) ,
315- ) ;
316- const existingIndex = findMatchingAccountIndex (
317- accounts ,
318- {
319- accountId,
320- email : accountEmail ,
321- refreshToken : result . refresh ,
322- } ,
323- {
324- allowUniqueAccountIdFallbackWithoutEmail : true ,
325- } ,
326- ) ;
327-
328- if ( existingIndex === undefined ) {
329- const initialWorkspaceIndex =
330- result . workspaces && result . workspaces . length > 0
331- ? ( ( ) => {
332- if ( accountId ) {
333- const matchingWorkspaceIndex = result . workspaces . findIndex (
334- ( workspace ) => workspace . id === accountId ,
335- ) ;
336- if ( matchingWorkspaceIndex >= 0 ) {
337- return matchingWorkspaceIndex ;
338- }
339- }
340- const firstEnabledWorkspaceIndex =
341- result . workspaces . findIndex (
342- ( workspace ) => workspace . enabled !== false ,
343- ) ;
344- return firstEnabledWorkspaceIndex >= 0
345- ? firstEnabledWorkspaceIndex
346- : 0 ;
347- } ) ( )
348- : undefined ;
349- accounts . push ( {
350- accountId,
351- accountIdSource,
352- accountLabel,
353- email : accountEmail ,
354- refreshToken : result . refresh ,
355- accessToken : result . access ,
356- expiresAt : result . expires ,
357- addedAt : now ,
358- lastUsed : now ,
359- workspaces : result . workspaces ,
360- currentWorkspaceIndex : initialWorkspaceIndex ,
361- } ) ;
362- continue ;
363- }
364-
365- const existing = accounts [ existingIndex ] ;
366- if ( ! existing ) continue ;
367-
368- const nextEmail = accountEmail ?? sanitizeEmail ( existing . email ) ;
369- const nextAccountId = accountId ?? existing . accountId ;
370- const nextAccountIdSource = accountId
371- ? ( accountIdSource ?? existing . accountIdSource )
372- : existing . accountIdSource ;
373- const nextAccountLabel = accountLabel ?? existing . accountLabel ;
374- // Preserve tracked workspace state when auth refreshes do not return workspace metadata.
375- const mergedWorkspaces = result . workspaces
376- ? result . workspaces . map ( ( newWs ) => {
377- const existingWs = existing . workspaces ?. find (
378- ( w ) => w . id === newWs . id ,
379- ) ;
380- return existingWs
381- ? {
382- ...newWs ,
383- enabled : existingWs . enabled ,
384- disabledAt : existingWs . disabledAt ,
385- }
386- : newWs ;
387- } )
388- : existing . workspaces ;
389- const currentWorkspaceId =
390- existing . workspaces ?. [
391- typeof existing . currentWorkspaceIndex === "number"
392- ? existing . currentWorkspaceIndex
393- : 0
394- ] ?. id ;
395- const nextCurrentWorkspaceIndex =
396- mergedWorkspaces && mergedWorkspaces . length > 0
397- ? ( ( ) => {
398- if ( currentWorkspaceId ) {
399- const matchingWorkspaceIndex = mergedWorkspaces . findIndex (
400- ( workspace ) => workspace . id === currentWorkspaceId ,
401- ) ;
402- if ( matchingWorkspaceIndex >= 0 ) {
403- return matchingWorkspaceIndex ;
404- }
405- }
406- const defaultWorkspaceIndex = mergedWorkspaces . findIndex (
407- ( workspace ) => workspace . isDefault === true ,
408- ) ;
409- if ( defaultWorkspaceIndex >= 0 ) {
410- return defaultWorkspaceIndex ;
411- }
412- const firstEnabledWorkspaceIndex = mergedWorkspaces . findIndex (
413- ( workspace ) => workspace . enabled !== false ,
414- ) ;
415- return firstEnabledWorkspaceIndex >= 0
416- ? firstEnabledWorkspaceIndex
417- : 0 ;
418- } ) ( )
419- : existing . currentWorkspaceIndex ;
420- accounts [ existingIndex ] = {
421- ...existing ,
422- accountId : nextAccountId ,
423- accountIdSource : nextAccountIdSource ,
424- accountLabel : nextAccountLabel ,
425- email : nextEmail ,
426- refreshToken : result . refresh ,
427- accessToken : result . access ,
428- expiresAt : result . expires ,
429- lastUsed : now ,
430- workspaces : mergedWorkspaces ,
431- currentWorkspaceIndex : nextCurrentWorkspaceIndex ,
432- } ;
433- }
434-
435- if ( accounts . length === 0 ) return ;
436-
437- const activeIndex = replaceAll
438- ? 0
439- : typeof stored ?. activeIndex === "number" &&
440- Number . isFinite ( stored . activeIndex )
441- ? stored . activeIndex
442- : 0 ;
443-
444- const clampedActiveIndex = Math . max (
445- 0 ,
446- Math . min ( activeIndex , accounts . length - 1 ) ,
447- ) ;
448- const activeIndexByFamily : Partial < Record < ModelFamily , number > > = { } ;
449- for ( const family of MODEL_FAMILIES ) {
450- const storedFamilyIndex = stored ?. activeIndexByFamily ?. [ family ] ;
451- const rawFamilyIndex = replaceAll
452- ? 0
453- : typeof storedFamilyIndex === "number" &&
454- Number . isFinite ( storedFamilyIndex )
455- ? storedFamilyIndex
456- : clampedActiveIndex ;
457- activeIndexByFamily [ family ] = Math . max (
458- 0 ,
459- Math . min ( Math . floor ( rawFamilyIndex ) , accounts . length - 1 ) ,
460- ) ;
461- }
462-
463- await persist ( {
464- version : 3 ,
465- accounts,
466- activeIndex : clampedActiveIndex ,
467- activeIndexByFamily,
468- } ) ;
298+ ) : Promise < void > =>
299+ persistAccountPool ( results , replaceAll , {
300+ withAccountStorageTransaction,
301+ extractAccountId,
302+ extractAccountEmail,
303+ sanitizeEmail,
304+ findMatchingAccountIndex,
305+ MODEL_FAMILIES ,
469306 } ) ;
470- } ;
471307
472308 const showToast = async (
473309 message : string ,
@@ -3485,7 +3321,7 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
34853321 }
34863322
34873323 if ( restored . length > 0 ) {
3488- await persistAccountPool ( restored , false ) ;
3324+ await persistAccounts ( restored , false ) ;
34893325 invalidateAccountManagerCache ( ) ;
34903326 }
34913327
@@ -3710,7 +3546,7 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
37103546 logInfo,
37113547 onSuccess : async ( tokens : TokenSuccessWithAccount ) => {
37123548 try {
3713- await persistAccountPool ( [ tokens ] , startFresh ) ;
3549+ await persistAccounts ( [ tokens ] , startFresh ) ;
37143550 invalidateAccountManagerCache ( ) ;
37153551 } catch ( err ) {
37163552 const storagePath = getStoragePath ( ) ;
@@ -3814,10 +3650,7 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
38143650
38153651 try {
38163652 const isFirstAccount = accounts . length === 1 ;
3817- await persistAccountPool (
3818- [ resolved ] ,
3819- isFirstAccount && startFresh ,
3820- ) ;
3653+ await persistAccounts ( [ resolved ] , isFirstAccount && startFresh ) ;
38213654 invalidateAccountManagerCache ( ) ;
38223655 } catch ( err ) {
38233656 const storagePath = getStoragePath ( ) ;
@@ -3905,7 +3738,7 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
39053738 logInfo,
39063739 onSuccess : async ( tokens : TokenSuccessWithAccount ) => {
39073740 try {
3908- await persistAccountPool ( [ tokens ] , false ) ;
3741+ await persistAccounts ( [ tokens ] , false ) ;
39093742 } catch ( err ) {
39103743 const storagePath = getStoragePath ( ) ;
39113744 const errorCode =
0 commit comments