import { PlatformError, OperationError, ResourceError } from './base.errors.js'; import type { IErrorContext } from './base.errors.js'; import { REPUTATION_CHECK_ERROR, REPUTATION_DATA_ERROR, REPUTATION_BLOCKLIST_ERROR, REPUTATION_UPDATE_ERROR, WARMUP_ALLOCATION_ERROR, WARMUP_LIMIT_EXCEEDED, WARMUP_SCHEDULE_ERROR } from './error.codes.js'; /** * Base class for reputation-related errors */ export class ReputationError extends OperationError { /** * Creates a new reputation error * * @param message Error message * @param code Error code * @param context Additional context */ constructor( message: string, code: string, context: IErrorContext = {} ) { super(message, code, context); } } /** * Error class for reputation check errors */ export class ReputationCheckError extends ReputationError { /** * Creates a new reputation check error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, REPUTATION_CHECK_ERROR, context); } /** * Creates an instance for an IP reputation check error * * @param ip IP address * @param provider Reputation provider * @param originalError Original error * @param context Additional context */ public static ipCheckFailed( ip: string, provider: string, originalError?: Error, context: IErrorContext = {} ): ReputationCheckError { const errorMsg = originalError ? `: ${originalError.message}` : ''; return new ReputationCheckError( `Failed to check reputation for IP ${ip} with provider ${provider}${errorMsg}`, { ...context, data: { ...context.data, ip, provider, originalError: originalError ? { message: originalError.message, stack: originalError.stack } : undefined } } ); } /** * Creates an instance for a domain reputation check error * * @param domain Domain * @param provider Reputation provider * @param originalError Original error * @param context Additional context */ public static domainCheckFailed( domain: string, provider: string, originalError?: Error, context: IErrorContext = {} ): ReputationCheckError { const errorMsg = originalError ? `: ${originalError.message}` : ''; return new ReputationCheckError( `Failed to check reputation for domain ${domain} with provider ${provider}${errorMsg}`, { ...context, data: { ...context.data, domain, provider, originalError: originalError ? { message: originalError.message, stack: originalError.stack } : undefined } } ); } } /** * Error class for reputation data errors */ export class ReputationDataError extends ReputationError { /** * Creates a new reputation data error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, REPUTATION_DATA_ERROR, context); } /** * Creates an instance for a data access error * * @param entity Entity type (domain, ip) * @param entityId Entity identifier * @param operation Operation that failed (read, write, update) * @param originalError Original error * @param context Additional context */ public static dataAccessFailed( entity: string, entityId: string, operation: string, originalError?: Error, context: IErrorContext = {} ): ReputationDataError { const errorMsg = originalError ? `: ${originalError.message}` : ''; return new ReputationDataError( `Failed to ${operation} reputation data for ${entity} ${entityId}${errorMsg}`, { ...context, data: { ...context.data, entity, entityId, operation, originalError: originalError ? { message: originalError.message, stack: originalError.stack } : undefined } } ); } } /** * Error class for blocklist-related errors */ export class BlocklistError extends ReputationError { /** * Creates a new blocklist error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, REPUTATION_BLOCKLIST_ERROR, context); } /** * Creates an instance for an entity found on a blocklist * * @param entity Entity type (domain, ip) * @param entityId Entity identifier * @param blocklist Blocklist name * @param reason Reason for listing (if available) * @param context Additional context */ public static entityBlocked( entity: string, entityId: string, blocklist: string, reason?: string, context: IErrorContext = {} ): BlocklistError { const reasonText = reason ? ` (${reason})` : ''; return new BlocklistError( `${entity.charAt(0).toUpperCase() + entity.slice(1)} ${entityId} is listed on blocklist ${blocklist}${reasonText}`, { ...context, data: { ...context.data, entity, entityId, blocklist, reason }, userMessage: `The ${entity} ${entityId} is on a blocklist. This may affect email deliverability.` } ); } } /** * Error class for reputation update errors */ export class ReputationUpdateError extends ReputationError { /** * Creates a new reputation update error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, REPUTATION_UPDATE_ERROR, context); } } /** * Error class for IP warmup allocation errors */ export class WarmupAllocationError extends ReputationError { /** * Creates a new warmup allocation error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, WARMUP_ALLOCATION_ERROR, context); } /** * Creates an instance for no available IPs * * @param domain Domain requesting an IP * @param policy Allocation policy that was used * @param context Additional context */ public static noAvailableIps( domain: string, policy: string, context: IErrorContext = {} ): WarmupAllocationError { return new WarmupAllocationError( `No available IPs for domain ${domain} using ${policy} allocation policy`, { ...context, data: { ...context.data, domain, policy }, userMessage: `No available sending IPs for ${domain}.` } ); } } /** * Error class for IP warmup limit exceeded errors */ export class WarmupLimitError extends ResourceError { /** * Creates a new warmup limit error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, WARMUP_LIMIT_EXCEEDED, context); } /** * Creates an instance for daily sending limit exceeded * * @param ip IP address * @param domain Domain * @param limit Daily limit * @param sent Number of emails sent * @param context Additional context */ public static dailyLimitExceeded( ip: string, domain: string, limit: number, sent: number, context: IErrorContext = {} ): WarmupLimitError { return new WarmupLimitError( `Daily sending limit exceeded for IP ${ip} and domain ${domain}: ${sent}/${limit}`, { ...context, data: { ...context.data, ip, domain, limit, sent }, userMessage: `Daily sending limit reached for ${domain}.` } ); } } /** * Error class for IP warmup schedule errors */ export class WarmupScheduleError extends ReputationError { /** * Creates a new warmup schedule error * * @param message Error message * @param context Additional context */ constructor( message: string, context: IErrorContext = {} ) { super(message, WARMUP_SCHEDULE_ERROR, context); } }