/** * 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 type WeChatConnectMode = "open" | "mp" | "mobile"; export interface PaymentVisibleMethodSourceOption { value: PaymentVisibleMethodSource; labelZh: string; labelEn: string; } export interface WeChatConnectModeOption { value: WeChatConnectMode; 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 > = { 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", }, }; const WECHAT_CONNECT_MODE_OPTIONS: WeChatConnectModeOption[] = [ { value: "open", labelZh: "PC 应用", labelEn: "PC App" }, { value: "mp", labelZh: "公众号", labelEn: "Official Account", }, { value: "mobile", labelZh: "移动应用", labelEn: "Mobile App", }, ]; const WECHAT_CONNECT_MODE_ALIASES: Record = { open: "open", open_platform: "open", official: "open", wx_open: "open", mp: "mp", official_account: "mp", wechat_mp: "mp", mini_program: "mp", mobile: "mobile", mobile_app: "mobile", native_app: "mobile", }; 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, ): AuthSourceDefaultsState { const raw = settings as Record; 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`] === true, 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; 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] ?? ""; } export function getWeChatConnectModeOptions(): WeChatConnectModeOption[] { return WECHAT_CONNECT_MODE_OPTIONS; } export function normalizeWeChatConnectMode(source: unknown): WeChatConnectMode { if (typeof source !== "string") return "open"; const normalized = source.trim().toLowerCase(); if (!normalized) return "open"; return WECHAT_CONNECT_MODE_ALIASES[normalized] ?? "open"; } export function defaultWeChatConnectScopesForMode(mode: unknown): string { switch (normalizeWeChatConnectMode(mode)) { case "mp": return "snsapi_userinfo"; case "mobile": return ""; default: return "snsapi_login"; } } export function resolveWeChatConnectModeCapabilities( openEnabled: unknown, mpEnabled: unknown, mobileEnabled: unknown, legacyMode: unknown, ): { openEnabled: boolean; mpEnabled: boolean; mobileEnabled: boolean } { if ( typeof openEnabled === "boolean" || typeof mpEnabled === "boolean" || typeof mobileEnabled === "boolean" ) { return { openEnabled: openEnabled === true, mpEnabled: mpEnabled === true, mobileEnabled: mobileEnabled === true, }; } switch (normalizeWeChatConnectMode(legacyMode)) { case "mp": return { openEnabled: false, mpEnabled: true, mobileEnabled: false }; case "mobile": return { openEnabled: false, mpEnabled: false, mobileEnabled: true }; default: return { openEnabled: true, mpEnabled: false, mobileEnabled: false }; } } export function deriveWeChatConnectStoredMode( openEnabled: boolean, mpEnabled: boolean, mobileEnabled: boolean, legacyMode: unknown, ): WeChatConnectMode { if (mpEnabled) return "mp"; if (mobileEnabled) return "mobile"; if (openEnabled) return "open"; return normalizeWeChatConnectMode(legacyMode); } /** * 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; affiliate_rebate_rate: number; default_concurrency: number; default_user_rpm_limit: 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; // WeChat Connect OAuth settings wechat_connect_enabled: boolean; wechat_connect_app_id: string; wechat_connect_app_secret_configured: boolean; wechat_connect_open_app_id?: string; wechat_connect_open_app_secret_configured?: boolean; wechat_connect_mp_app_id?: string; wechat_connect_mp_app_secret_configured?: boolean; wechat_connect_mobile_app_id?: string; wechat_connect_mobile_app_secret_configured?: boolean; wechat_connect_open_enabled?: boolean; wechat_connect_mp_enabled?: boolean; wechat_connect_mobile_enabled?: boolean; wechat_connect_mode: string; wechat_connect_scopes: string; wechat_connect_redirect_url: string; wechat_connect_frontend_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[]; // Channel Monitor feature switch channel_monitor_enabled: boolean; channel_monitor_default_interval_seconds: number; // Available Channels feature switch available_channels_enabled: boolean; } 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; affiliate_rebate_rate?: number; default_concurrency?: number; default_user_rpm_limit?: 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; wechat_connect_enabled?: boolean; wechat_connect_app_id?: string; wechat_connect_app_secret?: string; wechat_connect_open_app_id?: string; wechat_connect_open_app_secret?: string; wechat_connect_mp_app_id?: string; wechat_connect_mp_app_secret?: string; wechat_connect_mobile_app_id?: string; wechat_connect_mobile_app_secret?: string; wechat_connect_open_enabled?: boolean; wechat_connect_mp_enabled?: boolean; wechat_connect_mobile_enabled?: boolean; wechat_connect_mode?: string; wechat_connect_scopes?: string; wechat_connect_redirect_url?: string; wechat_connect_frontend_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[]; // Channel Monitor feature switch channel_monitor_enabled?: boolean; channel_monitor_default_interval_seconds?: number; // Available Channels feature switch available_channels_enabled?: boolean; } /** * Get all system settings * @returns System settings */ export async function getSettings(): Promise { const { data } = await apiClient.get("/admin/settings"); return data; } /** * Update system settings * @param settings - Partial settings to update * @returns Updated settings */ export async function updateSettings( settings: UpdateSettingsRequest, ): Promise { const { data } = await apiClient.put( "/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 { const { data } = await apiClient.get( "/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 { const { data } = await apiClient.get( "/admin/settings/overload-cooldown", ); return data; } export async function updateOverloadCooldownSettings( settings: OverloadCooldownSettings, ): Promise { const { data } = await apiClient.put( "/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 { const { data } = await apiClient.get( "/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 { const { data } = await apiClient.put( "/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 { const { data } = await apiClient.get( "/admin/settings/rectifier", ); return data; } /** * Update rectifier settings * @param settings - Rectifier settings to update * @returns Updated settings */ export async function updateRectifierSettings( settings: RectifierSettings, ): Promise { const { data } = await apiClient.put( "/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 { const { data } = await apiClient.get( "/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 { const { data } = await apiClient.put( "/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 { const { data } = await apiClient.get( "/admin/settings/web-search-emulation", ); return data; } export async function updateWebSearchEmulationConfig( config: WebSearchEmulationConfig, ): Promise { const { data } = await apiClient.put( "/admin/settings/web-search-emulation", config, ); return data; } export async function testWebSearchEmulation( query: string, ): Promise { const { data } = await apiClient.post( "/admin/settings/web-search-emulation/test", { query }, ); return data; } export async function resetWebSearchUsage(payload: { provider_type: string; }): Promise { 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;