intermittent commit

This commit is contained in:
2026-07-14 13:22:10 +02:00
parent 8aa1943581
commit e6f7c45f0a
76 changed files with 6039 additions and 2188 deletions

View File

@@ -1,9 +1,9 @@
import type { ApiSettings } from "../types";
const STORAGE_KEY = "multimailer.apiSettings";
const LEGACY_STORAGE_KEYS = ["i18n:govoplan-core.multimailer_apisettings.1d1601d4"];
const SESSION_STORAGE_KEY = "multimailer.session";
const CSRF_COOKIE_NAME = import.meta.env.VITE_CSRF_COOKIE_NAME ?? "msm_csrf";
const STORAGE_KEY = "govoplan.apiSettings";
const LEGACY_STORAGE_KEYS: string[] = [];
const SESSION_STORAGE_KEY = "govoplan.session";
const CSRF_COOKIE_NAME = import.meta.env.VITE_CSRF_COOKIE_NAME ?? "govoplan_csrf";
const RECENT_SAFE_REQUEST_TTL_MS = 750;
const MAX_RECENT_SAFE_REQUESTS = 100;
const MAX_CONDITIONAL_SAFE_REQUESTS = 200;
@@ -77,6 +77,56 @@ export function apiUrl(settings: ApiSettings, path: string): string {
return baseUrl ? `${baseUrl}${normalizedPath}` : normalizedPath;
}
export type ApiQueryValue = string | number | boolean | null | undefined;
export type ApiQueryParams = Record<string, ApiQueryValue | readonly ApiQueryValue[]>;
function queryValue(value: ApiQueryValue): string | null {
if (value === null || value === undefined || value === "") return null;
return String(value);
}
export function apiQuery(params: ApiQueryParams = {}): string {
const search = new URLSearchParams();
for (const [key, rawValue] of Object.entries(params)) {
const values = Array.isArray(rawValue) ? rawValue : [rawValue];
for (const value of values) {
const normalized = queryValue(value);
if (normalized !== null) search.append(key, normalized);
}
}
const query = search.toString();
return query ? `?${query}` : "";
}
export function apiPath(path: string, params: ApiQueryParams = {}): string {
const query = apiQuery(params);
if (!query) return path;
return path.includes("?") ? `${path}&${query.slice(1)}` : `${path}${query}`;
}
export async function apiGetList<TItem, K extends string>(
settings: ApiSettings,
path: string,
key: K,
params: ApiQueryParams = {}
): Promise<TItem[]> {
const response = await apiFetch<Record<K, TItem[] | null | undefined>>(settings, apiPath(path, params));
return response[key] ?? [];
}
export function apiPost<TResponse>(settings: ApiSettings, path: string, init: Omit<RequestInit, "method"> = {}): Promise<TResponse> {
return apiFetch<TResponse>(settings, path, { ...init, method: "POST" });
}
export function apiPostJson<TResponse, TPayload = unknown>(
settings: ApiSettings,
path: string,
payload: TPayload,
init: Omit<RequestInit, "method" | "body"> = {}
): Promise<TResponse> {
return apiPost<TResponse>(settings, path, { ...init, body: JSON.stringify(payload) });
}
export function loadApiSettings(): ApiSettings {
const storedBaseUrl = loadStoredSetting("baseUrl");
const storedApiKey = sessionStorage.getItem(`${SESSION_STORAGE_KEY}.apiKey`);