08fe06d074
Co-authored-by: Cursor <cursoragent@cursor.com>
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
const TOKEN_KEY = "control_token";
|
|
const USER_KEY = "control_user";
|
|
|
|
export function getToken(): string | null {
|
|
return localStorage.getItem(TOKEN_KEY);
|
|
}
|
|
|
|
export function getUsername(): string | null {
|
|
return localStorage.getItem(USER_KEY);
|
|
}
|
|
|
|
export function setSession(token: string, username: string) {
|
|
localStorage.setItem(TOKEN_KEY, token);
|
|
localStorage.setItem(USER_KEY, username);
|
|
}
|
|
|
|
export function clearSession() {
|
|
localStorage.removeItem(TOKEN_KEY);
|
|
localStorage.removeItem(USER_KEY);
|
|
}
|
|
|
|
export async function apiFetch<T>(
|
|
path: string,
|
|
options: RequestInit = {},
|
|
): Promise<T> {
|
|
const headers = new Headers(options.headers || {});
|
|
if (!headers.has("Content-Type") && options.body) {
|
|
headers.set("Content-Type", "application/json");
|
|
}
|
|
const token = getToken();
|
|
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
const res = await fetch(path, { ...options, headers });
|
|
const text = await res.text();
|
|
let data: unknown = null;
|
|
try {
|
|
data = text ? JSON.parse(text) : null;
|
|
} catch {
|
|
data = { detail: text };
|
|
}
|
|
if (res.status === 401) {
|
|
// 仅中控自身鉴权失败才清会话;勿把策略机错误当成掉登录
|
|
clearSession();
|
|
const detail =
|
|
typeof data === "object" && data && "detail" in data
|
|
? String((data as { detail: unknown }).detail)
|
|
: "unauthorized";
|
|
throw new Error(detail || "unauthorized");
|
|
}
|
|
if (!res.ok) {
|
|
const detail =
|
|
typeof data === "object" && data && "detail" in data
|
|
? String((data as { detail: unknown }).detail)
|
|
: res.statusText;
|
|
throw new Error(detail || `HTTP ${res.status}`);
|
|
}
|
|
return data as T;
|
|
}
|
|
|
|
export async function login(username: string, password: string) {
|
|
const res = await apiFetch<{ token: string; username: string }>(
|
|
"/api/auth/login",
|
|
{
|
|
method: "POST",
|
|
body: JSON.stringify({ username, password }),
|
|
},
|
|
);
|
|
setSession(res.token, res.username);
|
|
return res;
|
|
}
|
|
|
|
export type NodeCard = {
|
|
id: number;
|
|
name: string;
|
|
base_url: string;
|
|
token_configured: boolean;
|
|
online?: boolean;
|
|
health?: Record<string, unknown> | null;
|
|
fleet?: Record<string, unknown> | null;
|
|
fleet_ok?: boolean;
|
|
fleet_error?: string | null;
|
|
error?: string | null;
|
|
};
|