136 lines
3.9 KiB
TypeScript
136 lines
3.9 KiB
TypeScript
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<T>(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<T>(res: AxiosResponse<unknown>): T {
|
|
return unwrapData<T>(res.data);
|
|
}
|
|
|
|
/** 登录/验证码等:**不**附加 `Authorization`。 */
|
|
export async function publicAdminRequest<T>(
|
|
config: AxiosRequestConfig,
|
|
): Promise<T> {
|
|
try {
|
|
const res = await adminHttp.request<unknown>(
|
|
withAdminLocaleHeaders(config),
|
|
);
|
|
return unwrapResponse<T>(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<T>(config: AxiosRequestConfig): Promise<T> {
|
|
const merged = withAdminAuthHeader(withAdminLocaleHeaders(config));
|
|
try {
|
|
const res = await adminHttp.request<unknown>(merged);
|
|
return unwrapResponse<T>(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: <T>(url: string, config?: Omit<AxiosRequestConfig, "url" | "method">) =>
|
|
request<T>({ ...config, url, method: "GET" }),
|
|
|
|
delete: <T>(url: string, config?: Omit<AxiosRequestConfig, "url" | "method">) =>
|
|
request<T>({ ...config, url, method: "DELETE" }),
|
|
|
|
post: <T>(
|
|
url: string,
|
|
data?: unknown,
|
|
config?: Omit<AxiosRequestConfig, "url" | "method" | "data">,
|
|
) => request<T>({ ...config, url, method: "POST", data }),
|
|
|
|
patch: <T>(
|
|
url: string,
|
|
data?: unknown,
|
|
config?: Omit<AxiosRequestConfig, "url" | "method" | "data">,
|
|
) => request<T>({ ...config, url, method: "PATCH", data }),
|
|
|
|
put: <T>(
|
|
url: string,
|
|
data?: unknown,
|
|
config?: Omit<AxiosRequestConfig, "url" | "method" | "data">,
|
|
) => request<T>({ ...config, url, method: "PUT", data }),
|
|
};
|
|
|
|
export async function clearAdminSessionCookie(): Promise<void> {
|
|
await adminHttp.request({
|
|
url: "/admin/auth/logout",
|
|
method: "POST",
|
|
validateStatus: () => true,
|
|
});
|
|
}
|