apiFetch now redirects to login only on a genuine backend 401 (auth endpoints excluded, only when previously logged in). AuthSyncWatcher no longer treats localStorage.clear()/unrelated writes as a logout, fixing spurious sign-outs (e.g. when uploading skills). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
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;
|
|
}
|
|
|