* feat(api-key): add IP whitelist/blacklist restriction and usage log IP tracking - Add IP restriction feature for API keys (whitelist/blacklist with CIDR support) - Add IP address logging to usage logs (admin-only visibility) - Remove billing_type column from usage logs UI (redundant) - Use generic "Access denied" error message for security Backend: - New ip package with IP/CIDR validation and matching utilities - Database migrations for ip_whitelist, ip_blacklist (api_keys) and ip_address (usage_logs) - Middleware IP restriction check after API key validation - Input validation for IP/CIDR patterns on create/update Frontend: - API key form with enable toggle for IP restriction - Shield icon indicator in table for keys with IP restriction - Removed billing_type filter and column from usage views * fix: update API contract tests for ip_whitelist/ip_blacklist fields Add ip_whitelist and ip_blacklist fields to expected JSON responses in API contract tests to match the new API key schema.
118 lines
2.8 KiB
TypeScript
118 lines
2.8 KiB
TypeScript
/**
|
|
* Admin Usage API endpoints
|
|
* Handles admin-level usage logs and statistics retrieval
|
|
*/
|
|
|
|
import { apiClient } from '../client'
|
|
import type { UsageLog, UsageQueryParams, PaginatedResponse } from '@/types'
|
|
|
|
// ==================== Types ====================
|
|
|
|
export interface AdminUsageStatsResponse {
|
|
total_requests: number
|
|
total_input_tokens: number
|
|
total_output_tokens: number
|
|
total_cache_tokens: number
|
|
total_tokens: number
|
|
total_cost: number
|
|
total_actual_cost: number
|
|
average_duration_ms: number
|
|
}
|
|
|
|
export interface SimpleUser {
|
|
id: number
|
|
email: string
|
|
}
|
|
|
|
export interface SimpleApiKey {
|
|
id: number
|
|
name: string
|
|
user_id: number
|
|
}
|
|
|
|
export interface AdminUsageQueryParams extends UsageQueryParams {
|
|
user_id?: number
|
|
}
|
|
|
|
// ==================== API Functions ====================
|
|
|
|
/**
|
|
* List all usage logs with optional filters (admin only)
|
|
* @param params - Query parameters for filtering and pagination
|
|
* @returns Paginated list of usage logs
|
|
*/
|
|
export async function list(
|
|
params: AdminUsageQueryParams,
|
|
options?: { signal?: AbortSignal }
|
|
): Promise<PaginatedResponse<UsageLog>> {
|
|
const { data } = await apiClient.get<PaginatedResponse<UsageLog>>('/admin/usage', {
|
|
params,
|
|
signal: options?.signal
|
|
})
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Get usage statistics with optional filters (admin only)
|
|
* @param params - Query parameters for filtering
|
|
* @returns Usage statistics
|
|
*/
|
|
export async function getStats(params: {
|
|
user_id?: number
|
|
api_key_id?: number
|
|
account_id?: number
|
|
group_id?: number
|
|
model?: string
|
|
stream?: boolean
|
|
period?: string
|
|
start_date?: string
|
|
end_date?: string
|
|
timezone?: string
|
|
}): Promise<AdminUsageStatsResponse> {
|
|
const { data } = await apiClient.get<AdminUsageStatsResponse>('/admin/usage/stats', {
|
|
params
|
|
})
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Search users by email keyword (admin only)
|
|
* @param keyword - Email keyword to search
|
|
* @returns List of matching users (max 30)
|
|
*/
|
|
export async function searchUsers(keyword: string): Promise<SimpleUser[]> {
|
|
const { data } = await apiClient.get<SimpleUser[]>('/admin/usage/search-users', {
|
|
params: { q: keyword }
|
|
})
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Search API keys by user ID and/or keyword (admin only)
|
|
* @param userId - Optional user ID to filter by
|
|
* @param keyword - Optional keyword to search in key name
|
|
* @returns List of matching API keys (max 30)
|
|
*/
|
|
export async function searchApiKeys(userId?: number, keyword?: string): Promise<SimpleApiKey[]> {
|
|
const params: Record<string, unknown> = {}
|
|
if (userId !== undefined) {
|
|
params.user_id = userId
|
|
}
|
|
if (keyword) {
|
|
params.q = keyword
|
|
}
|
|
const { data } = await apiClient.get<SimpleApiKey[]>('/admin/usage/search-api-keys', {
|
|
params
|
|
})
|
|
return data
|
|
}
|
|
|
|
export const adminUsageAPI = {
|
|
list,
|
|
getStats,
|
|
searchUsers,
|
|
searchApiKeys
|
|
}
|
|
|
|
export default adminUsageAPI
|