first wokring prototype

This commit is contained in:
2026-06-10 04:10:02 +02:00
parent 50d779a537
commit 7491c0a1b4
90 changed files with 10799 additions and 1 deletions

62
src/api/client.ts Normal file
View File

@@ -0,0 +1,62 @@
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;
}