778 lines
24 KiB
TypeScript
778 lines
24 KiB
TypeScript
/**
|
|
* Admin Settings API endpoints
|
|
* Handles system settings management for administrators
|
|
*/
|
|
|
|
import { apiClient } from '../client'
|
|
import type { CustomMenuItem, CustomEndpoint, NotifyEmailEntry } from '@/types'
|
|
|
|
export interface DefaultSubscriptionSetting {
|
|
group_id: number
|
|
validity_days: number
|
|
}
|
|
|
|
export type AuthSourceType = 'email' | 'linuxdo' | 'oidc' | 'wechat'
|
|
|
|
export interface AuthSourceDefaultsValue {
|
|
balance: number
|
|
concurrency: number
|
|
subscriptions: DefaultSubscriptionSetting[]
|
|
grant_on_signup: boolean
|
|
grant_on_first_bind: boolean
|
|
}
|
|
|
|
export type AuthSourceDefaultsState = Record<AuthSourceType, AuthSourceDefaultsValue>
|
|
export type PaymentVisibleMethod = 'alipay' | 'wxpay'
|
|
export type PaymentVisibleMethodSource =
|
|
| ''
|
|
| 'official_alipay'
|
|
| 'easypay_alipay'
|
|
| 'official_wxpay'
|
|
| 'easypay_wxpay'
|
|
|
|
export interface PaymentVisibleMethodSourceOption {
|
|
value: PaymentVisibleMethodSource
|
|
labelZh: string
|
|
labelEn: string
|
|
}
|
|
|
|
const AUTH_SOURCE_TYPES: AuthSourceType[] = ['email', 'linuxdo', 'oidc', 'wechat']
|
|
const AUTH_SOURCE_DEFAULT_BALANCE = 0
|
|
const AUTH_SOURCE_DEFAULT_CONCURRENCY = 5
|
|
const PAYMENT_VISIBLE_METHOD_SOURCE_OPTIONS: Record<
|
|
PaymentVisibleMethod,
|
|
PaymentVisibleMethodSourceOption[]
|
|
> = {
|
|
alipay: [
|
|
{ value: '', labelZh: '未配置', labelEn: 'Not configured' },
|
|
{ value: 'official_alipay', labelZh: '支付宝官方', labelEn: 'Official Alipay' },
|
|
{ value: 'easypay_alipay', labelZh: '易支付支付宝', labelEn: 'EasyPay Alipay' },
|
|
],
|
|
wxpay: [
|
|
{ value: '', labelZh: '未配置', labelEn: 'Not configured' },
|
|
{ value: 'official_wxpay', labelZh: '微信官方', labelEn: 'Official WeChat Pay' },
|
|
{ value: 'easypay_wxpay', labelZh: '易支付微信', labelEn: 'EasyPay WeChat Pay' },
|
|
],
|
|
}
|
|
const PAYMENT_VISIBLE_METHOD_SOURCE_ALIASES: Record<
|
|
PaymentVisibleMethod,
|
|
Record<string, PaymentVisibleMethodSource>
|
|
> = {
|
|
alipay: {
|
|
official_alipay: 'official_alipay',
|
|
alipay: 'official_alipay',
|
|
alipay_direct: 'official_alipay',
|
|
official: 'official_alipay',
|
|
easypay_alipay: 'easypay_alipay',
|
|
easypay: 'easypay_alipay',
|
|
},
|
|
wxpay: {
|
|
official_wxpay: 'official_wxpay',
|
|
wxpay: 'official_wxpay',
|
|
wxpay_direct: 'official_wxpay',
|
|
wechat: 'official_wxpay',
|
|
official: 'official_wxpay',
|
|
easypay_wxpay: 'easypay_wxpay',
|
|
easypay: 'easypay_wxpay',
|
|
},
|
|
}
|
|
|
|
export function normalizeDefaultSubscriptionSettings(
|
|
subscriptions: DefaultSubscriptionSetting[] | null | undefined
|
|
): DefaultSubscriptionSetting[] {
|
|
if (!Array.isArray(subscriptions)) return []
|
|
|
|
return subscriptions
|
|
.filter((item) => item.group_id > 0 && item.validity_days > 0)
|
|
.map((item) => ({
|
|
group_id: Math.floor(item.group_id),
|
|
validity_days: Math.min(36500, Math.max(1, Math.floor(item.validity_days)))
|
|
}))
|
|
}
|
|
|
|
export function buildAuthSourceDefaultsState(
|
|
settings: Partial<SystemSettings>
|
|
): AuthSourceDefaultsState {
|
|
const raw = settings as Record<string, unknown>
|
|
|
|
return AUTH_SOURCE_TYPES.reduce((acc, source) => {
|
|
const subscriptions = raw[`auth_source_default_${source}_subscriptions`]
|
|
acc[source] = {
|
|
balance: Number(raw[`auth_source_default_${source}_balance`] ?? AUTH_SOURCE_DEFAULT_BALANCE),
|
|
concurrency: Math.max(
|
|
1,
|
|
Number(raw[`auth_source_default_${source}_concurrency`] ?? AUTH_SOURCE_DEFAULT_CONCURRENCY)
|
|
),
|
|
subscriptions: normalizeDefaultSubscriptionSettings(
|
|
Array.isArray(subscriptions) ? (subscriptions as DefaultSubscriptionSetting[]) : []
|
|
),
|
|
grant_on_signup: raw[`auth_source_default_${source}_grant_on_signup`] !== false,
|
|
grant_on_first_bind: raw[`auth_source_default_${source}_grant_on_first_bind`] === true,
|
|
}
|
|
return acc
|
|
}, {} as AuthSourceDefaultsState)
|
|
}
|
|
|
|
export function appendAuthSourceDefaultsToUpdateRequest(
|
|
payload: UpdateSettingsRequest,
|
|
authSourceDefaults: AuthSourceDefaultsState
|
|
): UpdateSettingsRequest {
|
|
const target = payload as Record<string, unknown>
|
|
|
|
for (const source of AUTH_SOURCE_TYPES) {
|
|
const current = authSourceDefaults[source]
|
|
target[`auth_source_default_${source}_balance`] = Number(current.balance) || 0
|
|
target[`auth_source_default_${source}_concurrency`] = Math.max(
|
|
1,
|
|
Math.floor(Number(current.concurrency) || AUTH_SOURCE_DEFAULT_CONCURRENCY)
|
|
)
|
|
target[`auth_source_default_${source}_subscriptions`] = normalizeDefaultSubscriptionSettings(
|
|
current.subscriptions
|
|
)
|
|
target[`auth_source_default_${source}_grant_on_signup`] = current.grant_on_signup
|
|
target[`auth_source_default_${source}_grant_on_first_bind`] = current.grant_on_first_bind
|
|
}
|
|
|
|
return payload
|
|
}
|
|
|
|
export function getPaymentVisibleMethodSourceOptions(
|
|
method: PaymentVisibleMethod
|
|
): PaymentVisibleMethodSourceOption[] {
|
|
return PAYMENT_VISIBLE_METHOD_SOURCE_OPTIONS[method]
|
|
}
|
|
|
|
export function normalizePaymentVisibleMethodSource(
|
|
method: PaymentVisibleMethod,
|
|
source: unknown
|
|
): PaymentVisibleMethodSource {
|
|
if (typeof source !== 'string') return ''
|
|
|
|
const normalized = source.trim().toLowerCase()
|
|
if (!normalized) return ''
|
|
|
|
return PAYMENT_VISIBLE_METHOD_SOURCE_ALIASES[method][normalized] ?? ''
|
|
}
|
|
|
|
/**
|
|
* System settings interface
|
|
*/
|
|
export interface SystemSettings {
|
|
// Registration settings
|
|
registration_enabled: boolean
|
|
email_verify_enabled: boolean
|
|
registration_email_suffix_whitelist: string[]
|
|
promo_code_enabled: boolean
|
|
password_reset_enabled: boolean
|
|
frontend_url: string
|
|
invitation_code_enabled: boolean
|
|
totp_enabled: boolean // TOTP 双因素认证
|
|
totp_encryption_key_configured: boolean // TOTP 加密密钥是否已配置
|
|
// Default settings
|
|
default_balance: number
|
|
default_concurrency: number
|
|
default_subscriptions: DefaultSubscriptionSetting[]
|
|
auth_source_default_email_balance?: number
|
|
auth_source_default_email_concurrency?: number
|
|
auth_source_default_email_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_email_grant_on_signup?: boolean
|
|
auth_source_default_email_grant_on_first_bind?: boolean
|
|
auth_source_default_linuxdo_balance?: number
|
|
auth_source_default_linuxdo_concurrency?: number
|
|
auth_source_default_linuxdo_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_linuxdo_grant_on_signup?: boolean
|
|
auth_source_default_linuxdo_grant_on_first_bind?: boolean
|
|
auth_source_default_oidc_balance?: number
|
|
auth_source_default_oidc_concurrency?: number
|
|
auth_source_default_oidc_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_oidc_grant_on_signup?: boolean
|
|
auth_source_default_oidc_grant_on_first_bind?: boolean
|
|
auth_source_default_wechat_balance?: number
|
|
auth_source_default_wechat_concurrency?: number
|
|
auth_source_default_wechat_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_wechat_grant_on_signup?: boolean
|
|
auth_source_default_wechat_grant_on_first_bind?: boolean
|
|
force_email_on_third_party_signup?: boolean
|
|
// OEM settings
|
|
site_name: string
|
|
site_logo: string
|
|
site_subtitle: string
|
|
api_base_url: string
|
|
contact_info: string
|
|
doc_url: string
|
|
home_content: string
|
|
hide_ccs_import_button: boolean
|
|
table_default_page_size: number
|
|
table_page_size_options: number[]
|
|
backend_mode_enabled: boolean
|
|
custom_menu_items: CustomMenuItem[]
|
|
custom_endpoints: CustomEndpoint[]
|
|
// SMTP settings
|
|
smtp_host: string
|
|
smtp_port: number
|
|
smtp_username: string
|
|
smtp_password_configured: boolean
|
|
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_configured: boolean
|
|
|
|
// LinuxDo Connect OAuth settings
|
|
linuxdo_connect_enabled: boolean
|
|
linuxdo_connect_client_id: string
|
|
linuxdo_connect_client_secret_configured: boolean
|
|
linuxdo_connect_redirect_url: string
|
|
|
|
// Generic OIDC OAuth settings
|
|
oidc_connect_enabled: boolean
|
|
oidc_connect_provider_name: string
|
|
oidc_connect_client_id: string
|
|
oidc_connect_client_secret_configured: boolean
|
|
oidc_connect_issuer_url: string
|
|
oidc_connect_discovery_url: string
|
|
oidc_connect_authorize_url: string
|
|
oidc_connect_token_url: string
|
|
oidc_connect_userinfo_url: string
|
|
oidc_connect_jwks_url: string
|
|
oidc_connect_scopes: string
|
|
oidc_connect_redirect_url: string
|
|
oidc_connect_frontend_redirect_url: string
|
|
oidc_connect_token_auth_method: string
|
|
oidc_connect_use_pkce: boolean
|
|
oidc_connect_validate_id_token: boolean
|
|
oidc_connect_allowed_signing_algs: string
|
|
oidc_connect_clock_skew_seconds: number
|
|
oidc_connect_require_email_verified: boolean
|
|
oidc_connect_userinfo_email_path: string
|
|
oidc_connect_userinfo_id_path: string
|
|
oidc_connect_userinfo_username_path: string
|
|
|
|
// Model fallback configuration
|
|
enable_model_fallback: boolean
|
|
fallback_model_anthropic: string
|
|
fallback_model_openai: string
|
|
fallback_model_gemini: string
|
|
fallback_model_antigravity: string
|
|
|
|
// Identity patch configuration (Claude -> Gemini)
|
|
enable_identity_patch: boolean
|
|
identity_patch_prompt: string
|
|
|
|
// Ops Monitoring (vNext)
|
|
ops_monitoring_enabled: boolean
|
|
ops_realtime_monitoring_enabled: boolean
|
|
ops_query_mode_default: 'auto' | 'raw' | 'preagg' | string
|
|
ops_metrics_interval_seconds: number
|
|
|
|
// Claude Code version check
|
|
min_claude_code_version: string
|
|
max_claude_code_version: string
|
|
|
|
// 分组隔离
|
|
allow_ungrouped_key_scheduling: boolean
|
|
|
|
// Gateway forwarding behavior
|
|
enable_fingerprint_unification: boolean
|
|
enable_metadata_passthrough: boolean
|
|
enable_cch_signing: boolean
|
|
web_search_emulation_enabled?: boolean
|
|
|
|
// Payment configuration
|
|
payment_enabled: boolean
|
|
payment_min_amount: number
|
|
payment_max_amount: number
|
|
payment_daily_limit: number
|
|
payment_order_timeout_minutes: number
|
|
payment_max_pending_orders: number
|
|
payment_enabled_types: string[]
|
|
payment_balance_disabled: boolean
|
|
payment_balance_recharge_multiplier: number
|
|
payment_recharge_fee_rate: number
|
|
payment_load_balance_strategy: string
|
|
payment_product_name_prefix: string
|
|
payment_product_name_suffix: string
|
|
payment_help_image_url: string
|
|
payment_help_text: string
|
|
payment_cancel_rate_limit_enabled: boolean
|
|
payment_cancel_rate_limit_max: number
|
|
payment_cancel_rate_limit_window: number
|
|
payment_cancel_rate_limit_unit: string
|
|
payment_cancel_rate_limit_window_mode: string
|
|
payment_visible_method_alipay_source?: string
|
|
payment_visible_method_wxpay_source?: string
|
|
payment_visible_method_alipay_enabled?: boolean
|
|
payment_visible_method_wxpay_enabled?: boolean
|
|
openai_advanced_scheduler_enabled?: boolean
|
|
|
|
// Balance & quota notification
|
|
balance_low_notify_enabled: boolean
|
|
balance_low_notify_threshold: number
|
|
balance_low_notify_recharge_url: string
|
|
account_quota_notify_enabled: boolean
|
|
account_quota_notify_emails: NotifyEmailEntry[]
|
|
}
|
|
|
|
export interface UpdateSettingsRequest {
|
|
registration_enabled?: boolean
|
|
email_verify_enabled?: boolean
|
|
registration_email_suffix_whitelist?: string[]
|
|
promo_code_enabled?: boolean
|
|
password_reset_enabled?: boolean
|
|
frontend_url?: string
|
|
invitation_code_enabled?: boolean
|
|
totp_enabled?: boolean // TOTP 双因素认证
|
|
default_balance?: number
|
|
default_concurrency?: number
|
|
default_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_email_balance?: number
|
|
auth_source_default_email_concurrency?: number
|
|
auth_source_default_email_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_email_grant_on_signup?: boolean
|
|
auth_source_default_email_grant_on_first_bind?: boolean
|
|
auth_source_default_linuxdo_balance?: number
|
|
auth_source_default_linuxdo_concurrency?: number
|
|
auth_source_default_linuxdo_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_linuxdo_grant_on_signup?: boolean
|
|
auth_source_default_linuxdo_grant_on_first_bind?: boolean
|
|
auth_source_default_oidc_balance?: number
|
|
auth_source_default_oidc_concurrency?: number
|
|
auth_source_default_oidc_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_oidc_grant_on_signup?: boolean
|
|
auth_source_default_oidc_grant_on_first_bind?: boolean
|
|
auth_source_default_wechat_balance?: number
|
|
auth_source_default_wechat_concurrency?: number
|
|
auth_source_default_wechat_subscriptions?: DefaultSubscriptionSetting[]
|
|
auth_source_default_wechat_grant_on_signup?: boolean
|
|
auth_source_default_wechat_grant_on_first_bind?: boolean
|
|
force_email_on_third_party_signup?: boolean
|
|
site_name?: string
|
|
site_logo?: string
|
|
site_subtitle?: string
|
|
api_base_url?: string
|
|
contact_info?: string
|
|
doc_url?: string
|
|
home_content?: string
|
|
hide_ccs_import_button?: boolean
|
|
table_default_page_size?: number
|
|
table_page_size_options?: number[]
|
|
backend_mode_enabled?: boolean
|
|
custom_menu_items?: CustomMenuItem[]
|
|
custom_endpoints?: CustomEndpoint[]
|
|
smtp_host?: string
|
|
smtp_port?: number
|
|
smtp_username?: string
|
|
smtp_password?: string
|
|
smtp_from_email?: string
|
|
smtp_from_name?: string
|
|
smtp_use_tls?: boolean
|
|
turnstile_enabled?: boolean
|
|
turnstile_site_key?: string
|
|
turnstile_secret_key?: string
|
|
linuxdo_connect_enabled?: boolean
|
|
linuxdo_connect_client_id?: string
|
|
linuxdo_connect_client_secret?: string
|
|
linuxdo_connect_redirect_url?: string
|
|
oidc_connect_enabled?: boolean
|
|
oidc_connect_provider_name?: string
|
|
oidc_connect_client_id?: string
|
|
oidc_connect_client_secret?: string
|
|
oidc_connect_issuer_url?: string
|
|
oidc_connect_discovery_url?: string
|
|
oidc_connect_authorize_url?: string
|
|
oidc_connect_token_url?: string
|
|
oidc_connect_userinfo_url?: string
|
|
oidc_connect_jwks_url?: string
|
|
oidc_connect_scopes?: string
|
|
oidc_connect_redirect_url?: string
|
|
oidc_connect_frontend_redirect_url?: string
|
|
oidc_connect_token_auth_method?: string
|
|
oidc_connect_use_pkce?: boolean
|
|
oidc_connect_validate_id_token?: boolean
|
|
oidc_connect_allowed_signing_algs?: string
|
|
oidc_connect_clock_skew_seconds?: number
|
|
oidc_connect_require_email_verified?: boolean
|
|
oidc_connect_userinfo_email_path?: string
|
|
oidc_connect_userinfo_id_path?: string
|
|
oidc_connect_userinfo_username_path?: string
|
|
enable_model_fallback?: boolean
|
|
fallback_model_anthropic?: string
|
|
fallback_model_openai?: string
|
|
fallback_model_gemini?: string
|
|
fallback_model_antigravity?: string
|
|
enable_identity_patch?: boolean
|
|
identity_patch_prompt?: string
|
|
ops_monitoring_enabled?: boolean
|
|
ops_realtime_monitoring_enabled?: boolean
|
|
ops_query_mode_default?: 'auto' | 'raw' | 'preagg' | string
|
|
ops_metrics_interval_seconds?: number
|
|
min_claude_code_version?: string
|
|
max_claude_code_version?: string
|
|
allow_ungrouped_key_scheduling?: boolean
|
|
enable_fingerprint_unification?: boolean
|
|
enable_metadata_passthrough?: boolean
|
|
enable_cch_signing?: boolean
|
|
// Payment configuration
|
|
payment_enabled?: boolean
|
|
payment_min_amount?: number
|
|
payment_max_amount?: number
|
|
payment_daily_limit?: number
|
|
payment_order_timeout_minutes?: number
|
|
payment_max_pending_orders?: number
|
|
payment_enabled_types?: string[]
|
|
payment_balance_disabled?: boolean
|
|
payment_balance_recharge_multiplier?: number
|
|
payment_recharge_fee_rate?: number
|
|
payment_load_balance_strategy?: string
|
|
payment_product_name_prefix?: string
|
|
payment_product_name_suffix?: string
|
|
payment_help_image_url?: string
|
|
payment_help_text?: string
|
|
payment_cancel_rate_limit_enabled?: boolean
|
|
payment_cancel_rate_limit_max?: number
|
|
payment_cancel_rate_limit_window?: number
|
|
payment_cancel_rate_limit_unit?: string
|
|
payment_cancel_rate_limit_window_mode?: string
|
|
payment_visible_method_alipay_source?: string
|
|
payment_visible_method_wxpay_source?: string
|
|
payment_visible_method_alipay_enabled?: boolean
|
|
payment_visible_method_wxpay_enabled?: boolean
|
|
openai_advanced_scheduler_enabled?: boolean
|
|
// Balance & quota notification
|
|
balance_low_notify_enabled?: boolean
|
|
balance_low_notify_threshold?: number
|
|
balance_low_notify_recharge_url?: string
|
|
account_quota_notify_enabled?: boolean
|
|
account_quota_notify_emails?: NotifyEmailEntry[]
|
|
}
|
|
|
|
/**
|
|
* 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: UpdateSettingsRequest): 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
|
|
}
|
|
|
|
/**
|
|
* Admin API Key status response
|
|
*/
|
|
export interface AdminApiKeyStatus {
|
|
exists: boolean
|
|
masked_key: string
|
|
}
|
|
|
|
/**
|
|
* Get admin API key status
|
|
* @returns Status indicating if key exists and masked version
|
|
*/
|
|
export async function getAdminApiKey(): Promise<AdminApiKeyStatus> {
|
|
const { data } = await apiClient.get<AdminApiKeyStatus>('/admin/settings/admin-api-key')
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Regenerate admin API key
|
|
* @returns The new full API key (only shown once)
|
|
*/
|
|
export async function regenerateAdminApiKey(): Promise<{ key: string }> {
|
|
const { data } = await apiClient.post<{ key: string }>('/admin/settings/admin-api-key/regenerate')
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Delete admin API key
|
|
* @returns Success message
|
|
*/
|
|
export async function deleteAdminApiKey(): Promise<{ message: string }> {
|
|
const { data } = await apiClient.delete<{ message: string }>('/admin/settings/admin-api-key')
|
|
return data
|
|
}
|
|
|
|
// ==================== Overload Cooldown Settings ====================
|
|
|
|
/**
|
|
* Overload cooldown settings interface (529 handling)
|
|
*/
|
|
export interface OverloadCooldownSettings {
|
|
enabled: boolean
|
|
cooldown_minutes: number
|
|
}
|
|
|
|
export async function getOverloadCooldownSettings(): Promise<OverloadCooldownSettings> {
|
|
const { data } = await apiClient.get<OverloadCooldownSettings>('/admin/settings/overload-cooldown')
|
|
return data
|
|
}
|
|
|
|
export async function updateOverloadCooldownSettings(
|
|
settings: OverloadCooldownSettings
|
|
): Promise<OverloadCooldownSettings> {
|
|
const { data } = await apiClient.put<OverloadCooldownSettings>(
|
|
'/admin/settings/overload-cooldown',
|
|
settings
|
|
)
|
|
return data
|
|
}
|
|
|
|
// ==================== Stream Timeout Settings ====================
|
|
|
|
/**
|
|
* Stream timeout settings interface
|
|
*/
|
|
export interface StreamTimeoutSettings {
|
|
enabled: boolean
|
|
action: 'temp_unsched' | 'error' | 'none'
|
|
temp_unsched_minutes: number
|
|
threshold_count: number
|
|
threshold_window_minutes: number
|
|
}
|
|
|
|
/**
|
|
* Get stream timeout settings
|
|
* @returns Stream timeout settings
|
|
*/
|
|
export async function getStreamTimeoutSettings(): Promise<StreamTimeoutSettings> {
|
|
const { data } = await apiClient.get<StreamTimeoutSettings>('/admin/settings/stream-timeout')
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Update stream timeout settings
|
|
* @param settings - Stream timeout settings to update
|
|
* @returns Updated settings
|
|
*/
|
|
export async function updateStreamTimeoutSettings(
|
|
settings: StreamTimeoutSettings
|
|
): Promise<StreamTimeoutSettings> {
|
|
const { data } = await apiClient.put<StreamTimeoutSettings>(
|
|
'/admin/settings/stream-timeout',
|
|
settings
|
|
)
|
|
return data
|
|
}
|
|
|
|
// ==================== Rectifier Settings ====================
|
|
|
|
/**
|
|
* Rectifier settings interface
|
|
*/
|
|
export interface RectifierSettings {
|
|
enabled: boolean
|
|
thinking_signature_enabled: boolean
|
|
thinking_budget_enabled: boolean
|
|
apikey_signature_enabled: boolean
|
|
apikey_signature_patterns: string[]
|
|
}
|
|
|
|
/**
|
|
* Get rectifier settings
|
|
* @returns Rectifier settings
|
|
*/
|
|
export async function getRectifierSettings(): Promise<RectifierSettings> {
|
|
const { data } = await apiClient.get<RectifierSettings>('/admin/settings/rectifier')
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Update rectifier settings
|
|
* @param settings - Rectifier settings to update
|
|
* @returns Updated settings
|
|
*/
|
|
export async function updateRectifierSettings(
|
|
settings: RectifierSettings
|
|
): Promise<RectifierSettings> {
|
|
const { data } = await apiClient.put<RectifierSettings>(
|
|
'/admin/settings/rectifier',
|
|
settings
|
|
)
|
|
return data
|
|
}
|
|
|
|
// ==================== Beta Policy Settings ====================
|
|
|
|
/**
|
|
* Beta policy rule interface
|
|
*/
|
|
export interface BetaPolicyRule {
|
|
beta_token: string
|
|
action: 'pass' | 'filter' | 'block'
|
|
scope: 'all' | 'oauth' | 'apikey' | 'bedrock'
|
|
error_message?: string
|
|
model_whitelist?: string[]
|
|
fallback_action?: 'pass' | 'filter' | 'block'
|
|
fallback_error_message?: string
|
|
}
|
|
|
|
/**
|
|
* Beta policy settings interface
|
|
*/
|
|
export interface BetaPolicySettings {
|
|
rules: BetaPolicyRule[]
|
|
}
|
|
|
|
/**
|
|
* Get beta policy settings
|
|
* @returns Beta policy settings
|
|
*/
|
|
export async function getBetaPolicySettings(): Promise<BetaPolicySettings> {
|
|
const { data } = await apiClient.get<BetaPolicySettings>('/admin/settings/beta-policy')
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* Update beta policy settings
|
|
* @param settings - Beta policy settings to update
|
|
* @returns Updated settings
|
|
*/
|
|
export async function updateBetaPolicySettings(
|
|
settings: BetaPolicySettings
|
|
): Promise<BetaPolicySettings> {
|
|
const { data } = await apiClient.put<BetaPolicySettings>(
|
|
'/admin/settings/beta-policy',
|
|
settings
|
|
)
|
|
return data
|
|
}
|
|
|
|
// --- Web Search Emulation Config ---
|
|
|
|
export interface WebSearchProviderConfig {
|
|
type: 'brave' | 'tavily'
|
|
api_key: string
|
|
api_key_configured: boolean
|
|
quota_limit: number | null
|
|
subscribed_at: number | null
|
|
quota_used?: number
|
|
proxy_id: number | null
|
|
expires_at: number | null
|
|
}
|
|
|
|
export interface WebSearchEmulationConfig {
|
|
enabled: boolean
|
|
providers: WebSearchProviderConfig[]
|
|
}
|
|
|
|
export interface WebSearchTestResult {
|
|
provider: string
|
|
results: { url: string; title: string; snippet: string; page_age?: string }[]
|
|
query: string
|
|
}
|
|
|
|
export async function getWebSearchEmulationConfig(): Promise<WebSearchEmulationConfig> {
|
|
const { data } = await apiClient.get<WebSearchEmulationConfig>(
|
|
'/admin/settings/web-search-emulation'
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function updateWebSearchEmulationConfig(
|
|
config: WebSearchEmulationConfig
|
|
): Promise<WebSearchEmulationConfig> {
|
|
const { data } = await apiClient.put<WebSearchEmulationConfig>(
|
|
'/admin/settings/web-search-emulation',
|
|
config
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function testWebSearchEmulation(
|
|
query: string
|
|
): Promise<WebSearchTestResult> {
|
|
const { data } = await apiClient.post<WebSearchTestResult>(
|
|
'/admin/settings/web-search-emulation/test',
|
|
{ query }
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function resetWebSearchUsage(
|
|
payload: { provider_type: string }
|
|
): Promise<void> {
|
|
await apiClient.post('/admin/settings/web-search-emulation/reset-usage', payload)
|
|
}
|
|
|
|
export const settingsAPI = {
|
|
getSettings,
|
|
updateSettings,
|
|
testSmtpConnection,
|
|
sendTestEmail,
|
|
getAdminApiKey,
|
|
regenerateAdminApiKey,
|
|
deleteAdminApiKey,
|
|
getOverloadCooldownSettings,
|
|
updateOverloadCooldownSettings,
|
|
getStreamTimeoutSettings,
|
|
updateStreamTimeoutSettings,
|
|
getRectifierSettings,
|
|
updateRectifierSettings,
|
|
getBetaPolicySettings,
|
|
updateBetaPolicySettings,
|
|
getWebSearchEmulationConfig,
|
|
updateWebSearchEmulationConfig,
|
|
testWebSearchEmulation,
|
|
resetWebSearchUsage
|
|
}
|
|
|
|
export default settingsAPI
|