const AUTH_STATE_COOKIE = "magent_logged_in"; export const getApiBase = () => process.env.NEXT_PUBLIC_API_BASE ?? "/api"; const setCookie = (name: string, value: string, maxAgeSeconds: number) => { if (typeof document === "undefined") return; document.cookie = `${name}=${value}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`; }; const clearCookie = (name: string) => { if (typeof document === "undefined") return; document.cookie = `${name}=; Max-Age=0; Path=/; SameSite=Lax`; }; export const getToken = () => { if (typeof document === "undefined") return null; const cookies = document.cookie.split(";").map((entry) => entry.trim()); const marker = cookies.find((entry) => entry.startsWith(`${AUTH_STATE_COOKIE}=`)); if (!marker) return null; const [, value] = marker.split("=", 2); return value || null; }; export const setToken = (_token: string) => { setCookie(AUTH_STATE_COOKIE, "1", 60 * 60 * 12); }; export const clearToken = () => { clearCookie(AUTH_STATE_COOKIE); if (typeof window === "undefined") return; const baseUrl = getApiBase(); void fetch(`${baseUrl}/auth/logout`, { method: "POST", credentials: "include", keepalive: true, }).catch(() => undefined); }; export const logout = async () => { const baseUrl = getApiBase(); clearCookie(AUTH_STATE_COOKIE); await fetch(`${baseUrl}/auth/logout`, { method: "POST", credentials: "include", }); }; export const authFetch = (input: RequestInfo | URL, init?: RequestInit) => { const headers = new Headers(init?.headers || {}); return fetch(input, { ...init, headers, credentials: "include" }); }; export const getEventStreamToken = async () => { const baseUrl = getApiBase(); const response = await authFetch(`${baseUrl}/auth/stream-token`); if (!response.ok) { const text = await response.text(); throw new Error(text || `Stream token request failed: ${response.status}`); } const data = await response.json(); const token = typeof data?.stream_token === "string" ? data.stream_token : ""; if (!token) { throw new Error("Stream token not returned"); } return token; }; export class UnauthorizedError extends Error { constructor() { super("Unauthorized"); this.name = "UnauthorizedError"; } } export class ForbiddenError extends Error { constructor() { super("Forbidden"); this.name = "ForbiddenError"; } } export const authFetchOrThrow = async (input: RequestInfo | URL, init?: RequestInit) => { const response = await authFetch(input, init); if (response.status === 401) { clearToken(); throw new UnauthorizedError(); } if (response.status === 403) { throw new ForbiddenError(); } return response; }; export const readResponseText = async (response: Response) => { try { return (await response.text()).trim(); } catch { return ""; } };