mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-13 06:30:20 +08:00
Merge upstream main into feat/500-api-key-ip-whitelist
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import apiClient from './client'
|
||||
import type { ModelTestCapabilities } from './endpoints/types'
|
||||
import axios from 'axios'
|
||||
import { cachedRequest, buildCacheKey } from '@/utils/cache'
|
||||
import type { BillingSummary } from './auth'
|
||||
@@ -420,6 +421,8 @@ export interface ProviderModelsQueryResponse {
|
||||
owned_by?: string
|
||||
display_name?: string
|
||||
api_format?: string
|
||||
api_formats?: string[]
|
||||
model_test_capabilities?: ModelTestCapabilities | null
|
||||
}>
|
||||
error?: string
|
||||
from_cache?: boolean
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface Announcement {
|
||||
priority: number
|
||||
is_pinned: boolean
|
||||
is_active: boolean
|
||||
requires_ack: boolean
|
||||
author: {
|
||||
id: string // UUID
|
||||
username: string
|
||||
@@ -31,6 +32,7 @@ export interface CreateAnnouncementRequest {
|
||||
type?: 'info' | 'warning' | 'maintenance' | 'important'
|
||||
priority?: number
|
||||
is_pinned?: boolean
|
||||
requires_ack?: boolean
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
}
|
||||
@@ -42,6 +44,7 @@ export interface UpdateAnnouncementRequest {
|
||||
priority?: number
|
||||
is_active?: boolean
|
||||
is_pinned?: boolean
|
||||
requires_ack?: boolean
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
}
|
||||
@@ -88,6 +91,11 @@ export const announcementApi = {
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getRequiredUnreadAnnouncements(): Promise<AnnouncementListResponse> {
|
||||
const response = await apiClient.get('/api/announcements/users/me/required-unread')
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 管理员方法
|
||||
// 创建公告
|
||||
async createAnnouncement(data: CreateAnnouncementRequest): Promise<{ id: string; title: string; message: string }> {
|
||||
@@ -106,4 +114,4 @@ export const announcementApi = {
|
||||
const response = await apiClient.delete(`/api/announcements/${id}`)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,9 @@ export interface RegisterRequest {
|
||||
username: string
|
||||
password: string
|
||||
turnstile_token?: string
|
||||
invite_code?: string
|
||||
privacy_policy_accepted?: boolean
|
||||
privacy_policy_version?: string
|
||||
}
|
||||
|
||||
export interface RegisterResponse {
|
||||
@@ -86,6 +89,14 @@ export interface RegistrationSettingsResponse {
|
||||
turnstile_enabled?: boolean
|
||||
turnstile_site_key?: string | null
|
||||
turnstile_required_actions?: string[]
|
||||
privacy_policy?: RegistrationPrivacyPolicySettings
|
||||
}
|
||||
|
||||
export interface RegistrationPrivacyPolicySettings {
|
||||
enabled: boolean
|
||||
format: 'markdown' | 'html'
|
||||
content: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export interface AuthSettingsResponse {
|
||||
|
||||
@@ -196,6 +196,7 @@ export interface RequestDetail {
|
||||
total_cost?: number
|
||||
cache_creation_cost?: number
|
||||
cache_read_cost?: number
|
||||
image_output_cost?: number
|
||||
request_cost?: number // 按次计费费用
|
||||
// Historical pricing fields (per 1M tokens)
|
||||
input_price_per_1m?: number
|
||||
|
||||
@@ -112,6 +112,7 @@ export interface PoolPresetMeta {
|
||||
export interface PoolKeyDetail {
|
||||
key_id: string
|
||||
key_name: string
|
||||
provider_type?: string | null
|
||||
is_active: boolean
|
||||
auth_type: string
|
||||
auth_type_by_format?: Record<string, 'api_key' | 'bearer'> | null
|
||||
|
||||
@@ -111,6 +111,12 @@ export async function importProviderRefreshToken(
|
||||
account_id?: string
|
||||
account_user_id?: string
|
||||
plan_type?: string
|
||||
pool_tier?: string
|
||||
sso_rw_token?: string
|
||||
cf_cookies?: string
|
||||
cf_clearance?: string
|
||||
user_agent?: string
|
||||
browser_profile?: string
|
||||
user_id?: string
|
||||
account_name?: string
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ function normalizeProviderSummary(
|
||||
...provider,
|
||||
chat_pii_redaction: normalizeChatPiiRedactionProvider(provider.chat_pii_redaction),
|
||||
pool_advanced: normalizePoolAdvanced(provider.pool_advanced),
|
||||
kiro_simulated_cache_enabled: provider.kiro_simulated_cache_enabled ?? false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ export async function updateProvider(
|
||||
providerId: string,
|
||||
data: Partial<{
|
||||
name: string
|
||||
provider_type: 'custom' | 'vertex_ai' | 'claude_code' | 'codex' | 'chatgpt_web' | 'gemini_cli' | 'antigravity' | 'kiro'
|
||||
provider_type: 'custom' | 'vertex_ai' | 'claude_code' | 'codex' | 'chatgpt_web' | 'gemini_cli' | 'antigravity' | 'kiro' | 'grok'
|
||||
description: string | null
|
||||
website: string
|
||||
provider_priority: number
|
||||
@@ -126,7 +127,7 @@ export async function updateProvider(
|
||||
export async function createProvider(
|
||||
data: {
|
||||
name: string
|
||||
provider_type?: 'custom' | 'vertex_ai' | 'claude_code' | 'codex' | 'chatgpt_web' | 'gemini_cli' | 'antigravity' | 'kiro'
|
||||
provider_type?: 'custom' | 'vertex_ai' | 'claude_code' | 'codex' | 'chatgpt_web' | 'gemini_cli' | 'antigravity' | 'kiro' | 'grok'
|
||||
description?: string
|
||||
website?: string
|
||||
billing_type?: 'monthly_quota' | 'pay_as_you_go' | 'free_tier'
|
||||
|
||||
@@ -18,9 +18,20 @@ export interface PricingTier {
|
||||
cache_ttl_pricing?: CacheTTLPricing[]
|
||||
}
|
||||
|
||||
export type ImageOutputQuality = 'low' | 'medium' | 'high'
|
||||
|
||||
export interface ImageOutputPriceRange {
|
||||
up_to_pixels: number | null
|
||||
prices: Partial<Record<ImageOutputQuality, number>>
|
||||
label?: string | null
|
||||
}
|
||||
|
||||
/** 阶梯计费配置 */
|
||||
export interface TieredPricingConfig {
|
||||
tiers: PricingTier[]
|
||||
image_output_prices?: Record<string, Record<string, number>> | null
|
||||
image_output_price_default?: number | null
|
||||
image_output_price_ranges?: ImageOutputPriceRange[] | null
|
||||
}
|
||||
|
||||
export interface Model {
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface ProxyConfig {
|
||||
url?: string
|
||||
username?: string
|
||||
password?: string
|
||||
node_id?: string // 代理节点 ID(aether-proxy 注册的节点,与 url 互斥)
|
||||
node_id?: string // 代理节点 ID(aether-tunnel 注册的节点,与 url 互斥)
|
||||
enabled?: boolean // 是否启用代理(false 时保留配置但不使用)
|
||||
}
|
||||
|
||||
@@ -389,11 +389,25 @@ export interface ChatGPTWebUpstreamMetadata {
|
||||
user_id?: string | null
|
||||
}
|
||||
|
||||
export interface GrokUpstreamMetadata {
|
||||
updated_at?: number // Unix 时间戳(秒)
|
||||
plan_type?: string | null
|
||||
pool_tier?: string | null
|
||||
is_banned?: boolean | null
|
||||
ban_reason?: string | null
|
||||
last_rate_limit_probe_at?: number | null
|
||||
clearance_state?: string | null
|
||||
email?: string | null
|
||||
account_id?: string | null
|
||||
account_user_id?: string | null
|
||||
}
|
||||
|
||||
export interface UpstreamMetadata {
|
||||
codex?: CodexUpstreamMetadata
|
||||
antigravity?: AntigravityUpstreamMetadata
|
||||
kiro?: KiroUpstreamMetadata
|
||||
chatgpt_web?: ChatGPTWebUpstreamMetadata
|
||||
grok?: GrokUpstreamMetadata
|
||||
}
|
||||
|
||||
// 按格式的健康度数据
|
||||
@@ -409,11 +423,20 @@ export interface FormatHealthData {
|
||||
// 按格式的熔断器数据
|
||||
export interface FormatCircuitBreakerData {
|
||||
open: boolean
|
||||
reason?: string | null
|
||||
open_at?: string | null
|
||||
next_probe_at?: string | null
|
||||
next_probe_at_unix_secs?: number | null
|
||||
probe_interval_minutes?: number | null
|
||||
max_probe_interval_minutes?: number | null
|
||||
failure_count?: number | null
|
||||
consecutive_failures?: number | null
|
||||
last_failure_at?: string | null
|
||||
last_probe_failure_at?: string | null
|
||||
half_open_until?: string | null
|
||||
half_open_successes: number
|
||||
half_open_failures: number
|
||||
request_results_window?: Array<{ ts: number; ok: boolean }>
|
||||
}
|
||||
|
||||
export interface EndpointAPIKeyUpdate {
|
||||
@@ -512,7 +535,7 @@ export interface PublicEndpointStatusMonitorResponse {
|
||||
formats: PublicEndpointStatusMonitor[]
|
||||
}
|
||||
|
||||
export type ProviderType = 'custom' | 'claude_code' | 'codex' | 'chatgpt_web' | 'gemini_cli' | 'antigravity' | 'kiro' | 'vertex_ai'
|
||||
export type ProviderType = 'custom' | 'claude_code' | 'codex' | 'chatgpt_web' | 'gemini_cli' | 'antigravity' | 'kiro' | 'grok' | 'vertex_ai'
|
||||
|
||||
export interface ClaudeCodeAdvancedConfig {
|
||||
// 会话数量控制:null/undefined 表示不限制
|
||||
@@ -661,6 +684,7 @@ export interface ProviderWithEndpointsSummary {
|
||||
failover_rules?: FailoverRulesConfig | null
|
||||
ops_configured: boolean // 是否配置了扩展操作(余额监控等)
|
||||
ops_architecture_id?: string // 扩展操作使用的架构 ID(如 cubence, anyrouter)
|
||||
kiro_simulated_cache_enabled?: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ export interface QuotaStatusSnapshot {
|
||||
reset_at?: number | null
|
||||
reset_seconds?: number | null
|
||||
plan_type?: string | null
|
||||
pool_tier?: string | null
|
||||
credits?: QuotaCreditsSnapshot | null
|
||||
windows?: QuotaWindowSnapshot[] | null
|
||||
}
|
||||
|
||||
@@ -61,11 +61,17 @@ export interface UsageRecordDetail {
|
||||
cost: number // 官方费率
|
||||
actual_cost?: number // 倍率消耗(仅管理员可见)
|
||||
rate_multiplier?: number // 成本倍率(仅管理员可见)
|
||||
response_time_ms?: number
|
||||
response_time_ms?: number | null
|
||||
first_byte_time_ms?: number | null
|
||||
is_stream: boolean
|
||||
upstream_is_stream?: boolean
|
||||
client_requested_stream?: boolean
|
||||
client_is_stream?: boolean
|
||||
client_family?: string | null
|
||||
client_ip?: string | null
|
||||
user_agent?: string | null
|
||||
request_path?: string | null
|
||||
request_path_and_query?: string | null
|
||||
created_at: string
|
||||
cache_creation_input_tokens?: number
|
||||
cache_creation_ephemeral_5m_input_tokens?: number
|
||||
|
||||
@@ -3,6 +3,7 @@ import apiClient from './client'
|
||||
export interface OAuthProviderInfo {
|
||||
provider_type: string
|
||||
display_name: string
|
||||
icon_url?: string | null
|
||||
}
|
||||
|
||||
export interface OAuthProvidersResponse {
|
||||
@@ -46,6 +47,7 @@ export interface OAuthProviderAdminConfig {
|
||||
frontend_callback_url: string
|
||||
attribute_mapping?: Record<string, unknown> | null
|
||||
extra_config?: Record<string, unknown> | null
|
||||
icon_url?: string | null
|
||||
is_enabled: boolean
|
||||
}
|
||||
|
||||
@@ -61,6 +63,7 @@ export interface OAuthProviderUpsertRequest {
|
||||
frontend_callback_url: string
|
||||
attribute_mapping?: Record<string, unknown> | null
|
||||
extra_config?: Record<string, unknown> | null
|
||||
icon_url?: string | null
|
||||
is_enabled: boolean
|
||||
force?: boolean
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ export interface ProxyNode {
|
||||
proxy_url?: string
|
||||
proxy_username?: string
|
||||
proxy_password?: string
|
||||
// 硬件信息(aether-proxy 节点)
|
||||
// 硬件信息(aether-tunnel 节点)
|
||||
hardware_info: Record<string, unknown> | null
|
||||
estimated_max_concurrency: number | null
|
||||
// 远程配置(aether-proxy 节点)
|
||||
// 远程配置(aether-tunnel 节点)
|
||||
remote_config: ProxyNodeRemoteConfig | null
|
||||
config_version: number
|
||||
registered_by: string | null
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import apiClient from './client'
|
||||
|
||||
export interface ReferralSummary {
|
||||
total_invites: number
|
||||
effective_invites: number
|
||||
paid_reward_usd: number
|
||||
pending_reward_usd: number
|
||||
reversed_reward_usd: number
|
||||
}
|
||||
|
||||
export interface ReferralDashboardResponse {
|
||||
invite_code: string
|
||||
invitation_link: string
|
||||
summary: ReferralSummary
|
||||
}
|
||||
|
||||
export interface ReferralRelationshipRecord {
|
||||
id: string
|
||||
inviter_user_id: string
|
||||
inviter_username?: string | null
|
||||
invitee_user_id: string
|
||||
invitee_username?: string | null
|
||||
invite_code_snapshot: string
|
||||
first_paid_order_id?: string | null
|
||||
first_paid_at_unix_secs?: number | null
|
||||
source?: Record<string, unknown> | null
|
||||
created_at_unix_secs: number
|
||||
}
|
||||
|
||||
export interface ReferralRewardRecord {
|
||||
id: string
|
||||
referral_id: string
|
||||
inviter_user_id: string
|
||||
invitee_user_id: string
|
||||
reward_type: string
|
||||
source_order_id?: string | null
|
||||
trigger_point: string
|
||||
amount_usd: number
|
||||
status: string
|
||||
wallet_transaction_id?: string | null
|
||||
idempotency_key: string
|
||||
reversed_amount_usd: number
|
||||
pending_reversal_amount_usd: number
|
||||
admin_operator_id?: string | null
|
||||
admin_note?: string | null
|
||||
created_at_unix_secs: number
|
||||
updated_at_unix_secs: number
|
||||
}
|
||||
|
||||
export interface ReferralListResponse<T> {
|
||||
items: T[]
|
||||
total: number
|
||||
limit: number
|
||||
offset: number
|
||||
stats: ReferralSummary
|
||||
}
|
||||
|
||||
export interface ReferralRelationshipQuery {
|
||||
inviter?: string
|
||||
invitee?: string
|
||||
invite_code?: string
|
||||
first_paid?: boolean | null
|
||||
limit?: number
|
||||
offset?: number
|
||||
}
|
||||
|
||||
export interface ReferralRewardQuery {
|
||||
order_id?: string
|
||||
reward_type?: string
|
||||
status?: string
|
||||
limit?: number
|
||||
offset?: number
|
||||
}
|
||||
|
||||
function cleanParams<T extends Record<string, unknown>>(params: T): Partial<T> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(params).filter(([, value]) => value !== undefined && value !== null && value !== '')
|
||||
) as Partial<T>
|
||||
}
|
||||
|
||||
export const referralApi = {
|
||||
async getMyReferral(): Promise<ReferralDashboardResponse> {
|
||||
const response = await apiClient.get<ReferralDashboardResponse>('/api/users/me/referral')
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getAdminReferrals(
|
||||
params: ReferralRelationshipQuery = {}
|
||||
): Promise<ReferralListResponse<ReferralRelationshipRecord>> {
|
||||
const response = await apiClient.get('/api/admin/referrals', {
|
||||
params: cleanParams(params as Record<string, unknown>)
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getAdminReferralRewards(
|
||||
params: ReferralRewardQuery = {}
|
||||
): Promise<ReferralListResponse<ReferralRewardRecord>> {
|
||||
const response = await apiClient.get('/api/admin/referral-rewards', {
|
||||
params: cleanParams(params as Record<string, unknown>)
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
|
||||
async retryReferralReward(id: string, note?: string): Promise<{ reward: ReferralRewardRecord }> {
|
||||
const response = await apiClient.post(`/api/admin/referral-rewards/${id}/retry`, { note })
|
||||
return response.data
|
||||
},
|
||||
|
||||
async voidReferralReward(id: string, note?: string): Promise<{ reward: ReferralRewardRecord }> {
|
||||
const response = await apiClient.post(`/api/admin/referral-rewards/${id}/void`, { note })
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,17 @@ export interface IPBlacklistEntry {
|
||||
ttl?: number
|
||||
}
|
||||
|
||||
export interface BlacklistListEntry {
|
||||
ip_address: string
|
||||
reason: string
|
||||
ttl_seconds?: number | null
|
||||
}
|
||||
|
||||
export interface BlacklistResponse {
|
||||
items: BlacklistListEntry[]
|
||||
total: number
|
||||
}
|
||||
|
||||
export interface IPWhitelistEntry {
|
||||
ip_address: string
|
||||
}
|
||||
@@ -50,6 +61,14 @@ export const blacklistApi = {
|
||||
async getStats(): Promise<BlacklistStats> {
|
||||
const response = await apiClient.get('/api/admin/security/ip/blacklist/stats')
|
||||
return response.data
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取黑名单列表
|
||||
*/
|
||||
async getList(): Promise<BlacklistResponse> {
|
||||
const response = await apiClient.get('/api/admin/security/ip/blacklist')
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ export interface UsageRecord {
|
||||
response_time?: number
|
||||
created_at: string
|
||||
has_fallback?: boolean // 🆕 是否发生了 fallback
|
||||
client_family?: string | null
|
||||
client_ip?: string | null
|
||||
user_agent?: string | null
|
||||
request_path?: string | null
|
||||
request_path_and_query?: string | null
|
||||
}
|
||||
|
||||
export interface UsageStats {
|
||||
@@ -107,6 +112,7 @@ export interface UsageFilters {
|
||||
granularity?: 'hour' | 'day' | 'week' | 'month'
|
||||
timezone?: string
|
||||
tz_offset_minutes?: number
|
||||
client_family?: string
|
||||
page?: number
|
||||
page_size?: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user