( clientEnv: ClientEnv = env, )
| 182 | let chatGptRefreshPromise: Promise<ChatGptOAuthCredentials | null> | null = null |
| 183 | |
| 184 | export const refreshChatGptOAuthToken = async ( |
| 185 | clientEnv: ClientEnv = env, |
| 186 | ): Promise<ChatGptOAuthCredentials | null> => { |
| 187 | if (chatGptRefreshPromise) { |
| 188 | return chatGptRefreshPromise |
| 189 | } |
| 190 | |
| 191 | const credentials = getChatGptOAuthCredentials(clientEnv) |
| 192 | if (!credentials?.refreshToken) { |
| 193 | return null |
| 194 | } |
| 195 | |
| 196 | chatGptRefreshPromise = (async () => { |
| 197 | try { |
| 198 | const response = await fetch(CHATGPT_OAUTH_TOKEN_URL, { |
| 199 | method: 'POST', |
| 200 | headers: { |
| 201 | 'Content-Type': 'application/json', |
| 202 | }, |
| 203 | body: JSON.stringify({ |
| 204 | grant_type: 'refresh_token', |
| 205 | refresh_token: credentials.refreshToken, |
| 206 | client_id: CHATGPT_OAUTH_CLIENT_ID, |
| 207 | }), |
| 208 | }) |
| 209 | |
| 210 | if (!response.ok) { |
| 211 | console.debug(`ChatGPT OAuth token refresh failed (status ${response.status})`) |
| 212 | return null |
| 213 | } |
| 214 | |
| 215 | const data = await response.json() |
| 216 | |
| 217 | if ( |
| 218 | typeof data?.access_token !== 'string' || |
| 219 | data.access_token.trim().length === 0 |
| 220 | ) { |
| 221 | console.debug('ChatGPT OAuth token refresh returned empty access token') |
| 222 | return null |
| 223 | } |
| 224 | |
| 225 | const expiresIn = |
| 226 | typeof data.expires_in === 'number' ? data.expires_in * 1000 : 3600 * 1000 |
| 227 | |
| 228 | const newCredentials: ChatGptOAuthCredentials = { |
| 229 | accessToken: data.access_token, |
| 230 | refreshToken: data.refresh_token ?? credentials.refreshToken, |
| 231 | expiresAt: Date.now() + expiresIn, |
| 232 | connectedAt: credentials.connectedAt, |
| 233 | } |
| 234 | |
| 235 | saveChatGptOAuthCredentials(newCredentials, clientEnv) |
| 236 | |
| 237 | return newCredentials |
| 238 | } catch (error) { |
| 239 | console.debug('ChatGPT OAuth token refresh failed:', error instanceof Error ? error.message : String(error)) |
| 240 | return null |
| 241 | } finally { |
no test coverage detected