export class ApiError extends Error { constructor( message: string, public readonly status?: number, public readonly code?: string, public readonly meta?: Record, ) { super(message); this.name = 'ApiError'; } } export function isApiError(value: unknown): value is ApiError { return value instanceof ApiError; } export function getApiErrorMessage(error: unknown, fallback: string): string { if (isApiError(error)) { if (error.message) { return error.message; } if (error.status && error.status >= 500) { return 'Der Server hat nicht reagiert. Bitte versuche es später erneut.'; } return fallback; } if (error instanceof Error && error.message) { return error.message; } return fallback; } export function getApiValidationMessage(error: unknown, fallback: string): string { if (isApiError(error)) { const errors = normalizeValidationErrors(error.meta); if (errors.length) { return errors.join('\n'); } } return getApiErrorMessage(error, fallback); } export type ApiErrorEventDetail = { message: string; status?: number; code?: string; meta?: Record; }; export const API_ERROR_EVENT = 'admin:api:error'; export function emitApiErrorEvent(detail: ApiErrorEventDetail): void { if (typeof window === 'undefined') { return; } window.dispatchEvent(new CustomEvent(API_ERROR_EVENT, { detail })); } export function registerApiErrorListener(handler: (detail: ApiErrorEventDetail) => void): () => void { if (typeof window === 'undefined') { return () => {}; } const listener = (event: Event) => { const customEvent = event as CustomEvent; handler(customEvent.detail); }; window.addEventListener(API_ERROR_EVENT, listener as EventListener); return () => window.removeEventListener(API_ERROR_EVENT, listener as EventListener); } function normalizeValidationErrors(meta?: Record): string[] { if (!meta || typeof meta !== 'object') { return []; } const errors = meta.errors; if (!errors || typeof errors !== 'object') { return []; } return Object.values(errors as Record) .flatMap((value) => (Array.isArray(value) ? value : [value])) .filter((value): value is string => typeof value === 'string' && value.trim() !== ''); }