()
| 128 | } |
| 129 | |
| 130 | export async function tryLoadExistingCredential(): Promise<ExistingCodexCredential | null> { |
| 131 | const authFile = await readCodexAuthFile() |
| 132 | if (!authFile) return null |
| 133 | |
| 134 | const tokens = authFile.tokens ?? undefined |
| 135 | const idTokenString = extractIdToken(tokens?.id_token) |
| 136 | if (tokens && idTokenString && tokens.access_token && tokens.refresh_token) { |
| 137 | const idTokenInfo = parseIdToken(idTokenString) |
| 138 | return { |
| 139 | type: "codex", |
| 140 | accessToken: tokens.access_token, |
| 141 | refreshToken: tokens.refresh_token, |
| 142 | idToken: idTokenString, |
| 143 | accountId: tokens.account_id ?? idTokenInfo?.chatgpt_account_id ?? undefined, |
| 144 | email: idTokenInfo?.email, |
| 145 | planType: idTokenInfo?.chatgpt_plan_type, |
| 146 | // Force a refresh on the first API call so we don't operate on potentially stale tokens. |
| 147 | expiresAt: Date.now() - 60 * 1000, |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | if (authFile.OPENAI_API_KEY) { |
| 152 | return { |
| 153 | type: "api", |
| 154 | key: authFile.OPENAI_API_KEY, |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | return null |
| 159 | } |
| 160 | |
| 161 | function parseIdToken(idToken: string): IdTokenInfo | null { |
| 162 | try { |
nothing calls this directly
no test coverage detected