/** * Hiérarchie d'erreurs de l'application. * * Toutes dérivent de `AppError`, qui porte un `statusCode` HTTP. Le gestionnaire * d'erreurs Fastify (`src/error-handler.ts`) s'appuie dessus pour formater la réponse. * Les messages ne doivent jamais contenir de donnée sensible (jeton, chemin absolu...). */ export abstract class AppError extends Error { public readonly statusCode: number; protected constructor(message: string, statusCode: number, options?: { cause?: unknown }) { super(message, options); this.name = this.constructor.name; this.statusCode = statusCode; } } /** Configuration invalide au démarrage (fichier JSON absent, illisible ou incohérent). */ export class ConfigError extends AppError { public constructor(message: string, options?: { cause?: unknown }) { super(message, 500, options); } } /** Découverte OIDC impossible au démarrage (issuer injoignable ou réponse invalide). */ export class OidcDiscoveryError extends AppError { public constructor(message: string, options?: { cause?: unknown }) { super(message, 500, options); } } /** Jeton d'accès absent, mal formé, expiré ou invalide. */ export class UnauthorizedError extends AppError { public constructor(message = "Jeton d'accès absent ou invalide") { super(message, 401); } } /** Requête mal formée (fichier manquant, type non autorisé...). */ export class ValidationError extends AppError { public constructor(message: string) { super(message, 400); } } /** Fichier au-dessus de la taille maximale autorisée. */ export class PayloadTooLargeError extends AppError { public constructor(message = 'Le fichier dépasse la taille maximale autorisée') { super(message, 413); } } /** Session d'upload introuvable ou expirée. */ export class UploadSessionNotFoundError extends AppError { public constructor(message = "Session d'upload inconnue ou expirée") { super(message, 404); } } /** Trop de sessions d'upload simultanées. */ export class TooManyUploadsError extends AppError { public constructor(message = "Trop d'uploads en cours, réessayez plus tard") { super(message, 429); } } /** Le client a interrompu la requête (annulation, pause, coupure réseau) avant la fin du corps. */ export class ClientAbortedError extends AppError { public constructor(message = 'Requête interrompue par le client') { super(message, 400); } } /** Plus d'espace disque disponible sur la cible de dépôt. */ export class InsufficientStorageError extends AppError { public constructor(message = 'Espace de stockage insuffisant sur le serveur') { super(message, 507); } }