UNPKG

route-claudecode

Version:

Advanced routing and transformation system for Claude Code outputs to multiple AI providers

342 lines 14.8 kB
"use strict"; /** * CodeWhisperer 增强认证管理器 * 整合多源凭据管理和智能重试机制 * 基于 AIClient-2-API 的优秀架构设计 * 项目所有者: Jason Zhang */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnhancedCodeWhispererAuth = void 0; const path = __importStar(require("path")); const os = __importStar(require("os")); const axios_1 = __importDefault(require("axios")); const logger_1 = require("@/utils/logger"); const credential_manager_1 = require("./credential-manager"); const retry_manager_1 = require("./retry-manager"); const enhanced_auth_config_1 = require("./enhanced-auth-config"); class EnhancedCodeWhispererAuth { static instance; tokenCache = null; lastTokenRead = 0; TOKEN_CACHE_TTL = 5 * 60 * 1000; // 5分钟缓存 credentialManager; retryManager; config; constructor(config = {}) { // 合并默认配置 this.config = { credentials: { ...enhanced_auth_config_1.DEFAULT_CREDENTIAL_CONFIG, ...config.credentials }, region: { ...enhanced_auth_config_1.DEFAULT_REGION_CONFIG, ...config.region }, retry: { ...enhanced_auth_config_1.DEFAULT_RETRY_CONFIG, ...config.retry }, authMethod: config.authMethod || enhanced_auth_config_1.AuthMethod.SOCIAL, userAgent: config.userAgent || 'CodeWhisperer-Router/2.7.0', enableDebugLog: config.enableDebugLog || false }; // 初始化管理器 this.credentialManager = new credential_manager_1.CredentialManager(this.config.credentials, logger_1.logger); this.retryManager = new retry_manager_1.RetryManager(this.config.retry, logger_1.logger); this.log('info', 'Enhanced CodeWhisperer Auth initialized', { region: this.config.region?.region, authMethod: this.config.authMethod, credentialSources: this.config.credentials.priorityOrder }); } static getInstance(config) { if (!EnhancedCodeWhispererAuth.instance) { EnhancedCodeWhispererAuth.instance = new EnhancedCodeWhispererAuth(config); } return EnhancedCodeWhispererAuth.instance; } /** * 重新初始化实例(用于配置更新) */ static reinitialize(config) { EnhancedCodeWhispererAuth.instance = new EnhancedCodeWhispererAuth(config); return EnhancedCodeWhispererAuth.instance; } /** * 获取访问令牌 */ async getToken() { return this.retryManager.executeWithRetry(async () => { // 检查缓存是否有效 const now = Date.now(); if (this.tokenCache && (now - this.lastTokenRead) < this.TOKEN_CACHE_TTL) { return this.tokenCache.accessToken; } // 从多源加载凭据 const credentials = await this.credentialManager.loadCredentials(); if (!credentials) { throw new Error('无法从任何配置源加载凭据。请检查配置或安装 Kiro 并登录!'); } if (!credentials.accessToken) { throw new Error('凭据中缺少 accessToken'); } // 更新缓存 this.tokenCache = credentials; this.lastTokenRead = now; this.log('debug', 'Token loaded successfully', { tokenLength: credentials.accessToken.length, hasRefreshToken: !!credentials.refreshToken, expiresAt: credentials.expiresAt, region: credentials.region }); return credentials.accessToken; }); } /** * 获取 ProfileArn */ async getProfileArn() { return this.retryManager.executeWithRetry(async () => { // 先获取token以确保缓存更新 await this.getToken(); if (this.tokenCache?.profileArn) { return this.tokenCache.profileArn; } // 如果凭据中没有profileArn,使用默认值 const defaultProfileArn = 'arn:aws:codewhisperer:us-east-1:699475941385:profile/EHGA3GRVQMUK'; this.log('warn', 'ProfileArn not found in credentials, using default', { defaultProfileArn }); return defaultProfileArn; }); } /** * 刷新访问令牌 */ async refreshToken(forceRefresh = false) { return this.retryManager.executeWithRetry(async () => { this.log('info', 'Starting token refresh...', { forceRefresh }); // 加载当前凭据 const currentCredentials = await this.credentialManager.loadCredentials(); if (!currentCredentials?.refreshToken) { throw retry_manager_1.RetryManager.createRetryableError('No refresh token available', undefined, false); } // 构建刷新URL const refreshUrl = this.buildRefreshUrl(); // 准备刷新请求 const refreshReq = { refreshToken: currentCredentials.refreshToken, }; // 根据认证方法添加额外参数 if (this.config.authMethod !== enhanced_auth_config_1.AuthMethod.SOCIAL) { refreshReq.clientId = currentCredentials.clientId; refreshReq.clientSecret = currentCredentials.clientSecret; refreshReq.grantType = 'refresh_token'; } this.log('debug', 'Sending token refresh request', { refreshUrl, authMethod: this.config.authMethod, hasClientId: !!refreshReq.clientId }); try { // 发送刷新请求 const response = await axios_1.default.post(refreshUrl, refreshReq, { headers: { 'Content-Type': 'application/json', 'User-Agent': this.config.userAgent }, timeout: this.config.retry?.timeoutMs || 120000, }); if (response.status !== 200) { throw retry_manager_1.RetryManager.createRetryableError(`Token refresh failed with status: ${response.status}`, response.status); } const newTokenData = response.data; // 保留原有的配置信息 const updatedTokenData = { ...currentCredentials, ...newTokenData, // 确保保留区域和认证方法 region: newTokenData.region || currentCredentials.region || this.config.region?.region, authMethod: newTokenData.authMethod || currentCredentials.authMethod || this.config.authMethod }; // 保存更新的凭据到默认文件 const defaultPath = path.join(os.homedir(), '.aws', 'sso', 'cache', enhanced_auth_config_1.KIRO_AUTH_TOKEN_FILE); await this.credentialManager.saveCredentialsToFile(defaultPath, updatedTokenData); // 更新缓存 this.tokenCache = updatedTokenData; this.lastTokenRead = Date.now(); this.log('info', 'Token refresh completed successfully', { newTokenLength: updatedTokenData.accessToken.length, expiresAt: updatedTokenData.expiresAt, region: updatedTokenData.region }); } catch (error) { // 转换为 RetryableError const retryableError = retry_manager_1.RetryManager.createRetryableErrorFromResponse(error, 'Token refresh request failed'); this.log('error', 'Token refresh failed', { error: error instanceof Error ? error.message : String(error), statusCode: retryableError.statusCode, isRetryable: retryableError.isRetryable }); throw retryableError; } }); } /** * 验证令牌有效性 */ async validateToken() { try { const token = await this.getToken(); // 简单验证:检查token格式和长度 if (!token || token.length < 10) { return false; } this.log('debug', 'Token validation passed', { tokenLength: token.length, }); return true; } catch (error) { this.log('warn', 'Token validation failed', { error: error instanceof Error ? error.message : String(error) }); return false; } } /** * 构建刷新URL */ buildRefreshUrl() { const region = this.config.region?.region || 'us-east-1'; if (this.config.authMethod === enhanced_auth_config_1.AuthMethod.SOCIAL) { // Social 认证使用 Kiro 刷新端点 const template = this.config.region?.refreshUrl || enhanced_auth_config_1.DEFAULT_REGION_CONFIG.refreshUrl; return template?.replace('{{region}}', region) || ''; } else { // IDC 认证使用 AWS OIDC 端点 const template = this.config.region?.refreshIDCUrl || enhanced_auth_config_1.DEFAULT_REGION_CONFIG.refreshIDCUrl; return template?.replace('{{region}}', region) || ''; } } /** * 获取当前配置 */ getConfig() { return { ...this.config }; } /** * 更新配置 */ updateConfig(newConfig) { this.config = { credentials: { ...this.config.credentials, ...newConfig.credentials }, region: { region: newConfig.region?.region || this.config.region?.region || 'us-east-1', refreshUrl: newConfig.region?.refreshUrl || this.config.region?.refreshUrl, refreshIDCUrl: newConfig.region?.refreshIDCUrl || this.config.region?.refreshIDCUrl, baseUrl: newConfig.region?.baseUrl || this.config.region?.baseUrl, amazonQUrl: newConfig.region?.amazonQUrl || this.config.region?.amazonQUrl }, retry: { maxRetries: newConfig.retry?.maxRetries || this.config.retry?.maxRetries || 3, baseDelay: newConfig.retry?.baseDelay || this.config.retry?.baseDelay || 1000, backoffMultiplier: newConfig.retry?.backoffMultiplier || this.config.retry?.backoffMultiplier || 2, retryableStatuses: newConfig.retry?.retryableStatuses || this.config.retry?.retryableStatuses || [429, 500, 502, 503, 504], timeoutMs: newConfig.retry?.timeoutMs || this.config.retry?.timeoutMs || 120000 }, authMethod: newConfig.authMethod || this.config.authMethod, userAgent: newConfig.userAgent || this.config.userAgent, enableDebugLog: newConfig.enableDebugLog !== undefined ? newConfig.enableDebugLog : this.config.enableDebugLog }; // 重新初始化管理器 this.credentialManager = new credential_manager_1.CredentialManager(this.config.credentials, logger_1.logger); this.retryManager = new retry_manager_1.RetryManager(this.config.retry, logger_1.logger); // 清除缓存以强制重新加载 this.clearCache(); this.log('info', 'Configuration updated', { region: this.config.region?.region, authMethod: this.config.authMethod }); } /** * 导出环境变量格式 */ async exportEnvVars(baseUrl = 'http://localhost:3456') { try { const token = await this.getToken(); const isWindows = process.platform === 'win32'; if (isWindows) { return [ 'REM CMD格式', `set ANTHROPIC_BASE_URL=${baseUrl}`, `set ANTHROPIC_API_KEY=${token}`, '', 'REM PowerShell格式', `$env:ANTHROPIC_BASE_URL="${baseUrl}"`, `$env:ANTHROPIC_API_KEY="${token}"`, ].join('\n'); } else { return [ `export ANTHROPIC_BASE_URL=${baseUrl}`, `export ANTHROPIC_API_KEY="${token}"`, ].join('\n'); } } catch (error) { this.log('error', 'Failed to export environment variables', { error: error instanceof Error ? error.message : String(error) }); throw error; } } /** * 清除缓存 */ clearCache() { this.tokenCache = null; this.lastTokenRead = 0; this.log('debug', 'Token cache cleared'); } /** * 日志输出方法 */ log(level, message, meta) { if (!this.config.enableDebugLog && level === 'debug') { return; } if (logger_1.logger) { logger_1.logger[level]?.(message, meta); } else { console.log(`[EnhancedCodeWhispererAuth] ${level.toUpperCase()}: ${message}`, meta || ''); } } } exports.EnhancedCodeWhispererAuth = EnhancedCodeWhispererAuth; //# sourceMappingURL=enhanced-auth-manager.js.map