Backend now returns { code: ErrorCode, message: string } for all errors,
making it language-agnostic. Frontend maps codes to localised strings via
Paraglide (en/de/es), so translations live in messages/*.json.
- Add ErrorCode enum and DomainException with static factory methods
- Update GlobalExceptionHandler to return ErrorResponse(code, message)
- Replace ResponseStatusException throughout controllers/services/aspects
- Add frontend errors.ts with parseBackendError() and getErrorMessage()
- getErrorMessage() delegates to Paraglide m.error_*() functions
- Add error_* keys to messages/en.json, de.json, es.json
- Update all page.server.ts files to use the new error utilities
- Fix hardcoded localhost URLs in admin and login pages
- Fix missing baseUrl in deleteTag action
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
55 lines
2.0 KiB
TypeScript
55 lines
2.0 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'
|
|
| 'IMPORT_ALREADY_RUNNING'
|
|
| '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 'IMPORT_ALREADY_RUNNING':return m.error_import_already_running();
|
|
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();
|
|
}
|
|
}
|