63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
import type { ApiSettings } from "../types";
|
|
|
|
const STORAGE_KEY = "multimailer.apiSettings";
|
|
|
|
export function loadApiSettings(): ApiSettings {
|
|
const storedBaseUrl = localStorage.getItem(`${STORAGE_KEY}.baseUrl`);
|
|
|
|
return {
|
|
// Empty base URL means "same origin". In Vite dev, /api is proxied to FastAPI.
|
|
apiBaseUrl:
|
|
storedBaseUrl !== null
|
|
? storedBaseUrl
|
|
: import.meta.env.VITE_API_BASE_URL ?? "",
|
|
apiKey: localStorage.getItem(`${STORAGE_KEY}.apiKey`) || "",
|
|
accessToken: localStorage.getItem(`${STORAGE_KEY}.accessToken`) || ""
|
|
};
|
|
}
|
|
|
|
export function saveApiSettings(settings: ApiSettings): void {
|
|
localStorage.setItem(`${STORAGE_KEY}.baseUrl`, settings.apiBaseUrl);
|
|
localStorage.setItem(`${STORAGE_KEY}.apiKey`, settings.apiKey);
|
|
localStorage.setItem(`${STORAGE_KEY}.accessToken`, settings.accessToken);
|
|
}
|
|
|
|
export function clearAccessToken(): void {
|
|
localStorage.removeItem(`${STORAGE_KEY}.accessToken`);
|
|
}
|
|
|
|
export async function apiFetch<T>(settings: ApiSettings, path: string, init?: RequestInit): Promise<T> {
|
|
const baseUrl = settings.apiBaseUrl.trim().replace(/\/$/, "");
|
|
const url = baseUrl ? `${baseUrl}${path}` : path;
|
|
|
|
const headers = new Headers(init?.headers || {});
|
|
|
|
if (!(init?.body instanceof FormData) && !headers.has("Content-Type")) {
|
|
headers.set("Content-Type", "application/json");
|
|
}
|
|
|
|
if (settings.accessToken) {
|
|
headers.set("Authorization", `Bearer ${settings.accessToken}`);
|
|
} else if (settings.apiKey) {
|
|
headers.set("X-API-Key", settings.apiKey);
|
|
}
|
|
|
|
const response = await fetch(url, { ...init, headers });
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text();
|
|
throw new Error(`${response.status} ${response.statusText}: ${text}`);
|
|
}
|
|
|
|
if (response.status === 204) {
|
|
return undefined as T;
|
|
}
|
|
|
|
const contentType = response.headers.get("content-type") || "";
|
|
if (!contentType.includes("application/json")) {
|
|
return (await response.text()) as T;
|
|
}
|
|
|
|
return (await response.json()) as T;
|
|
}
|