export class AppError extends Error { public statusCode: number; public isOperational: boolean; constructor(message: string, statusCode: number, isOperational = true) { super(message); this.statusCode = statusCode; this.isOperational = isOperational; Object.setPrototypeOf(this, AppError.prototype); Error.captureStackTrace(this, this.constructor); } } export class BadRequestError extends AppError { constructor(message = 'Bad Request') { super(message, 400); } } export class UnauthorizedError extends AppError { constructor(message = 'Unauthorized') { super(message, 401); } } export class ForbiddenError extends AppError { constructor(message = 'Forbidden') { super(message, 403); } } export class NotFoundError extends AppError { constructor(message = 'Not Found') { super(message, 404); } } export class ConflictError extends AppError { constructor(message = 'Conflict') { super(message, 409); } } export class TooManyRequestsError extends AppError { constructor(message = 'Too Many Requests') { super(message, 429); } } export class InternalError extends AppError { constructor(message = 'Internal Server Error') { super(message, 500, false); } } export function validateRequired(fields: Record): void { const missing: string[] = []; for (const [key, value] of Object.entries(fields)) { if (value === undefined || value === null || value === '') { missing.push(key); } } if (missing.length > 0) { throw new BadRequestError(`Missing required fields: ${missing.join(', ')}`); } } export function validateEmail(email: string): boolean { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(email); } export function validatePassword(password: string): boolean { return password.length >= 8; } export function sanitizeString(str: string): string { return str.replace(/[<>\"'&]/g, (char) => { const map: Record = { '<': '<', '>': '>', '"': '"', "'": ''', '&': '&', }; return map[char] || char; }); }