93 lines
2.7 KiB
TypeScript
93 lines
2.7 KiB
TypeScript
// Duenne fetch-Wrapper gegen die IAM-08-Backend-Endpunkte. Kein Framework,
|
|
// keine Abstraktionsschicht ueber das Notwendige hinaus (Produkt-DNA:
|
|
// schlanker Go-Dienst + schmales Frontend statt schwergewichtiger Plattform).
|
|
|
|
const API_BASE = process.env.NEXT_PUBLIC_CORE_API_BASE ?? "";
|
|
|
|
export class ApiError extends Error {
|
|
code?: string;
|
|
constructor(message: string, code?: string) {
|
|
super(message);
|
|
this.code = code;
|
|
}
|
|
}
|
|
|
|
async function postJSON<T>(path: string, body: unknown): Promise<T> {
|
|
const res = await fetch(`${API_BASE}${path}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "include",
|
|
body: JSON.stringify(body),
|
|
});
|
|
const data = await res.json().catch(() => ({}));
|
|
if (!res.ok) {
|
|
throw new ApiError(data.error ?? data.message ?? "Unbekannter Fehler", data.code);
|
|
}
|
|
return data as T;
|
|
}
|
|
|
|
async function getJSON<T>(path: string): Promise<T> {
|
|
const res = await fetch(`${API_BASE}${path}`, { credentials: "include" });
|
|
const data = await res.json().catch(() => ({}));
|
|
if (!res.ok) {
|
|
throw new ApiError(data.error ?? data.message ?? "Unbekannter Fehler", data.code);
|
|
}
|
|
return data as T;
|
|
}
|
|
|
|
export interface LoginResult {
|
|
ok: true;
|
|
}
|
|
|
|
export async function login(email: string, password: string, totpCode?: string): Promise<LoginResult> {
|
|
await postJSON("/auth/login", { email, password, totp_code: totpCode ?? "" });
|
|
return { ok: true };
|
|
}
|
|
|
|
export async function requestPasswordReset(email: string): Promise<{ message: string }> {
|
|
return postJSON("/auth/password-reset/request", { email });
|
|
}
|
|
|
|
export async function completePasswordReset(token: string, newPassword: string): Promise<void> {
|
|
await postJSON("/auth/password-reset/complete", { token, new_password: newPassword });
|
|
}
|
|
|
|
export async function changePassword(currentPassword: string, newPassword: string): Promise<void> {
|
|
await postJSON("/account/change-password", { current_password: currentPassword, new_password: newPassword });
|
|
}
|
|
|
|
export interface Me {
|
|
id: string;
|
|
email: string;
|
|
name: string;
|
|
}
|
|
|
|
export async function fetchMe(): Promise<Me> {
|
|
return getJSON("/account/me");
|
|
}
|
|
|
|
export interface TotpStatus {
|
|
enabled: boolean;
|
|
}
|
|
|
|
export async function fetchTotpStatus(): Promise<TotpStatus> {
|
|
return getJSON("/auth/totp/status");
|
|
}
|
|
|
|
export interface TotpSetupBegin {
|
|
secret: string;
|
|
provisioning_uri: string;
|
|
}
|
|
|
|
export async function beginTotpSetup(): Promise<TotpSetupBegin> {
|
|
return postJSON("/auth/totp/setup/begin", {});
|
|
}
|
|
|
|
export interface TotpSetupConfirm {
|
|
recovery_codes: string[];
|
|
}
|
|
|
|
export async function confirmTotpSetup(code: string): Promise<TotpSetupConfirm> {
|
|
return postJSON("/auth/totp/setup/confirm", { code });
|
|
}
|