route-claudecode
Version:
Advanced routing and transformation system for Claude Code outputs to multiple AI providers
342 lines • 14.8 kB
JavaScript
"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