update
This commit is contained in:
437
ts/errors/base.errors.ts
Normal file
437
ts/errors/base.errors.ts
Normal file
@ -0,0 +1,437 @@
|
||||
import { ErrorSeverity, ErrorCategory, ErrorRecoverability } from './error.codes.js';
|
||||
import { logger } from '../logger.js';
|
||||
|
||||
// Import TLogLevel from plugins
|
||||
import type { TLogLevel } from '../plugins.js';
|
||||
|
||||
/**
|
||||
* Context information added to structured errors
|
||||
*/
|
||||
export interface IErrorContext {
|
||||
/** Component or service where the error occurred */
|
||||
component?: string;
|
||||
|
||||
/** Operation that was being performed */
|
||||
operation?: string;
|
||||
|
||||
/** Unique request ID if available */
|
||||
requestId?: string;
|
||||
|
||||
/** Error occurred at timestamp */
|
||||
timestamp?: number;
|
||||
|
||||
/** User-visible message (safe to display to end-users) */
|
||||
userMessage?: string;
|
||||
|
||||
/** Additional structured data for debugging */
|
||||
data?: Record<string, any>;
|
||||
|
||||
/** Related entity IDs if applicable */
|
||||
entity?: {
|
||||
type: string;
|
||||
id: string | number;
|
||||
};
|
||||
|
||||
/** Stack trace (if enabled in configuration) */
|
||||
stack?: string;
|
||||
|
||||
/** Retry information if applicable */
|
||||
retry?: {
|
||||
/** Maximum number of retries allowed */
|
||||
maxRetries?: number;
|
||||
|
||||
/** Current retry count */
|
||||
currentRetry?: number;
|
||||
|
||||
/** Next retry timestamp */
|
||||
nextRetryAt?: number;
|
||||
|
||||
/** Delay between retries (in ms) */
|
||||
retryDelay?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all errors in the Platform Service
|
||||
* Adds structured error information, logging, and error tracking
|
||||
*/
|
||||
export class PlatformError extends Error {
|
||||
/** Error code identifying the specific error type */
|
||||
public readonly code: string;
|
||||
|
||||
/** Error severity level */
|
||||
public readonly severity: ErrorSeverity;
|
||||
|
||||
/** Error category for grouping related errors */
|
||||
public readonly category: ErrorCategory;
|
||||
|
||||
/** Whether the error can be recovered from automatically */
|
||||
public readonly recoverability: ErrorRecoverability;
|
||||
|
||||
/** Additional context information */
|
||||
public readonly context: IErrorContext;
|
||||
|
||||
/**
|
||||
* Creates a new PlatformError
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code from error.codes.ts
|
||||
* @param severity Error severity level
|
||||
* @param category Error category
|
||||
* @param recoverability Error recoverability indication
|
||||
* @param context Additional context information
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
severity: ErrorSeverity = ErrorSeverity.MEDIUM,
|
||||
category: ErrorCategory = ErrorCategory.OTHER,
|
||||
recoverability: ErrorRecoverability = ErrorRecoverability.NON_RECOVERABLE,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(message);
|
||||
|
||||
// Set error metadata
|
||||
this.name = this.constructor.name;
|
||||
this.code = code;
|
||||
this.severity = severity;
|
||||
this.category = category;
|
||||
this.recoverability = recoverability;
|
||||
|
||||
// Add timestamp if not provided
|
||||
this.context = {
|
||||
...context,
|
||||
timestamp: context.timestamp || Date.now(),
|
||||
};
|
||||
|
||||
// Capture stack trace
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
|
||||
// Log the error automatically unless explicitly disabled
|
||||
if (!context.data?.skipLogging) {
|
||||
this.logError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the error using the platform logger
|
||||
*/
|
||||
private logError(): void {
|
||||
const logLevel = this.getLogLevelFromSeverity() as TLogLevel;
|
||||
|
||||
// Construct structured log entry
|
||||
const logData = {
|
||||
error_code: this.code,
|
||||
error_name: this.name,
|
||||
severity: this.severity,
|
||||
category: this.category,
|
||||
recoverability: this.recoverability,
|
||||
...this.context
|
||||
};
|
||||
|
||||
// Log with appropriate level
|
||||
logger.log(logLevel, this.message, logData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps severity levels to log levels
|
||||
*/
|
||||
private getLogLevelFromSeverity(): string {
|
||||
switch (this.severity) {
|
||||
case ErrorSeverity.CRITICAL:
|
||||
case ErrorSeverity.HIGH:
|
||||
return 'error';
|
||||
case ErrorSeverity.MEDIUM:
|
||||
return 'warn';
|
||||
case ErrorSeverity.LOW:
|
||||
return 'info';
|
||||
case ErrorSeverity.INFO:
|
||||
return 'debug';
|
||||
default:
|
||||
return 'error';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON representation of the error
|
||||
*/
|
||||
public toJSON(): Record<string, any> {
|
||||
return {
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
code: this.code,
|
||||
severity: this.severity,
|
||||
category: this.category,
|
||||
recoverability: this.recoverability,
|
||||
context: this.context,
|
||||
stack: process.env.NODE_ENV !== 'production' ? this.stack : undefined
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance with retry information
|
||||
*
|
||||
* @param maxRetries Maximum number of retries
|
||||
* @param currentRetry Current retry count
|
||||
* @param retryDelay Delay between retries in ms
|
||||
*/
|
||||
public withRetry(
|
||||
maxRetries: number,
|
||||
currentRetry: number = 0,
|
||||
retryDelay: number = 1000
|
||||
): PlatformError {
|
||||
const nextRetryAt = Date.now() + retryDelay;
|
||||
|
||||
// Create a new instance with the same parameters but updated context
|
||||
return new (this.constructor as typeof PlatformError)(
|
||||
this.message,
|
||||
this.code,
|
||||
this.severity,
|
||||
this.category,
|
||||
// If we can retry, the error is at least maybe recoverable
|
||||
currentRetry < maxRetries
|
||||
? ErrorRecoverability.MAYBE_RECOVERABLE
|
||||
: this.recoverability,
|
||||
{
|
||||
...this.context,
|
||||
retry: {
|
||||
maxRetries,
|
||||
currentRetry,
|
||||
nextRetryAt,
|
||||
retryDelay
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the error should be retried based on retry information
|
||||
*/
|
||||
public shouldRetry(): boolean {
|
||||
const { retry } = this.context;
|
||||
if (!retry) return false;
|
||||
|
||||
return retry.currentRetry < retry.maxRetries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a user-friendly message that is safe to display to end users
|
||||
*/
|
||||
public getUserMessage(): string {
|
||||
return this.context.userMessage || 'An unexpected error occurred.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for validation errors
|
||||
*/
|
||||
export class ValidationError extends PlatformError {
|
||||
/**
|
||||
* Creates a new validation error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.LOW,
|
||||
ErrorCategory.VALIDATION,
|
||||
ErrorRecoverability.NON_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for configuration errors
|
||||
*/
|
||||
export class ConfigurationError extends PlatformError {
|
||||
/**
|
||||
* Creates a new configuration error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.MEDIUM,
|
||||
ErrorCategory.CONFIGURATION,
|
||||
ErrorRecoverability.NON_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for network-related errors
|
||||
*/
|
||||
export class NetworkError extends PlatformError {
|
||||
/**
|
||||
* Creates a new network error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.MEDIUM,
|
||||
ErrorCategory.CONNECTIVITY,
|
||||
ErrorRecoverability.MAYBE_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for resource availability errors (rate limits, quotas)
|
||||
*/
|
||||
export class ResourceError extends PlatformError {
|
||||
/**
|
||||
* Creates a new resource error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.MEDIUM,
|
||||
ErrorCategory.RESOURCE,
|
||||
ErrorRecoverability.MAYBE_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for authentication/authorization errors
|
||||
*/
|
||||
export class AuthenticationError extends PlatformError {
|
||||
/**
|
||||
* Creates a new authentication error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.HIGH,
|
||||
ErrorCategory.AUTHENTICATION,
|
||||
ErrorRecoverability.NON_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for operation errors (API calls, processing)
|
||||
*/
|
||||
export class OperationError extends PlatformError {
|
||||
/**
|
||||
* Creates a new operation error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.MEDIUM,
|
||||
ErrorCategory.OPERATION,
|
||||
ErrorRecoverability.MAYBE_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for critical system errors
|
||||
*/
|
||||
export class SystemError extends PlatformError {
|
||||
/**
|
||||
* Creates a new system error
|
||||
*
|
||||
* @param message Error message
|
||||
* @param code Error code
|
||||
* @param context Additional context
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
code: string,
|
||||
context: IErrorContext = {}
|
||||
) {
|
||||
super(
|
||||
message,
|
||||
code,
|
||||
ErrorSeverity.CRITICAL,
|
||||
ErrorCategory.OTHER,
|
||||
ErrorRecoverability.NON_RECOVERABLE,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the appropriate error class based on error category
|
||||
*
|
||||
* @param category Error category
|
||||
* @returns The appropriate error class
|
||||
*/
|
||||
export function getErrorClassForCategory(category: ErrorCategory): any {
|
||||
switch (category) {
|
||||
case ErrorCategory.VALIDATION:
|
||||
return ValidationError;
|
||||
case ErrorCategory.CONFIGURATION:
|
||||
return ConfigurationError;
|
||||
case ErrorCategory.CONNECTIVITY:
|
||||
return NetworkError;
|
||||
case ErrorCategory.RESOURCE:
|
||||
return ResourceError;
|
||||
case ErrorCategory.AUTHENTICATION:
|
||||
return AuthenticationError;
|
||||
case ErrorCategory.OPERATION:
|
||||
return OperationError;
|
||||
default:
|
||||
return PlatformError;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user