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; }