import { existsSync, readFileSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; const OAUTH_CREDS_PATH = join(homedir(), '.qwen', 'oauth_creds.json'); interface OAuthCreds { access_token?: unknown; expires_at?: unknown; expiry_date?: unknown; } /** * Resolved authentication configuration for Qwen API calls. * * `source` indicates which credential source won the priority resolution: * - `oauth`: Qwen Code OAuth token from ~/.qwen/oauth_creds.json * - `env`: API key from DASHSCOPE_API_KEY or QWEN_API_KEY */ export interface AuthConfig { apiKey: string; baseUrl: string; model: string; source: 'oauth' | 'env'; } /** * Resolves authentication using strict source priority: * 1) Qwen Code OAuth token from ~/.qwen/oauth_creds.json * 2) Environment API key (DASHSCOPE_API_KEY or QWEN_API_KEY) * * OAuth token is used only when `access_token` is a non-empty string and * `expires_at` (unix seconds) is in the future. * * Throws when no valid authentication source can be resolved. */ export function resolveAuth(): AuthConfig { if (existsSync(OAUTH_CREDS_PATH)) { try { const raw = readFileSync(OAUTH_CREDS_PATH, 'utf8'); const parsed = JSON.parse(raw) as OAuthCreds; const accessToken = typeof parsed.access_token === 'string' ? parsed.access_token.trim() : ''; let expiresAt: number | null = null; if (typeof parsed.expires_at === 'number' && Number.isFinite(parsed.expires_at)) { expiresAt = Math.floor(parsed.expires_at); } else if (typeof parsed.expiry_date === 'number' && Number.isFinite(parsed.expiry_date)) { expiresAt = Math.floor(parsed.expiry_date / 1000); } if (accessToken.length > 0 && expiresAt !== null) { const nowUnix = Math.floor(Date.now() / 1000); if (expiresAt > nowUnix) { return { apiKey: accessToken, baseUrl: 'https://chat.qwen.ai/api', model: 'qwen-plus', source: 'oauth', }; } console.warn('⚠️ Qwen OAuth token expired. Run: qwen auth'); } } catch { // Ignore invalid oauth_creds.json and continue to env fallback. } } const apiKey = process.env.DASHSCOPE_API_KEY ?? process.env.QWEN_API_KEY; if (typeof apiKey === 'string' && apiKey.trim().length > 0) { return { apiKey: apiKey.trim(), baseUrl: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1', model: 'qwen-plus', source: 'env', }; } throw new Error( 'No authentication found.\n' + 'Options:\n' + " 1. Run 'qwen auth' to use free Qwen OAuth (1000 req/day)\n" + ' 2. Set DASHSCOPE_API_KEY environment variable', ); }