Files
familienarchiv/frontend/src/lib/errors.ts
2026-03-24 11:02:38 +01:00

83 lines
2.3 KiB
TypeScript

import * as m from '$lib/paraglide/messages.js';
/**
* Mirror of the backend ErrorCode enum.
* Keep in sync with backend/src/main/java/org/raddatz/familienarchiv/exception/ErrorCode.java
*/
export type ErrorCode =
| 'DOCUMENT_NOT_FOUND'
| 'DOCUMENT_NO_FILE'
| 'FILE_NOT_FOUND'
| 'FILE_UPLOAD_FAILED'
| 'USER_NOT_FOUND'
| 'EMAIL_ALREADY_IN_USE'
| 'WRONG_CURRENT_PASSWORD'
| 'IMPORT_ALREADY_RUNNING'
| 'INVALID_RESET_TOKEN'
| 'ANNOTATION_NOT_FOUND'
| 'ANNOTATION_OVERLAP'
| 'COMMENT_NOT_FOUND'
| 'UNAUTHORIZED'
| 'FORBIDDEN'
| 'VALIDATION_ERROR'
| 'INTERNAL_ERROR';
export interface BackendError {
code: ErrorCode;
message: string; // English developer message — not shown to users
}
/**
* Attempts to parse a backend ErrorResponse from a failed fetch response.
* Returns null if the body is not valid JSON or does not contain a code field.
*/
export async function parseBackendError(res: Response): Promise<BackendError | null> {
try {
const body = await res.json();
if (body && typeof body.code === 'string') {
return body as BackendError;
}
} catch {
// Body was not JSON
}
return null;
}
/** Returns a localised message for the given error code via Paraglide. Falls back to INTERNAL_ERROR. */
export function getErrorMessage(code: ErrorCode | string | undefined): string {
switch (code) {
case 'DOCUMENT_NOT_FOUND':
return m.error_document_not_found();
case 'DOCUMENT_NO_FILE':
return m.error_document_no_file();
case 'FILE_NOT_FOUND':
return m.error_file_not_found();
case 'FILE_UPLOAD_FAILED':
return m.error_file_upload_failed();
case 'USER_NOT_FOUND':
return m.error_user_not_found();
case 'EMAIL_ALREADY_IN_USE':
return m.error_email_already_in_use();
case 'WRONG_CURRENT_PASSWORD':
return m.error_wrong_current_password();
case 'IMPORT_ALREADY_RUNNING':
return m.error_import_already_running();
case 'INVALID_RESET_TOKEN':
return m.error_invalid_reset_token();
case 'ANNOTATION_NOT_FOUND':
return m.error_annotation_not_found();
case 'ANNOTATION_OVERLAP':
return m.error_annotation_overlap();
case 'COMMENT_NOT_FOUND':
return m.error_comment_not_found();
case 'UNAUTHORIZED':
return m.error_unauthorized();
case 'FORBIDDEN':
return m.error_forbidden();
case 'VALIDATION_ERROR':
return m.error_validation_error();
default:
return m.error_internal_error();
}
}