- 拆分管理台入口为 App/feature/core 结构并更新样式/配置 - 规范 worker 路由/中间件/服务类型与 JSON 解析 - 同步工具链与知识库记录
41 lines
1.1 KiB
TypeScript
41 lines
1.1 KiB
TypeScript
import { apiBase } from "./constants";
|
|
|
|
export type ApiFetch = <T>(path: string, options?: RequestInit) => Promise<T>;
|
|
|
|
/**
|
|
* Creates a typed API fetcher bound to the current auth token.
|
|
*
|
|
* Args:
|
|
* token: Bearer token string or null.
|
|
* onUnauthorized: Callback invoked on 401 responses.
|
|
*
|
|
* Returns:
|
|
* A fetch function that wraps API calls with auth headers and errors.
|
|
*/
|
|
export const createApiFetch = (
|
|
token: string | null,
|
|
onUnauthorized: () => void,
|
|
): ApiFetch => {
|
|
return async <T>(path: string, options: RequestInit = {}): Promise<T> => {
|
|
const headers = new Headers(options.headers ?? {});
|
|
headers.set("Content-Type", "application/json");
|
|
if (token) {
|
|
headers.set("Authorization", `Bearer ${token}`);
|
|
}
|
|
const response = await fetch(`${apiBase}${path}`, {
|
|
...options,
|
|
headers,
|
|
});
|
|
if (!response.ok) {
|
|
if (response.status === 401) {
|
|
onUnauthorized();
|
|
}
|
|
const payload = (await response.json().catch(() => null)) as {
|
|
error?: string;
|
|
} | null;
|
|
throw new Error(payload?.error ?? `HTTP ${response.status}`);
|
|
}
|
|
return response.json() as Promise<T>;
|
|
};
|
|
};
|