import { clearStoredAuth, getAuthorizationHeaderValue, getStoredAuth, } from "@/core/auth"; import { withCsrfHeaders } from "./csrf"; function withAuthHeaders(headers?: HeadersInit): Headers { const next = withCsrfHeaders(headers); const authHeader = getAuthorizationHeaderValue(); if (authHeader && !next.has("Authorization")) { next.set("Authorization", authHeader); } return next; } function requestUrl(input: RequestInfo | URL): string { if (typeof input === "string") return input; if (input instanceof URL) return input.href; return (input as Request).url ?? ""; } export async function apiFetch(input: RequestInfo | URL, init?: RequestInit) { const response = await fetch(input, { ...init, credentials: init?.credentials ?? "include", headers: withAuthHeaders(init?.headers), }); // Session is considered lost ONLY when the backend actually answers 401. // (Previously a stray localStorage change could log the user out client-side // even though the session was still valid.) Auth endpoints are excluded so a // failed/transient login attempt never wipes state, and we only act when we // believed we were logged in — avoiding redirect loops on the login page. if (response.status === 401) { const url = requestUrl(input); const isAuthEndpoint = url.includes("/api/v1/auth/"); if (!isAuthEndpoint && getStoredAuth()) { clearStoredAuth(); if ( typeof window !== "undefined" && !window.location.hash.startsWith("#/login") ) { window.location.replace("#/login"); } } } return response; }