import axios, { isAxiosError, type AxiosRequestConfig, type AxiosResponse, } from "axios"; import { withAdminAuthHeader } from "@/lib/admin-auth"; import { handleAdminAuthRejected, isAdminAuthRejected, } from "@/lib/admin-auth-reject"; import { withAdminLocaleHeaders } from "@/lib/admin-locale"; import { LotteryApiBizError, LotteryApiEnvelopeError } from "@/types/api/errors"; import { isApiEnvelope } from "@/types/api/envelope"; import { resolveLotteryApiV1Base } from "@/lib/lottery-api-base"; export { hasLotteryAdminApiBaseUrl } from "@/lib/lottery-api-env"; export const adminHttp = axios.create({ baseURL: resolveLotteryApiV1Base(), timeout: 30_000, headers: { Accept: "application/json" }, }); adminHttp.interceptors.response.use( (response) => response, (error: unknown) => { if (isAdminAuthRejected(error)) { handleAdminAuthRejected(error); } if (isAxiosError(error) && typeof window !== "undefined") { const status = error.response?.status; if (status === 500 || status === 502 || status === 503) { console.error("[admin-http] upstream unavailable", status); } if (!error.response && error.message?.includes("Network Error")) { console.error("[admin-http] network offline or upstream unreachable"); } } return Promise.reject(error); }, ); function rejectAfterAuthCheck(err: unknown): never { if (isAdminAuthRejected(err)) { handleAdminAuthRejected(err); } throw err; } export function unwrapData(payload: unknown): T { if (!isApiEnvelope(payload)) { throw new LotteryApiEnvelopeError(); } if (payload.code !== 0) { throw new LotteryApiBizError(payload.msg, payload.code, payload.data); } return payload.data as T; } export function unwrapResponse(res: AxiosResponse): T { return unwrapData(res.data); } /** 登录/验证码等:**不**附加 `Authorization`。 */ export async function publicAdminRequest( config: AxiosRequestConfig, ): Promise { try { const res = await adminHttp.request( withAdminLocaleHeaders(config), ); return unwrapResponse(res); } catch (err: unknown) { if (isAxiosError(err) && err.response?.data !== undefined) { const body = err.response.data; if (isApiEnvelope(body) && body.code !== 0) { throw new LotteryApiBizError(body.msg, body.code, body.data); } } rejectAfterAuthCheck(err); } } export async function request(config: AxiosRequestConfig): Promise { const merged = withAdminAuthHeader(withAdminLocaleHeaders(config)); try { const res = await adminHttp.request(merged); return unwrapResponse(res); } catch (err: unknown) { if (isAxiosError(err) && err.response?.data !== undefined) { const body = err.response.data; if (isApiEnvelope(body) && body.code !== 0) { throw new LotteryApiBizError(body.msg, body.code, body.data); } } rejectAfterAuthCheck(err); } } export const adminRequest = { request, get: (url: string, config?: Omit) => request({ ...config, url, method: "GET" }), delete: (url: string, config?: Omit) => request({ ...config, url, method: "DELETE" }), post: ( url: string, data?: unknown, config?: Omit, ) => request({ ...config, url, method: "POST", data }), patch: ( url: string, data?: unknown, config?: Omit, ) => request({ ...config, url, method: "PATCH", data }), put: ( url: string, data?: unknown, config?: Omit, ) => request({ ...config, url, method: "PUT", data }), }; export async function clearAdminSessionCookie(): Promise { await adminHttp.request({ url: "/admin/auth/logout", method: "POST", validateStatus: () => true, }); }