| import { OAuthService } from "./oauth.js"; |
| import { OPENAI_CONFIG } from "../constants/oauth.js"; |
| import { getServerCredentials } from "../config/index.js"; |
| import { spinner as createSpinner } from "../utils/ui.js"; |
|
|
| |
| |
| |
| |
| export class OpenAIService extends OAuthService { |
| constructor() { |
| super(OPENAI_CONFIG); |
| } |
|
|
| |
| |
| |
| buildOpenAIAuthUrl(redirectUri, state, codeChallenge) { |
| const params = new URLSearchParams({ |
| client_id: OPENAI_CONFIG.clientId, |
| response_type: "code", |
| redirect_uri: redirectUri, |
| scope: OPENAI_CONFIG.scope, |
| state: state, |
| code_challenge: codeChallenge, |
| code_challenge_method: OPENAI_CONFIG.codeChallengeMethod, |
| ...OPENAI_CONFIG.extraParams, |
| }); |
|
|
| return `${OPENAI_CONFIG.authorizeUrl}?${params.toString()}`; |
| } |
|
|
| |
| |
| |
| async exchangeOpenAICode(code, redirectUri, codeVerifier) { |
| const response = await fetch(OPENAI_CONFIG.tokenUrl, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/x-www-form-urlencoded", |
| Accept: "application/json", |
| }, |
| body: new URLSearchParams({ |
| grant_type: "authorization_code", |
| client_id: OPENAI_CONFIG.clientId, |
| code: code, |
| redirect_uri: redirectUri, |
| code_verifier: codeVerifier, |
| }), |
| }); |
|
|
| if (!response.ok) { |
| const error = await response.text(); |
| throw new Error(`Token exchange failed: ${error}`); |
| } |
|
|
| return await response.json(); |
| } |
|
|
| |
| |
| |
| async saveTokens(tokens) { |
| const { server, token, userId } = getServerCredentials(); |
|
|
| const response = await fetch(`${server}/api/cli/providers/openai`, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| Authorization: `Bearer ${token}`, |
| "X-User-Id": userId, |
| }, |
| body: JSON.stringify({ |
| accessToken: tokens.access_token, |
| refreshToken: tokens.refresh_token, |
| expiresIn: tokens.expires_in, |
| idToken: tokens.id_token, |
| scope: tokens.scope, |
| }), |
| }); |
|
|
| if (!response.ok) { |
| const error = await response.json(); |
| throw new Error(error.error || "Failed to save tokens"); |
| } |
|
|
| return await response.json(); |
| } |
|
|
| |
| |
| |
| async connect() { |
| const spinner = createSpinner("Starting OpenAI OAuth...").start(); |
|
|
| try { |
| spinner.text = "Starting local server..."; |
|
|
| |
| const { code, codeVerifier, redirectUri } = await this.authenticate( |
| "OpenAI", |
| this.buildOpenAIAuthUrl.bind(this) |
| ); |
|
|
| spinner.start("Exchanging code for tokens..."); |
|
|
| |
| const tokens = await this.exchangeOpenAICode(code, redirectUri, codeVerifier); |
|
|
| spinner.text = "Saving tokens to server..."; |
|
|
| |
| await this.saveTokens(tokens); |
|
|
| spinner.succeed("OpenAI connected successfully!"); |
| return true; |
| } catch (error) { |
| spinner.fail(`Failed: ${error.message}`); |
| throw error; |
| } |
| } |
| } |
|
|
|
|