fix(quotas): unifier le décompte IA (BYOK, rollback) et combler les fuites
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 6m55s
CI / Deploy production (on server) (push) Successful in 36s

Centralise la réserve via ai-quota, corrige admin unavailable (-1), brancher les routes sans quota et le host-pays brainstorm, avec usage-meter élargi, noms de clusters, MCP et ajustements dashboard/insights.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Antigravity
2026-07-15 20:42:25 +00:00
parent 30da592ba2
commit 4fe31ebc99
75 changed files with 2949 additions and 785 deletions

View File

@@ -28,6 +28,28 @@ function setCachedKey(keyHash, data) {
keyCache.set(keyHash, { data, timestamp: Date.now() });
}
async function getEffectiveTier(prisma, userId) {
if (!userId) return 'BASIC';
const sub = await prisma.subscription.findUnique({
where: { userId },
select: { tier: true, status: true, currentPeriodEnd: true },
});
if (!sub) return 'BASIC';
if (sub.status === 'ACTIVE' || sub.status === 'TRIALING') return sub.tier;
if (
(sub.status === 'PAST_DUE' || sub.status === 'CANCELED') &&
sub.currentPeriodEnd &&
new Date() < new Date(sub.currentPeriodEnd)
) {
return sub.tier;
}
return 'BASIC';
}
function isMcpTierAllowed(tier) {
return tier !== 'BASIC';
}
/**
* Generate a new API key.
* @param {import('@prisma/client').PrismaClient} prisma
@@ -111,6 +133,9 @@ export async function validateApiKey(prisma, rawKey) {
const info = JSON.parse(entry.value);
if (info.keyHash !== keyHash || !info.active) return null;
const tier = await getEffectiveTier(prisma, info.userId);
if (!isMcpTierAllowed(tier)) return null;
info.lastUsedAt = new Date().toISOString();
prisma.systemConfig.update({
where: { key: configKey },