wg_index/frontend/js/api.js
2025-12-27 05:02:10 +03:00

97 lines
3 KiB
JavaScript
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { CONFIG } from "./config.js";
import { loadSession, saveSession, clearSession } from "./storage.js";
function urlJoin(base, path) {
if (!base) return path;
return base.replace(/\/+$/, "") + "/" + path.replace(/^\/+/, "");
}
async function parseResponse(res) {
const ct = (res.headers.get("content-type") || "").toLowerCase();
if (ct.includes("application/json")) return await res.json();
const text = await res.text();
// иногда сервер шлёт json как text/plain
try { return JSON.parse(text); } catch { return text; }
}
export async function renewTokens() {
const s = loadSession();
if (!s) throw new Error("NO_SESSION");
// /renew/ ждёт user_id и live_token в headers :contentReference[oaicite:1]{index=1}
const res = await fetch(urlJoin(CONFIG.API_BASE_URL, CONFIG.ENDPOINTS.renew), {
method: "GET",
headers: {
"user_id": String(s.user_id),
"live_token": String(s.live_token)
}
});
if (res.status === CONFIG.AUTH_ERROR_STATUS) {
clearSession();
throw new Error("RENEW_DENIED");
}
if (!res.ok) {
const body = await parseResponse(res);
throw new Error(typeof body === "string" ? body : "RENEW_FAILED");
}
const data = await parseResponse(res);
if (!data?.short_token || !data?.live_token) {
throw new Error("BAD_RENEW_RESPONSE");
}
const next = { ...s, short_token: data.short_token, live_token: data.live_token };
saveSession(next);
return next;
}
export async function apiFetch(path, {
method = "GET",
headers = {},
body = null,
auth = true
} = {}) {
const s = loadSession();
const reqHeaders = { ...headers };
if (auth) {
if (!s?.short_token) throw new Error("NO_AUTH");
// Все защищённые ручки проверяют short_token в headers :contentReference[oaicite:2]{index=2}
reqHeaders["short_token"] = String(s.short_token);
}
const doRequest = async () => {
const res = await fetch(urlJoin(CONFIG.API_BASE_URL, path), {
method,
headers: {
...reqHeaders,
...(body ? { "content-type": "application/json" } : {})
},
body: body ? JSON.stringify(body) : null
});
return res;
};
let res = await doRequest();
// Авто-обновление токенов при 426 :contentReference[oaicite:3]{index=3}
if (auth && res.status === CONFIG.AUTH_ERROR_STATUS) {
await renewTokens();
// обновим заголовок short_token и повторим один раз
const s2 = loadSession();
reqHeaders["short_token"] = String(s2.short_token);
res = await doRequest();
}
const payload = await parseResponse(res);
if (!res.ok) {
const err = new Error("API_ERROR");
err.status = res.status;
err.payload = payload;
throw err;
}
return payload;
}