Files
nas-tools/dashboard/frontend/src/lib/api.js
T
Gan, Jimmy 910ed3f7e6
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 2m45s
feat: add LiteLLM health page to dashboard
Expose LiteLLM operational status in the NAS Dashboard UI so auth-required and outage states are visible without calling backend APIs directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 03:50:56 +08:00

149 lines
3.4 KiB
JavaScript

const BASE = "/api";
let token = localStorage.getItem("token") || "";
// Current user info populated after auth
export let currentUser = { username: "", role: "", pages: [] };
export function setCurrentUser(u) {
currentUser = u;
}
export function setToken(t) {
token = t;
if (t) localStorage.setItem("token", t);
else localStorage.removeItem("token");
}
export function getToken() {
return token;
}
export function setRefreshToken(t) {
if (t) localStorage.setItem("refresh_token", t);
else localStorage.removeItem("refresh_token");
}
function getRefreshToken() {
return localStorage.getItem("refresh_token") || "";
}
let refreshPromise = null;
async function tryRefresh() {
if (refreshPromise) return refreshPromise;
const rt = getRefreshToken();
if (!rt) return false;
refreshPromise = (async () => {
try {
const r = await fetch(BASE + "/auth/refresh", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ refresh_token: rt }),
});
if (!r.ok) return false;
const data = await r.json();
setToken(data.access_token);
setRefreshToken(data.refresh_token);
return true;
} catch {
return false;
} finally {
refreshPromise = null;
}
})();
return refreshPromise;
}
async function request(path, opts = {}) {
const headers = opts.headers || {};
if (token) headers["Authorization"] = `Bearer ${token}`;
if (opts.json) {
headers["Content-Type"] = "application/json";
opts.body = JSON.stringify(opts.json);
delete opts.json;
}
try {
let r = await fetch(BASE + path, { ...opts, headers });
if (r.status === 401 && !path.includes("/auth/refresh")) {
const refreshed = await tryRefresh();
if (refreshed) {
headers["Authorization"] = `Bearer ${token}`;
r = await fetch(BASE + path, { ...opts, headers });
}
}
if (r.status === 401) {
setToken("");
setRefreshToken("");
throw new Error("Unauthorized");
}
if (!r.ok) {
const error = new Error(`HTTP ${r.status}`);
error.status = r.status;
try { error.body = await r.json(); } catch { }
throw error;
}
return r.json();
} catch (e) {
console.error(`API ${opts.method || "GET"} ${path}:`, e);
throw e;
}
}
export function get(path) {
return request(path);
}
export function post(path, data) {
return request(path, { method: "POST", json: data });
}
export function del(path) {
return request(path, { method: "DELETE" });
}
export async function upload(path, file) {
const headers = {};
if (token) headers["Authorization"] = `Bearer ${token}`;
const form = new FormData();
form.append("file", file);
const r = await fetch(`${BASE}/files/upload?path=${encodeURIComponent(path)}`, {
method: "POST",
headers,
body: form,
});
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
}
export function login(creds) {
return request("/auth/login", { method: "POST", json: creds });
}
export function checkAuth() {
return request("/auth/me");
}
export function getPreferences() {
return get("/auth/preferences");
}
export function savePreferences(data) {
return request("/auth/preferences", { method: "PUT", json: data });
}
export function getLiteLLMHealth() {
return get("/litellm/health");
}
export function put(path, data) {
return request(path, { method: "PUT", json: data });
}