Merge remote-tracking branch 'origin/master' into gitea/feature/end

Resolved conflicts taking origin/master (v0.5.55) as canonical, with local
features re-applied:
- runtime log level (LOG_LEVEL env + dashboard Settings → Logging, applied
  immediately and persisted across restarts)
- free/noAuth provider enable/disable toggle via providerStrategies.enabled
- parallel model testing (Test All Models / Test Selected Keys)
This commit is contained in:
2026-08-17 00:38:31 +07:00
parent e7470e955e
commit 7e45ead2ac
557 changed files with 53396 additions and 6935 deletions

View File

@@ -19,7 +19,43 @@ const CLAUDE_CONFIG = {
const OAUTH_429_COOLDOWN_MS = 180000;
const oauthCooldown = new Map();
export async function getClaudeUsage(accessToken, proxyOptions = null) {
// Dedup + short TTL cache per access token. Many tabs / many accounts / auto-refresh
// all funnel through here; without this each call hits Anthropic and triggers 429.
const USAGE_CACHE_TTL_MS = 300000;
const usageCache = new Map(); // token -> { promise } | { result, expiresAt }
export async function getClaudeUsage(accessToken, proxyOptions = null, options = {}) {
const force = options?.force === true;
// Serve in-flight or fresh cached result (skip on manual force)
if (!force && accessToken) {
const hit = usageCache.get(accessToken);
if (hit?.promise) return hit.promise;
if (hit && hit.expiresAt > Date.now()) return hit.result;
}
const stale = (!force && accessToken && usageCache.get(accessToken)?.result) || null;
const promise = (async () => {
const result = await fetchClaudeUsageRaw(accessToken, proxyOptions);
// Only cache real quota data, not soft-failure {message: ...} payloads
if (accessToken && result?.quotas) {
usageCache.set(accessToken, {
result,
expiresAt: Date.now() + USAGE_CACHE_TTL_MS,
});
return result;
}
// Soft failure (429/error): prefer the last good read over a transient error
if (stale) return stale;
return result;
})();
if (accessToken) usageCache.set(accessToken, { promise });
return promise;
}
async function fetchClaudeUsageRaw(accessToken, proxyOptions = null) {
try {
// Skip OAuth usage call while this token is cooling down from a recent 429
const cooldownUntil = oauthCooldown.get(accessToken);