const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "/backend"; export class ApiError extends Error { status: number; code: number | string | undefined; constructor(message: string, status: number, code?: number | string) { super(message); this.name = "ApiError"; this.status = status; this.code = code; } } export async function apiFetch(path: string, init: RequestInit = {}): Promise { const token = typeof window === "undefined" ? null : localStorage.getItem("huaxia_token"); const headers = new Headers(init.headers); headers.set("Content-Type", "application/json"); if (token) headers.set("Authorization", `Bearer ${token}`); const response = await fetch(`${API_BASE_URL}${path}`, { ...init, headers, cache: "no-store", }); const payload = await response.json().catch(() => null); if (response.status === 401 && typeof window !== "undefined") { localStorage.removeItem("huaxia_token"); if (!window.location.pathname.startsWith("/login")) window.location.href = "/login"; } if (!response.ok || (payload && payload.code !== 200)) { throw new ApiError( payload?.message ?? "请求失败,请稍后重试", response.status, payload?.code ); } return (payload?.data ?? payload) as T; } export async function apiStream(path: string, body: unknown): Promise { const token = typeof window === "undefined" ? null : localStorage.getItem("huaxia_token"); const headers = new Headers({ "Content-Type": "application/json", Accept: "text/event-stream" }); if (token) headers.set("Authorization", `Bearer ${token}`); const response = await fetch(`${API_BASE_URL}${path}`, { method: "POST", headers, body: JSON.stringify(body), cache: "no-store", }); if (!response.ok) throw new ApiError("请求失败,请稍后重试", response.status); const text = await response.text(); const event = text.split("\n").find((line) => line.startsWith("data:")); if (!event) return text; const payload = JSON.parse(event.slice(5).trim()) as { content?: string; answer?: string; message?: string }; return payload.content ?? payload.answer ?? payload.message ?? text; }