First commit

This commit is contained in:
shaw
2025-12-18 13:50:39 +08:00
parent 569f4882e5
commit 642842c29e
218 changed files with 86902 additions and 0 deletions

View File

@@ -0,0 +1,270 @@
/**
* Admin Accounts API endpoints
* Handles AI platform account management for administrators
*/
import { apiClient } from '../client';
import type {
Account,
CreateAccountRequest,
UpdateAccountRequest,
PaginatedResponse,
AccountUsageInfo,
WindowStats,
} from '@/types';
/**
* List all accounts with pagination
* @param page - Page number (default: 1)
* @param pageSize - Items per page (default: 20)
* @param filters - Optional filters
* @returns Paginated list of accounts
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
platform?: string;
type?: string;
status?: string;
search?: string;
}
): Promise<PaginatedResponse<Account>> {
const { data } = await apiClient.get<PaginatedResponse<Account>>('/admin/accounts', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
}
/**
* Get account by ID
* @param id - Account ID
* @returns Account details
*/
export async function getById(id: number): Promise<Account> {
const { data } = await apiClient.get<Account>(`/admin/accounts/${id}`);
return data;
}
/**
* Create new account
* @param accountData - Account data
* @returns Created account
*/
export async function create(accountData: CreateAccountRequest): Promise<Account> {
const { data } = await apiClient.post<Account>('/admin/accounts', accountData);
return data;
}
/**
* Update account
* @param id - Account ID
* @param updates - Fields to update
* @returns Updated account
*/
export async function update(id: number, updates: UpdateAccountRequest): Promise<Account> {
const { data } = await apiClient.put<Account>(`/admin/accounts/${id}`, updates);
return data;
}
/**
* Delete account
* @param id - Account ID
* @returns Success confirmation
*/
export async function deleteAccount(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/accounts/${id}`);
return data;
}
/**
* Toggle account status
* @param id - Account ID
* @param status - New status
* @returns Updated account
*/
export async function toggleStatus(
id: number,
status: 'active' | 'inactive'
): Promise<Account> {
return update(id, { status });
}
/**
* Test account connectivity
* @param id - Account ID
* @returns Test result
*/
export async function testAccount(id: number): Promise<{
success: boolean;
message: string;
latency_ms?: number;
}> {
const { data } = await apiClient.post<{
success: boolean;
message: string;
latency_ms?: number;
}>(`/admin/accounts/${id}/test`);
return data;
}
/**
* Refresh account credentials
* @param id - Account ID
* @returns Updated account
*/
export async function refreshCredentials(id: number): Promise<Account> {
const { data } = await apiClient.post<Account>(`/admin/accounts/${id}/refresh`);
return data;
}
/**
* Get account usage statistics
* @param id - Account ID
* @param period - Time period
* @returns Account usage statistics
*/
export async function getStats(
id: number,
period: string = 'month'
): Promise<{
total_requests: number;
successful_requests: number;
failed_requests: number;
total_tokens: number;
average_response_time: number;
}> {
const { data } = await apiClient.get<{
total_requests: number;
successful_requests: number;
failed_requests: number;
total_tokens: number;
average_response_time: number;
}>(`/admin/accounts/${id}/stats`, {
params: { period },
});
return data;
}
/**
* Clear account error
* @param id - Account ID
* @returns Updated account
*/
export async function clearError(id: number): Promise<Account> {
const { data } = await apiClient.post<Account>(`/admin/accounts/${id}/clear-error`);
return data;
}
/**
* Get account usage information (5h/7d window)
* @param id - Account ID
* @returns Account usage info
*/
export async function getUsage(id: number): Promise<AccountUsageInfo> {
const { data } = await apiClient.get<AccountUsageInfo>(`/admin/accounts/${id}/usage`);
return data;
}
/**
* Clear account rate limit status
* @param id - Account ID
* @returns Success confirmation
*/
export async function clearRateLimit(id: number): Promise<{ message: string }> {
const { data } = await apiClient.post<{ message: string }>(`/admin/accounts/${id}/clear-rate-limit`);
return data;
}
/**
* Generate OAuth authorization URL
* @param endpoint - API endpoint path
* @param config - Proxy configuration
* @returns Auth URL and session ID
*/
export async function generateAuthUrl(
endpoint: string,
config: { proxy_id?: number }
): Promise<{ auth_url: string; session_id: string }> {
const { data } = await apiClient.post<{ auth_url: string; session_id: string }>(endpoint, config);
return data;
}
/**
* Exchange authorization code for tokens
* @param endpoint - API endpoint path
* @param exchangeData - Session ID, code, and optional proxy config
* @returns Token information
*/
export async function exchangeCode(
endpoint: string,
exchangeData: { session_id: string; code: string; proxy_id?: number }
): Promise<Record<string, unknown>> {
const { data } = await apiClient.post<Record<string, unknown>>(endpoint, exchangeData);
return data;
}
/**
* Batch create accounts
* @param accounts - Array of account data
* @returns Results of batch creation
*/
export async function batchCreate(accounts: CreateAccountRequest[]): Promise<{
success: number;
failed: number;
results: Array<{ success: boolean; account?: Account; error?: string }>;
}> {
const { data } = await apiClient.post<{
success: number;
failed: number;
results: Array<{ success: boolean; account?: Account; error?: string }>;
}>('/admin/accounts/batch', { accounts });
return data;
}
/**
* Get account today statistics
* @param id - Account ID
* @returns Today's stats (requests, tokens, cost)
*/
export async function getTodayStats(id: number): Promise<WindowStats> {
const { data } = await apiClient.get<WindowStats>(`/admin/accounts/${id}/today-stats`);
return data;
}
/**
* Set account schedulable status
* @param id - Account ID
* @param schedulable - Whether the account should participate in scheduling
* @returns Updated account
*/
export async function setSchedulable(id: number, schedulable: boolean): Promise<Account> {
const { data } = await apiClient.post<Account>(`/admin/accounts/${id}/schedulable`, { schedulable });
return data;
}
export const accountsAPI = {
list,
getById,
create,
update,
delete: deleteAccount,
toggleStatus,
testAccount,
refreshCredentials,
getStats,
clearError,
getUsage,
getTodayStats,
clearRateLimit,
setSchedulable,
generateAuthUrl,
exchangeCode,
batchCreate,
};
export default accountsAPI;

View File

@@ -0,0 +1,173 @@
/**
* Admin Dashboard API endpoints
* Provides system-wide statistics and metrics
*/
import { apiClient } from '../client';
import type { DashboardStats, TrendDataPoint, ModelStat, ApiKeyUsageTrendPoint, UserUsageTrendPoint } from '@/types';
/**
* Get dashboard statistics
* @returns Dashboard statistics including users, keys, accounts, and token usage
*/
export async function getStats(): Promise<DashboardStats> {
const { data } = await apiClient.get<DashboardStats>('/admin/dashboard/stats');
return data;
}
/**
* Get real-time metrics
* @returns Real-time system metrics
*/
export async function getRealtimeMetrics(): Promise<{
active_requests: number;
requests_per_minute: number;
average_response_time: number;
error_rate: number;
}> {
const { data } = await apiClient.get<{
active_requests: number;
requests_per_minute: number;
average_response_time: number;
error_rate: number;
}>('/admin/dashboard/realtime');
return data;
}
export interface TrendParams {
start_date?: string;
end_date?: string;
granularity?: 'day' | 'hour';
}
export interface TrendResponse {
trend: TrendDataPoint[];
start_date: string;
end_date: string;
granularity: string;
}
/**
* Get usage trend data
* @param params - Query parameters for filtering
* @returns Usage trend data
*/
export async function getUsageTrend(params?: TrendParams): Promise<TrendResponse> {
const { data } = await apiClient.get<TrendResponse>('/admin/dashboard/trend', { params });
return data;
}
export interface ModelStatsResponse {
models: ModelStat[];
start_date: string;
end_date: string;
}
/**
* Get model usage statistics
* @param params - Query parameters for filtering
* @returns Model usage statistics
*/
export async function getModelStats(params?: { start_date?: string; end_date?: string }): Promise<ModelStatsResponse> {
const { data } = await apiClient.get<ModelStatsResponse>('/admin/dashboard/models', { params });
return data;
}
export interface ApiKeyTrendParams extends TrendParams {
limit?: number;
}
export interface ApiKeyTrendResponse {
trend: ApiKeyUsageTrendPoint[];
start_date: string;
end_date: string;
granularity: string;
}
/**
* Get API key usage trend data
* @param params - Query parameters for filtering
* @returns API key usage trend data
*/
export async function getApiKeyUsageTrend(params?: ApiKeyTrendParams): Promise<ApiKeyTrendResponse> {
const { data } = await apiClient.get<ApiKeyTrendResponse>('/admin/dashboard/api-keys-trend', { params });
return data;
}
export interface UserTrendParams extends TrendParams {
limit?: number;
}
export interface UserTrendResponse {
trend: UserUsageTrendPoint[];
start_date: string;
end_date: string;
granularity: string;
}
/**
* Get user usage trend data
* @param params - Query parameters for filtering
* @returns User usage trend data
*/
export async function getUserUsageTrend(params?: UserTrendParams): Promise<UserTrendResponse> {
const { data } = await apiClient.get<UserTrendResponse>('/admin/dashboard/users-trend', { params });
return data;
}
export interface BatchUserUsageStats {
user_id: number;
today_actual_cost: number;
total_actual_cost: number;
}
export interface BatchUsersUsageResponse {
stats: Record<string, BatchUserUsageStats>;
}
/**
* Get batch usage stats for multiple users
* @param userIds - Array of user IDs
* @returns Usage stats map keyed by user ID
*/
export async function getBatchUsersUsage(userIds: number[]): Promise<BatchUsersUsageResponse> {
const { data } = await apiClient.post<BatchUsersUsageResponse>('/admin/dashboard/users-usage', {
user_ids: userIds,
});
return data;
}
export interface BatchApiKeyUsageStats {
api_key_id: number;
today_actual_cost: number;
total_actual_cost: number;
}
export interface BatchApiKeysUsageResponse {
stats: Record<string, BatchApiKeyUsageStats>;
}
/**
* Get batch usage stats for multiple API keys
* @param apiKeyIds - Array of API key IDs
* @returns Usage stats map keyed by API key ID
*/
export async function getBatchApiKeysUsage(apiKeyIds: number[]): Promise<BatchApiKeysUsageResponse> {
const { data } = await apiClient.post<BatchApiKeysUsageResponse>('/admin/dashboard/api-keys-usage', {
api_key_ids: apiKeyIds,
});
return data;
}
export const dashboardAPI = {
getStats,
getRealtimeMetrics,
getUsageTrend,
getModelStats,
getApiKeyUsageTrend,
getUserUsageTrend,
getBatchUsersUsage,
getBatchApiKeysUsage,
};
export default dashboardAPI;

View File

@@ -0,0 +1,170 @@
/**
* Admin Groups API endpoints
* Handles API key group management for administrators
*/
import { apiClient } from '../client';
import type {
Group,
GroupPlatform,
CreateGroupRequest,
UpdateGroupRequest,
PaginatedResponse,
} from '@/types';
/**
* List all groups with pagination
* @param page - Page number (default: 1)
* @param pageSize - Items per page (default: 20)
* @param filters - Optional filters (platform, status, is_exclusive)
* @returns Paginated list of groups
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
platform?: GroupPlatform;
status?: 'active' | 'inactive';
is_exclusive?: boolean;
}
): Promise<PaginatedResponse<Group>> {
const { data } = await apiClient.get<PaginatedResponse<Group>>('/admin/groups', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
}
/**
* Get all active groups (without pagination)
* @param platform - Optional platform filter
* @returns List of all active groups
*/
export async function getAll(platform?: GroupPlatform): Promise<Group[]> {
const { data } = await apiClient.get<Group[]>('/admin/groups/all', {
params: platform ? { platform } : undefined
});
return data;
}
/**
* Get active groups by platform
* @param platform - Platform to filter by
* @returns List of groups for the specified platform
*/
export async function getByPlatform(platform: GroupPlatform): Promise<Group[]> {
return getAll(platform);
}
/**
* Get group by ID
* @param id - Group ID
* @returns Group details
*/
export async function getById(id: number): Promise<Group> {
const { data } = await apiClient.get<Group>(`/admin/groups/${id}`);
return data;
}
/**
* Create new group
* @param groupData - Group data
* @returns Created group
*/
export async function create(groupData: CreateGroupRequest): Promise<Group> {
const { data } = await apiClient.post<Group>('/admin/groups', groupData);
return data;
}
/**
* Update group
* @param id - Group ID
* @param updates - Fields to update
* @returns Updated group
*/
export async function update(id: number, updates: UpdateGroupRequest): Promise<Group> {
const { data } = await apiClient.put<Group>(`/admin/groups/${id}`, updates);
return data;
}
/**
* Delete group
* @param id - Group ID
* @returns Success confirmation
*/
export async function deleteGroup(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/groups/${id}`);
return data;
}
/**
* Toggle group status
* @param id - Group ID
* @param status - New status
* @returns Updated group
*/
export async function toggleStatus(
id: number,
status: 'active' | 'inactive'
): Promise<Group> {
return update(id, { status });
}
/**
* Get group statistics
* @param id - Group ID
* @returns Group usage statistics
*/
export async function getStats(id: number): Promise<{
total_api_keys: number;
active_api_keys: number;
total_requests: number;
total_cost: number;
}> {
const { data } = await apiClient.get<{
total_api_keys: number;
active_api_keys: number;
total_requests: number;
total_cost: number;
}>(`/admin/groups/${id}/stats`);
return data;
}
/**
* Get API keys in a group
* @param id - Group ID
* @param page - Page number
* @param pageSize - Items per page
* @returns Paginated list of API keys in the group
*/
export async function getGroupApiKeys(
id: number,
page: number = 1,
pageSize: number = 20
): Promise<PaginatedResponse<any>> {
const { data } = await apiClient.get<PaginatedResponse<any>>(
`/admin/groups/${id}/api-keys`,
{
params: { page, page_size: pageSize },
}
);
return data;
}
export const groupsAPI = {
list,
getAll,
getByPlatform,
getById,
create,
update,
delete: deleteGroup,
toggleStatus,
getStats,
getGroupApiKeys,
};
export default groupsAPI;

View File

@@ -0,0 +1,35 @@
/**
* Admin API barrel export
* Centralized exports for all admin API modules
*/
import dashboardAPI from './dashboard';
import usersAPI from './users';
import groupsAPI from './groups';
import accountsAPI from './accounts';
import proxiesAPI from './proxies';
import redeemAPI from './redeem';
import settingsAPI from './settings';
import systemAPI from './system';
import subscriptionsAPI from './subscriptions';
import usageAPI from './usage';
/**
* Unified admin API object for convenient access
*/
export const adminAPI = {
dashboard: dashboardAPI,
users: usersAPI,
groups: groupsAPI,
accounts: accountsAPI,
proxies: proxiesAPI,
redeem: redeemAPI,
settings: settingsAPI,
system: systemAPI,
subscriptions: subscriptionsAPI,
usage: usageAPI,
};
export { dashboardAPI, usersAPI, groupsAPI, accountsAPI, proxiesAPI, redeemAPI, settingsAPI, systemAPI, subscriptionsAPI, usageAPI };
export default adminAPI;

View File

@@ -0,0 +1,211 @@
/**
* Admin Proxies API endpoints
* Handles proxy server management for administrators
*/
import { apiClient } from '../client';
import type {
Proxy,
CreateProxyRequest,
UpdateProxyRequest,
PaginatedResponse,
} from '@/types';
/**
* List all proxies with pagination
* @param page - Page number (default: 1)
* @param pageSize - Items per page (default: 20)
* @param filters - Optional filters
* @returns Paginated list of proxies
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
protocol?: string;
status?: 'active' | 'inactive';
search?: string;
}
): Promise<PaginatedResponse<Proxy>> {
const { data } = await apiClient.get<PaginatedResponse<Proxy>>('/admin/proxies', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
}
/**
* Get all active proxies (without pagination)
* @returns List of all active proxies
*/
export async function getAll(): Promise<Proxy[]> {
const { data } = await apiClient.get<Proxy[]>('/admin/proxies/all');
return data;
}
/**
* Get all active proxies with account count (sorted by creation time desc)
* @returns List of all active proxies with account count
*/
export async function getAllWithCount(): Promise<Proxy[]> {
const { data } = await apiClient.get<Proxy[]>('/admin/proxies/all', {
params: { with_count: 'true' },
});
return data;
}
/**
* Get proxy by ID
* @param id - Proxy ID
* @returns Proxy details
*/
export async function getById(id: number): Promise<Proxy> {
const { data } = await apiClient.get<Proxy>(`/admin/proxies/${id}`);
return data;
}
/**
* Create new proxy
* @param proxyData - Proxy data
* @returns Created proxy
*/
export async function create(proxyData: CreateProxyRequest): Promise<Proxy> {
const { data } = await apiClient.post<Proxy>('/admin/proxies', proxyData);
return data;
}
/**
* Update proxy
* @param id - Proxy ID
* @param updates - Fields to update
* @returns Updated proxy
*/
export async function update(id: number, updates: UpdateProxyRequest): Promise<Proxy> {
const { data } = await apiClient.put<Proxy>(`/admin/proxies/${id}`, updates);
return data;
}
/**
* Delete proxy
* @param id - Proxy ID
* @returns Success confirmation
*/
export async function deleteProxy(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/proxies/${id}`);
return data;
}
/**
* Toggle proxy status
* @param id - Proxy ID
* @param status - New status
* @returns Updated proxy
*/
export async function toggleStatus(
id: number,
status: 'active' | 'inactive'
): Promise<Proxy> {
return update(id, { status });
}
/**
* Test proxy connectivity
* @param id - Proxy ID
* @returns Test result with IP info
*/
export async function testProxy(id: number): Promise<{
success: boolean;
message: string;
latency_ms?: number;
ip_address?: string;
city?: string;
region?: string;
country?: string;
}> {
const { data } = await apiClient.post<{
success: boolean;
message: string;
latency_ms?: number;
ip_address?: string;
city?: string;
region?: string;
country?: string;
}>(`/admin/proxies/${id}/test`);
return data;
}
/**
* Get proxy usage statistics
* @param id - Proxy ID
* @returns Proxy usage statistics
*/
export async function getStats(id: number): Promise<{
total_accounts: number;
active_accounts: number;
total_requests: number;
success_rate: number;
average_latency: number;
}> {
const { data } = await apiClient.get<{
total_accounts: number;
active_accounts: number;
total_requests: number;
success_rate: number;
average_latency: number;
}>(`/admin/proxies/${id}/stats`);
return data;
}
/**
* Get accounts using a proxy
* @param id - Proxy ID
* @returns List of accounts using the proxy
*/
export async function getProxyAccounts(id: number): Promise<PaginatedResponse<any>> {
const { data } = await apiClient.get<PaginatedResponse<any>>(
`/admin/proxies/${id}/accounts`
);
return data;
}
/**
* Batch create proxies
* @param proxies - Array of proxy data to create
* @returns Creation result with count of created and skipped
*/
export async function batchCreate(proxies: Array<{
protocol: string;
host: string;
port: number;
username?: string;
password?: string;
}>): Promise<{
created: number;
skipped: number;
}> {
const { data } = await apiClient.post<{
created: number;
skipped: number;
}>('/admin/proxies/batch', { proxies });
return data;
}
export const proxiesAPI = {
list,
getAll,
getAllWithCount,
getById,
create,
update,
delete: deleteProxy,
toggleStatus,
testProxy,
getStats,
getProxyAccounts,
batchCreate,
};
export default proxiesAPI;

View File

@@ -0,0 +1,170 @@
/**
* Admin Redeem Codes API endpoints
* Handles redeem code generation and management for administrators
*/
import { apiClient } from '../client';
import type {
RedeemCode,
GenerateRedeemCodesRequest,
RedeemCodeType,
PaginatedResponse,
} from '@/types';
/**
* List all redeem codes with pagination
* @param page - Page number (default: 1)
* @param pageSize - Items per page (default: 20)
* @param filters - Optional filters
* @returns Paginated list of redeem codes
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
type?: RedeemCodeType;
status?: 'active' | 'used' | 'expired';
search?: string;
}
): Promise<PaginatedResponse<RedeemCode>> {
const { data } = await apiClient.get<PaginatedResponse<RedeemCode>>('/admin/redeem-codes', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
}
/**
* Get redeem code by ID
* @param id - Redeem code ID
* @returns Redeem code details
*/
export async function getById(id: number): Promise<RedeemCode> {
const { data } = await apiClient.get<RedeemCode>(`/admin/redeem-codes/${id}`);
return data;
}
/**
* Generate new redeem codes
* @param count - Number of codes to generate
* @param type - Type of redeem code
* @param value - Value of the code
* @param groupId - Group ID (required for subscription type)
* @param validityDays - Validity days (for subscription type)
* @returns Array of generated redeem codes
*/
export async function generate(
count: number,
type: RedeemCodeType,
value: number,
groupId?: number | null,
validityDays?: number
): Promise<RedeemCode[]> {
const payload: GenerateRedeemCodesRequest = {
count,
type,
value,
};
// 订阅类型专用字段
if (type === 'subscription') {
payload.group_id = groupId;
if (validityDays && validityDays > 0) {
payload.validity_days = validityDays;
}
}
const { data } = await apiClient.post<RedeemCode[]>('/admin/redeem-codes/generate', payload);
return data;
}
/**
* Delete redeem code
* @param id - Redeem code ID
* @returns Success confirmation
*/
export async function deleteCode(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/redeem-codes/${id}`);
return data;
}
/**
* Batch delete redeem codes
* @param ids - Array of redeem code IDs
* @returns Success confirmation
*/
export async function batchDelete(ids: number[]): Promise<{
deleted: number;
message: string;
}> {
const { data } = await apiClient.post<{
deleted: number;
message: string;
}>('/admin/redeem-codes/batch-delete', { ids });
return data;
}
/**
* Expire redeem code
* @param id - Redeem code ID
* @returns Updated redeem code
*/
export async function expire(id: number): Promise<RedeemCode> {
const { data } = await apiClient.post<RedeemCode>(`/admin/redeem-codes/${id}/expire`);
return data;
}
/**
* Get redeem code statistics
* @returns Statistics about redeem codes
*/
export async function getStats(): Promise<{
total_codes: number;
active_codes: number;
used_codes: number;
expired_codes: number;
total_value_distributed: number;
by_type: Record<RedeemCodeType, number>;
}> {
const { data } = await apiClient.get<{
total_codes: number;
active_codes: number;
used_codes: number;
expired_codes: number;
total_value_distributed: number;
by_type: Record<RedeemCodeType, number>;
}>('/admin/redeem-codes/stats');
return data;
}
/**
* Export redeem codes to CSV
* @param filters - Optional filters
* @returns CSV data as blob
*/
export async function exportCodes(filters?: {
type?: RedeemCodeType;
status?: 'active' | 'used' | 'expired';
}): Promise<Blob> {
const response = await apiClient.get('/admin/redeem-codes/export', {
params: filters,
responseType: 'blob',
});
return response.data;
}
export const redeemAPI = {
list,
getById,
generate,
delete: deleteCode,
batchDelete,
expire,
getStats,
exportCodes,
};
export default redeemAPI;

View File

@@ -0,0 +1,109 @@
/**
* Admin Settings API endpoints
* Handles system settings management for administrators
*/
import { apiClient } from '../client';
/**
* System settings interface
*/
export interface SystemSettings {
// Registration settings
registration_enabled: boolean;
email_verify_enabled: boolean;
// Default settings
default_balance: number;
default_concurrency: number;
// OEM settings
site_name: string;
site_logo: string;
site_subtitle: string;
api_base_url: string;
contact_info: string;
// SMTP settings
smtp_host: string;
smtp_port: number;
smtp_username: string;
smtp_password: string;
smtp_from_email: string;
smtp_from_name: string;
smtp_use_tls: boolean;
// Cloudflare Turnstile settings
turnstile_enabled: boolean;
turnstile_site_key: string;
turnstile_secret_key: string;
}
/**
* Get all system settings
* @returns System settings
*/
export async function getSettings(): Promise<SystemSettings> {
const { data } = await apiClient.get<SystemSettings>('/admin/settings');
return data;
}
/**
* Update system settings
* @param settings - Partial settings to update
* @returns Updated settings
*/
export async function updateSettings(settings: Partial<SystemSettings>): Promise<SystemSettings> {
const { data } = await apiClient.put<SystemSettings>('/admin/settings', settings);
return data;
}
/**
* Test SMTP connection request
*/
export interface TestSmtpRequest {
smtp_host: string;
smtp_port: number;
smtp_username: string;
smtp_password: string;
smtp_use_tls: boolean;
}
/**
* Test SMTP connection with provided config
* @param config - SMTP configuration to test
* @returns Test result message
*/
export async function testSmtpConnection(config: TestSmtpRequest): Promise<{ message: string }> {
const { data } = await apiClient.post<{ message: string }>('/admin/settings/test-smtp', config);
return data;
}
/**
* Send test email request
*/
export interface SendTestEmailRequest {
email: string;
smtp_host: string;
smtp_port: number;
smtp_username: string;
smtp_password: string;
smtp_from_email: string;
smtp_from_name: string;
smtp_use_tls: boolean;
}
/**
* Send test email with provided SMTP config
* @param request - Email address and SMTP config
* @returns Test result message
*/
export async function sendTestEmail(request: SendTestEmailRequest): Promise<{ message: string }> {
const { data } = await apiClient.post<{ message: string }>('/admin/settings/send-test-email', request);
return data;
}
export const settingsAPI = {
getSettings,
updateSettings,
testSmtpConnection,
sendTestEmail,
};
export default settingsAPI;

View File

@@ -0,0 +1,157 @@
/**
* Admin Subscriptions API endpoints
* Handles user subscription management for administrators
*/
import { apiClient } from '../client';
import type {
UserSubscription,
SubscriptionProgress,
AssignSubscriptionRequest,
BulkAssignSubscriptionRequest,
ExtendSubscriptionRequest,
PaginatedResponse,
} from '@/types';
/**
* List all subscriptions with pagination
* @param page - Page number (default: 1)
* @param pageSize - Items per page (default: 20)
* @param filters - Optional filters (status, user_id, group_id)
* @returns Paginated list of subscriptions
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
status?: 'active' | 'expired' | 'revoked';
user_id?: number;
group_id?: number;
}
): Promise<PaginatedResponse<UserSubscription>> {
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>('/admin/subscriptions', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
}
/**
* Get subscription by ID
* @param id - Subscription ID
* @returns Subscription details
*/
export async function getById(id: number): Promise<UserSubscription> {
const { data } = await apiClient.get<UserSubscription>(`/admin/subscriptions/${id}`);
return data;
}
/**
* Get subscription progress
* @param id - Subscription ID
* @returns Subscription progress with usage stats
*/
export async function getProgress(id: number): Promise<SubscriptionProgress> {
const { data } = await apiClient.get<SubscriptionProgress>(`/admin/subscriptions/${id}/progress`);
return data;
}
/**
* Assign subscription to user
* @param request - Assignment request
* @returns Created subscription
*/
export async function assign(request: AssignSubscriptionRequest): Promise<UserSubscription> {
const { data } = await apiClient.post<UserSubscription>('/admin/subscriptions/assign', request);
return data;
}
/**
* Bulk assign subscriptions to multiple users
* @param request - Bulk assignment request
* @returns Created subscriptions
*/
export async function bulkAssign(request: BulkAssignSubscriptionRequest): Promise<UserSubscription[]> {
const { data } = await apiClient.post<UserSubscription[]>('/admin/subscriptions/bulk-assign', request);
return data;
}
/**
* Extend subscription validity
* @param id - Subscription ID
* @param request - Extension request with days
* @returns Updated subscription
*/
export async function extend(id: number, request: ExtendSubscriptionRequest): Promise<UserSubscription> {
const { data } = await apiClient.post<UserSubscription>(`/admin/subscriptions/${id}/extend`, request);
return data;
}
/**
* Revoke subscription
* @param id - Subscription ID
* @returns Success confirmation
*/
export async function revoke(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/subscriptions/${id}`);
return data;
}
/**
* List subscriptions by group
* @param groupId - Group ID
* @param page - Page number
* @param pageSize - Items per page
* @returns Paginated list of subscriptions in the group
*/
export async function listByGroup(
groupId: number,
page: number = 1,
pageSize: number = 20
): Promise<PaginatedResponse<UserSubscription>> {
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>(
`/admin/groups/${groupId}/subscriptions`,
{
params: { page, page_size: pageSize },
}
);
return data;
}
/**
* List subscriptions by user
* @param userId - User ID
* @param page - Page number
* @param pageSize - Items per page
* @returns Paginated list of user's subscriptions
*/
export async function listByUser(
userId: number,
page: number = 1,
pageSize: number = 20
): Promise<PaginatedResponse<UserSubscription>> {
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>(
`/admin/users/${userId}/subscriptions`,
{
params: { page, page_size: pageSize },
}
);
return data;
}
export const subscriptionsAPI = {
list,
getById,
getProgress,
assign,
bulkAssign,
extend,
revoke,
listByGroup,
listByUser,
};
export default subscriptionsAPI;

View File

@@ -0,0 +1,48 @@
/**
* System API endpoints for admin operations
*/
import { apiClient } from '../client';
export interface ReleaseInfo {
name: string;
body: string;
published_at: string;
html_url: string;
}
export interface VersionInfo {
current_version: string;
latest_version: string;
has_update: boolean;
release_info?: ReleaseInfo;
cached: boolean;
warning?: string;
build_type: string; // "source" for manual builds, "release" for CI builds
}
/**
* Get current version
*/
export async function getVersion(): Promise<{ version: string }> {
const { data } = await apiClient.get<{ version: string }>('/admin/system/version');
return data;
}
/**
* Check for updates
* @param force - Force refresh from GitHub API
*/
export async function checkUpdates(force = false): Promise<VersionInfo> {
const { data } = await apiClient.get<VersionInfo>('/admin/system/check-updates', {
params: force ? { force: 'true' } : undefined,
});
return data;
}
export const systemAPI = {
getVersion,
checkUpdates,
};
export default systemAPI;

View File

@@ -0,0 +1,112 @@
/**
* 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): Promise<PaginatedResponse<UsageLog>> {
const { data } = await apiClient.get<PaginatedResponse<UsageLog>>('/admin/usage', {
params,
});
return data;
}
/**
* Get usage statistics with optional filters (admin only)
* @param params - Query parameters (user_id, api_key_id, period/date range)
* @returns Usage statistics
*/
export async function getStats(params: {
user_id?: number;
api_key_id?: number;
period?: string;
start_date?: string;
end_date?: 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;

View File

@@ -0,0 +1,168 @@
/**
* Admin Users API endpoints
* Handles user management for administrators
*/
import { apiClient } from '../client';
import type { User, UpdateUserRequest, PaginatedResponse } from '@/types';
/**
* List all users with pagination
* @param page - Page number (default: 1)
* @param pageSize - Items per page (default: 20)
* @param filters - Optional filters (status, role, search)
* @returns Paginated list of users
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
status?: 'active' | 'disabled';
role?: 'admin' | 'user';
search?: string;
}
): Promise<PaginatedResponse<User>> {
const { data } = await apiClient.get<PaginatedResponse<User>>('/admin/users', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
}
/**
* Get user by ID
* @param id - User ID
* @returns User details
*/
export async function getById(id: number): Promise<User> {
const { data } = await apiClient.get<User>(`/admin/users/${id}`);
return data;
}
/**
* Create new user
* @param userData - User data (email, password, etc.)
* @returns Created user
*/
export async function create(userData: {
email: string;
password: string;
balance?: number;
concurrency?: number;
allowed_groups?: number[] | null;
}): Promise<User> {
const { data } = await apiClient.post<User>('/admin/users', userData);
return data;
}
/**
* Update user
* @param id - User ID
* @param updates - Fields to update
* @returns Updated user
*/
export async function update(id: number, updates: UpdateUserRequest): Promise<User> {
const { data } = await apiClient.put<User>(`/admin/users/${id}`, updates);
return data;
}
/**
* Delete user
* @param id - User ID
* @returns Success confirmation
*/
export async function deleteUser(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/users/${id}`);
return data;
}
/**
* Update user balance
* @param id - User ID
* @param balance - New balance
* @param operation - Operation type ('set', 'add', 'subtract')
* @returns Updated user
*/
export async function updateBalance(
id: number,
balance: number,
operation: 'set' | 'add' | 'subtract' = 'set'
): Promise<User> {
const { data } = await apiClient.post<User>(`/admin/users/${id}/balance`, {
balance,
operation,
});
return data;
}
/**
* Update user concurrency
* @param id - User ID
* @param concurrency - New concurrency limit
* @returns Updated user
*/
export async function updateConcurrency(id: number, concurrency: number): Promise<User> {
return update(id, { concurrency });
}
/**
* Toggle user status
* @param id - User ID
* @param status - New status
* @returns Updated user
*/
export async function toggleStatus(id: number, status: 'active' | 'disabled'): Promise<User> {
return update(id, { status });
}
/**
* Get user's API keys
* @param id - User ID
* @returns List of user's API keys
*/
export async function getUserApiKeys(id: number): Promise<PaginatedResponse<any>> {
const { data } = await apiClient.get<PaginatedResponse<any>>(`/admin/users/${id}/api-keys`);
return data;
}
/**
* Get user's usage statistics
* @param id - User ID
* @param period - Time period
* @returns User usage statistics
*/
export async function getUserUsageStats(
id: number,
period: string = 'month'
): Promise<{
total_requests: number;
total_cost: number;
total_tokens: number;
}> {
const { data } = await apiClient.get<{
total_requests: number;
total_cost: number;
total_tokens: number;
}>(`/admin/users/${id}/usage`, {
params: { period },
});
return data;
}
export const usersAPI = {
list,
getById,
create,
update,
delete: deleteUser,
updateBalance,
updateConcurrency,
toggleStatus,
getUserApiKeys,
getUserUsageStats,
};
export default usersAPI;