mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 20:56:48 +00:00
refactor: standardize code formatting and linting configuration
- Replace .eslintrc.js with .eslintrc.cjs for better ES module compatibility - Add .prettierrc configuration for consistent code formatting - Update package.json with new lint and format scripts - Add nodemon.json for development hot reloading configuration - Standardize code formatting across all JavaScript and Vue files - Update web admin SPA with improved linting rules and formatting - Add prettier configuration to web admin SPA 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
* 负责存储和管理不同账号使用的 Claude Code headers
|
||||
*/
|
||||
|
||||
const redis = require('../models/redis');
|
||||
const logger = require('../utils/logger');
|
||||
const redis = require('../models/redis')
|
||||
const logger = require('../utils/logger')
|
||||
|
||||
class ClaudeCodeHeadersService {
|
||||
constructor() {
|
||||
@@ -22,8 +22,8 @@ class ClaudeCodeHeadersService {
|
||||
'user-agent': 'claude-cli/1.0.57 (external, cli)',
|
||||
'accept-language': '*',
|
||||
'sec-fetch-mode': 'cors'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// 需要捕获的 Claude Code 特定 headers
|
||||
this.claudeCodeHeaderKeys = [
|
||||
'x-stainless-retry-count',
|
||||
@@ -40,16 +40,18 @@ class ClaudeCodeHeadersService {
|
||||
'accept-language',
|
||||
'sec-fetch-mode',
|
||||
'accept-encoding'
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 user-agent 中提取版本号
|
||||
*/
|
||||
extractVersionFromUserAgent(userAgent) {
|
||||
if (!userAgent) return null;
|
||||
const match = userAgent.match(/claude-cli\/(\d+\.\d+\.\d+)/);
|
||||
return match ? match[1] : null;
|
||||
if (!userAgent) {
|
||||
return null
|
||||
}
|
||||
const match = userAgent.match(/claude-cli\/(\d+\.\d+\.\d+)/)
|
||||
return match ? match[1] : null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,43 +59,49 @@ class ClaudeCodeHeadersService {
|
||||
* @returns {number} 1 if v1 > v2, -1 if v1 < v2, 0 if equal
|
||||
*/
|
||||
compareVersions(v1, v2) {
|
||||
if (!v1 || !v2) return 0;
|
||||
|
||||
const parts1 = v1.split('.').map(Number);
|
||||
const parts2 = v2.split('.').map(Number);
|
||||
|
||||
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
||||
const p1 = parts1[i] || 0;
|
||||
const p2 = parts2[i] || 0;
|
||||
|
||||
if (p1 > p2) return 1;
|
||||
if (p1 < p2) return -1;
|
||||
if (!v1 || !v2) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
const parts1 = v1.split('.').map(Number)
|
||||
const parts2 = v2.split('.').map(Number)
|
||||
|
||||
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
||||
const p1 = parts1[i] || 0
|
||||
const p2 = parts2[i] || 0
|
||||
|
||||
if (p1 > p2) {
|
||||
return 1
|
||||
}
|
||||
if (p1 < p2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 从客户端 headers 中提取 Claude Code 相关的 headers
|
||||
*/
|
||||
extractClaudeCodeHeaders(clientHeaders) {
|
||||
const headers = {};
|
||||
|
||||
const headers = {}
|
||||
|
||||
// 转换所有 header keys 为小写进行比较
|
||||
const lowerCaseHeaders = {};
|
||||
Object.keys(clientHeaders || {}).forEach(key => {
|
||||
lowerCaseHeaders[key.toLowerCase()] = clientHeaders[key];
|
||||
});
|
||||
|
||||
const lowerCaseHeaders = {}
|
||||
Object.keys(clientHeaders || {}).forEach((key) => {
|
||||
lowerCaseHeaders[key.toLowerCase()] = clientHeaders[key]
|
||||
})
|
||||
|
||||
// 提取需要的 headers
|
||||
this.claudeCodeHeaderKeys.forEach(key => {
|
||||
const lowerKey = key.toLowerCase();
|
||||
this.claudeCodeHeaderKeys.forEach((key) => {
|
||||
const lowerKey = key.toLowerCase()
|
||||
if (lowerCaseHeaders[lowerKey]) {
|
||||
headers[key] = lowerCaseHeaders[lowerKey];
|
||||
headers[key] = lowerCaseHeaders[lowerKey]
|
||||
}
|
||||
});
|
||||
|
||||
return headers;
|
||||
})
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,48 +109,47 @@ class ClaudeCodeHeadersService {
|
||||
*/
|
||||
async storeAccountHeaders(accountId, clientHeaders) {
|
||||
try {
|
||||
const extractedHeaders = this.extractClaudeCodeHeaders(clientHeaders);
|
||||
|
||||
const extractedHeaders = this.extractClaudeCodeHeaders(clientHeaders)
|
||||
|
||||
// 检查是否有 user-agent
|
||||
const userAgent = extractedHeaders['user-agent'];
|
||||
const userAgent = extractedHeaders['user-agent']
|
||||
if (!userAgent || !userAgent.includes('claude-cli')) {
|
||||
// 不是 Claude Code 的请求,不存储
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const version = this.extractVersionFromUserAgent(userAgent);
|
||||
|
||||
const version = this.extractVersionFromUserAgent(userAgent)
|
||||
if (!version) {
|
||||
logger.warn(`⚠️ Failed to extract version from user-agent: ${userAgent}`);
|
||||
return;
|
||||
logger.warn(`⚠️ Failed to extract version from user-agent: ${userAgent}`)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 获取当前存储的 headers
|
||||
const key = `claude_code_headers:${accountId}`;
|
||||
const currentData = await redis.getClient().get(key);
|
||||
|
||||
const key = `claude_code_headers:${accountId}`
|
||||
const currentData = await redis.getClient().get(key)
|
||||
|
||||
if (currentData) {
|
||||
const current = JSON.parse(currentData);
|
||||
const currentVersion = this.extractVersionFromUserAgent(current.headers['user-agent']);
|
||||
|
||||
const current = JSON.parse(currentData)
|
||||
const currentVersion = this.extractVersionFromUserAgent(current.headers['user-agent'])
|
||||
|
||||
// 只有新版本更高时才更新
|
||||
if (this.compareVersions(version, currentVersion) <= 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 存储新的 headers
|
||||
const data = {
|
||||
headers: extractedHeaders,
|
||||
version: version,
|
||||
version,
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
await redis.getClient().setex(key, 86400 * 7, JSON.stringify(data)); // 7天过期
|
||||
|
||||
logger.info(`✅ Stored Claude Code headers for account ${accountId}, version: ${version}`);
|
||||
|
||||
}
|
||||
|
||||
await redis.getClient().setex(key, 86400 * 7, JSON.stringify(data)) // 7天过期
|
||||
|
||||
logger.info(`✅ Stored Claude Code headers for account ${accountId}, version: ${version}`)
|
||||
} catch (error) {
|
||||
logger.error(`❌ Failed to store Claude Code headers for account ${accountId}:`, error);
|
||||
logger.error(`❌ Failed to store Claude Code headers for account ${accountId}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,22 +158,23 @@ class ClaudeCodeHeadersService {
|
||||
*/
|
||||
async getAccountHeaders(accountId) {
|
||||
try {
|
||||
const key = `claude_code_headers:${accountId}`;
|
||||
const data = await redis.getClient().get(key);
|
||||
|
||||
const key = `claude_code_headers:${accountId}`
|
||||
const data = await redis.getClient().get(key)
|
||||
|
||||
if (data) {
|
||||
const parsed = JSON.parse(data);
|
||||
logger.debug(`📋 Retrieved Claude Code headers for account ${accountId}, version: ${parsed.version}`);
|
||||
return parsed.headers;
|
||||
const parsed = JSON.parse(data)
|
||||
logger.debug(
|
||||
`📋 Retrieved Claude Code headers for account ${accountId}, version: ${parsed.version}`
|
||||
)
|
||||
return parsed.headers
|
||||
}
|
||||
|
||||
|
||||
// 返回默认 headers
|
||||
logger.debug(`📋 Using default Claude Code headers for account ${accountId}`);
|
||||
return this.defaultHeaders;
|
||||
|
||||
logger.debug(`📋 Using default Claude Code headers for account ${accountId}`)
|
||||
return this.defaultHeaders
|
||||
} catch (error) {
|
||||
logger.error(`❌ Failed to get Claude Code headers for account ${accountId}:`, error);
|
||||
return this.defaultHeaders;
|
||||
logger.error(`❌ Failed to get Claude Code headers for account ${accountId}:`, error)
|
||||
return this.defaultHeaders
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,11 +183,11 @@ class ClaudeCodeHeadersService {
|
||||
*/
|
||||
async clearAccountHeaders(accountId) {
|
||||
try {
|
||||
const key = `claude_code_headers:${accountId}`;
|
||||
await redis.getClient().del(key);
|
||||
logger.info(`🗑️ Cleared Claude Code headers for account ${accountId}`);
|
||||
const key = `claude_code_headers:${accountId}`
|
||||
await redis.getClient().del(key)
|
||||
logger.info(`🗑️ Cleared Claude Code headers for account ${accountId}`)
|
||||
} catch (error) {
|
||||
logger.error(`❌ Failed to clear Claude Code headers for account ${accountId}:`, error);
|
||||
logger.error(`❌ Failed to clear Claude Code headers for account ${accountId}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,25 +196,24 @@ class ClaudeCodeHeadersService {
|
||||
*/
|
||||
async getAllAccountHeaders() {
|
||||
try {
|
||||
const pattern = 'claude_code_headers:*';
|
||||
const keys = await redis.getClient().keys(pattern);
|
||||
|
||||
const results = {};
|
||||
const pattern = 'claude_code_headers:*'
|
||||
const keys = await redis.getClient().keys(pattern)
|
||||
|
||||
const results = {}
|
||||
for (const key of keys) {
|
||||
const accountId = key.replace('claude_code_headers:', '');
|
||||
const data = await redis.getClient().get(key);
|
||||
const accountId = key.replace('claude_code_headers:', '')
|
||||
const data = await redis.getClient().get(key)
|
||||
if (data) {
|
||||
results[accountId] = JSON.parse(data);
|
||||
results[accountId] = JSON.parse(data)
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
|
||||
return results
|
||||
} catch (error) {
|
||||
logger.error('❌ Failed to get all account headers:', error);
|
||||
return {};
|
||||
logger.error('❌ Failed to get all account headers:', error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new ClaudeCodeHeadersService();
|
||||
module.exports = new ClaudeCodeHeadersService()
|
||||
|
||||
Reference in New Issue
Block a user