102 lines
2.4 KiB
TypeScript
102 lines
2.4 KiB
TypeScript
import { storage } from '../storage';
|
|
|
|
const BASE_URL = 'https://api.mixvideo.bowong.cc';
|
|
|
|
export interface ApiRequestOptions {
|
|
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
body?: string;
|
|
params?: Record<string, any>;
|
|
headers?: Record<string, string>;
|
|
requiresAuth?: boolean;
|
|
}
|
|
|
|
type UnauthorizedListener = () => void;
|
|
const unauthorizedListeners: UnauthorizedListener[] = [];
|
|
|
|
export const authEvents = {
|
|
onUnauthorized(listener: UnauthorizedListener) {
|
|
unauthorizedListeners.push(listener);
|
|
return () => {
|
|
const index = unauthorizedListeners.indexOf(listener);
|
|
if (index > -1) unauthorizedListeners.splice(index, 1);
|
|
};
|
|
},
|
|
emitUnauthorized() {
|
|
unauthorizedListeners.forEach(listener => listener());
|
|
}
|
|
};
|
|
|
|
async function getAuthToken(): Promise<string> {
|
|
return (await storage.getItem(`bestaibest.better-auth.session_token`)) || '';
|
|
}
|
|
|
|
export async function apiRequest<T = any>(
|
|
endpoint: string,
|
|
options: ApiRequestOptions = {}
|
|
): Promise<T> {
|
|
const {
|
|
method = 'GET',
|
|
body,
|
|
params,
|
|
headers = {},
|
|
requiresAuth = true,
|
|
} = options;
|
|
|
|
// 构建 URL
|
|
const url = new URL(endpoint, BASE_URL);
|
|
|
|
// 添加查询参数
|
|
if (params) {
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) {
|
|
url.searchParams.append(key, String(value));
|
|
}
|
|
});
|
|
}
|
|
|
|
// 准备请求头
|
|
const requestHeaders: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...headers,
|
|
};
|
|
|
|
// 如果需要认证,添加 Bearer token
|
|
if (requiresAuth) {
|
|
const token = await getAuthToken();
|
|
if (token) {
|
|
requestHeaders['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
}
|
|
|
|
// 发起请求
|
|
const response = await fetch(url.toString(), {
|
|
method,
|
|
headers: requestHeaders,
|
|
body: method !== 'GET' ? body : undefined,
|
|
});
|
|
|
|
// 检查 401 未授权
|
|
if (response.status === 401) {
|
|
authEvents.emitUnauthorized();
|
|
throw new Error(`HTTP 401: Unauthorized`);
|
|
}
|
|
|
|
// 检查其他错误状态
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
export async function apiClient<T = any>(
|
|
endpoint: string,
|
|
options: ApiRequestOptions = {}
|
|
): Promise<T> {
|
|
return apiRequest<T>(endpoint, {
|
|
...options,
|
|
requiresAuth: true,
|
|
});
|
|
}
|