feat(api-key): add independent quota and expiration support
This feature allows API Keys to have their own quota limits and expiration times, independent of the user's balance. Backend: - Add quota, quota_used, expires_at fields to api_key schema - Implement IsExpired() and IsQuotaExhausted() checks in middleware - Add ResetQuota and ClearExpiration API endpoints - Integrate quota billing in gateway handlers (OpenAI, Anthropic, Gemini) - Include quota/expiration fields in auth cache for performance - Expiration check returns 403, quota exhausted returns 429 Frontend: - Add quota and expiration inputs to key create/edit dialog - Add quick-select buttons for expiration (+7, +30, +90 days) - Add reset quota confirmation dialog - Add expires_at column to keys list - Add i18n translations for new features (en/zh) Migration: - Add 045_add_api_key_quota.sql for new columns
This commit is contained in:
@@ -44,6 +44,8 @@ export async function getById(id: number): Promise<ApiKey> {
|
||||
* @param customKey - Optional custom key value
|
||||
* @param ipWhitelist - Optional IP whitelist
|
||||
* @param ipBlacklist - Optional IP blacklist
|
||||
* @param quota - Optional quota limit in USD (0 = unlimited)
|
||||
* @param expiresInDays - Optional days until expiry (undefined = never expires)
|
||||
* @returns Created API key
|
||||
*/
|
||||
export async function create(
|
||||
@@ -51,7 +53,9 @@ export async function create(
|
||||
groupId?: number | null,
|
||||
customKey?: string,
|
||||
ipWhitelist?: string[],
|
||||
ipBlacklist?: string[]
|
||||
ipBlacklist?: string[],
|
||||
quota?: number,
|
||||
expiresInDays?: number
|
||||
): Promise<ApiKey> {
|
||||
const payload: CreateApiKeyRequest = { name }
|
||||
if (groupId !== undefined) {
|
||||
@@ -66,6 +70,12 @@ export async function create(
|
||||
if (ipBlacklist && ipBlacklist.length > 0) {
|
||||
payload.ip_blacklist = ipBlacklist
|
||||
}
|
||||
if (quota !== undefined && quota > 0) {
|
||||
payload.quota = quota
|
||||
}
|
||||
if (expiresInDays !== undefined && expiresInDays > 0) {
|
||||
payload.expires_in_days = expiresInDays
|
||||
}
|
||||
|
||||
const { data } = await apiClient.post<ApiKey>('/keys', payload)
|
||||
return data
|
||||
|
||||
Reference in New Issue
Block a user