352 lines
8.3 KiB
TypeScript
352 lines
8.3 KiB
TypeScript
|
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);
|
||
|
}
|
||
|
}
|