| |
| |
| |
| |
| |
| |
| |
|
|
| import { CodexAuthData } from '@/lib/llm/providers/types'; |
| import { configManager } from '@/lib/config/storage'; |
|
|
| |
| |
| |
| |
| export async function connectCodex(auth: CodexAuthData): Promise<CodexAuthData> { |
| const res = await fetch('/api/auth/codex/connect', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| credentials: 'same-origin', |
| body: JSON.stringify(auth), |
| }); |
|
|
| if (!res.ok) { |
| const data = await res.json().catch(() => ({ error: 'Connect failed' })); |
| throw new Error(data.error || 'Failed to connect Codex session'); |
| } |
|
|
| |
| return res.json(); |
| } |
|
|
| |
| |
| |
| export async function disconnectCodex(): Promise<void> { |
| const res = await fetch('/api/auth/codex/disconnect', { |
| method: 'POST', |
| credentials: 'same-origin', |
| }); |
| if (!res.ok) { |
| throw new Error('Failed to clear server session'); |
| } |
| configManager.clearCodexAuth(); |
| } |
|
|
| |
| |
| |
| export async function checkCodexStatus(): Promise<boolean> { |
| const res = await fetch('/api/auth/codex/status', { |
| credentials: 'same-origin', |
| }); |
| if (!res.ok) return false; |
| const data = await res.json(); |
| return !!data.hasRefreshToken; |
| } |
|
|
| |
| |
| |
| |
| export async function refreshAccessToken(): Promise<CodexAuthData> { |
| const res = await fetch('/api/auth/codex/token', { |
| method: 'POST', |
| credentials: 'same-origin', |
| }); |
|
|
| if (!res.ok) { |
| const data = await res.json().catch(() => ({ error: 'Token refresh failed' })); |
| throw new Error(data.error || `Token refresh failed: ${res.status}`); |
| } |
|
|
| |
| return res.json(); |
| } |
|
|
| |
| |
| |
| |
| export async function ensureValidCodexToken(): Promise<string> { |
| const auth = configManager.getCodexAuth(); |
| if (!auth) { |
| throw new Error('ChatGPT session not found. Please log in via Settings.'); |
| } |
|
|
| if (!configManager.isCodexTokenExpired()) { |
| return auth.access_token; |
| } |
|
|
| |
| try { |
| const refreshed = await refreshAccessToken(); |
| configManager.setCodexAuth(refreshed); |
| return refreshed.access_token; |
| } catch { |
| configManager.clearCodexAuth(); |
| throw new Error('ChatGPT session expired. Please re-authenticate in Settings.'); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function parseCodexAuthJson(json: string): CodexAuthData { |
| const parsed = JSON.parse(json); |
|
|
| |
| const tokens = parsed.tokens || parsed; |
| const accessToken = tokens.access_token || tokens.token; |
| const refreshToken = tokens.refresh_token; |
|
|
| if (!accessToken) { |
| throw new Error('Missing access_token in pasted JSON'); |
| } |
| if (!refreshToken) { |
| throw new Error('Missing refresh_token in pasted JSON'); |
| } |
|
|
| return { |
| access_token: accessToken, |
| refresh_token: refreshToken, |
| expires_at: tokens.expires_at || parsed.expires_at || Math.floor(Date.now() / 1000) + 3600, |
| user_email: tokens.user_email || parsed.user_email || tokens.email || parsed.email, |
| }; |
| } |
|
|