fix(quotas): unifier le décompte IA (BYOK, rollback) et combler les fuites
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:
35
memento-note/lib/mcp-access.ts
Normal file
35
memento-note/lib/mcp-access.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { getEffectiveTier, QuotaExceededError } from '@/lib/entitlements'
|
||||
import { reserveAiUsageOrThrow } from '@/lib/ai-quota'
|
||||
import type { SubscriptionTier } from '@/lib/plan-entitlements'
|
||||
import type { FeatureName } from '@/lib/quota-utils'
|
||||
|
||||
/** MCP (clés API + outils externes) réservé aux plans payants + 1 unité chat par invocation. */
|
||||
export function isMcpTierAllowed(tier: SubscriptionTier): boolean {
|
||||
return tier !== 'BASIC'
|
||||
}
|
||||
|
||||
export class McpTierLimitedError extends Error {
|
||||
code = 'MCP_TIER_LIMITED' as const
|
||||
|
||||
constructor(public tier: SubscriptionTier) {
|
||||
super('MCP requires a Pro plan or higher')
|
||||
}
|
||||
}
|
||||
|
||||
export async function assertMcpAccess(userId: string): Promise<SubscriptionTier> {
|
||||
const tier = await getEffectiveTier(userId)
|
||||
if (!isMcpTierAllowed(tier)) {
|
||||
throw new McpTierLimitedError(tier)
|
||||
}
|
||||
return tier
|
||||
}
|
||||
|
||||
/** Tier gate + monthly chat quota (MCP tool calls bill like chat). */
|
||||
export async function assertMcpAccessWithQuota(
|
||||
userId: string,
|
||||
feature: FeatureName = 'chat',
|
||||
): Promise<SubscriptionTier> {
|
||||
const tier = await assertMcpAccess(userId)
|
||||
await reserveAiUsageOrThrow(userId, feature, { lane: 'chat' })
|
||||
return tier
|
||||
}
|
||||
Reference in New Issue
Block a user