@tryloop/oats
Version:
š¾ OATS - OpenAPI TypeScript Sync. The missing link between your OpenAPI specs and TypeScript applications. Automatically watch, generate, and sync TypeScript clients from your API definitions.
306 lines ⢠8.33 kB
JavaScript
/**
* Custom Error Classes for OATS
*
* This module defines a hierarchy of error classes for better error handling
* and user-friendly error messages throughout the application.
*
* @module @oatsjs/errors
*/
/**
* Base error class for all OATS errors
*/
export class OatsError extends Error {
/**
* Error code for programmatic handling
*/
code;
/**
* Additional context about the error
*/
context;
/**
* Whether this error is recoverable
*/
recoverable;
/**
* Timestamp when the error occurred
*/
timestamp;
constructor(message, code, recoverable = false, context) {
super(message);
this.name = this.constructor.name;
this.code = code;
this.recoverable = recoverable;
this.context = context;
this.timestamp = new Date();
// Maintains proper stack trace for where our error was thrown
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
/**
* Returns a user-friendly error message
*/
getUserMessage() {
return this.message;
}
/**
* Returns error details for logging
*/
getDetails() {
return {
name: this.name,
code: this.code,
message: this.message,
recoverable: this.recoverable,
context: this.context,
timestamp: this.timestamp,
stack: this.stack,
};
}
}
/**
* Configuration-related errors
*/
export class ConfigError extends OatsError {
constructor(message, context) {
super(message, 'CONFIG_ERROR', false, context);
}
}
/**
* Configuration validation error
*/
export class ConfigValidationError extends ConfigError {
validationErrors;
constructor(message, validationErrors, context) {
super(message, context);
this.code = 'CONFIG_VALIDATION_ERROR';
this.validationErrors = validationErrors;
}
getUserMessage() {
const errors = this.validationErrors
.map((err) => ` - ${err.path}: ${err.message}`)
.join('\n');
return `${this.message}\n${errors}`;
}
}
/**
* Service-related errors
*/
export class ServiceError extends OatsError {
service;
constructor(message, service, code = 'SERVICE_ERROR', recoverable = true, context) {
super(message, code, recoverable, context);
this.service = service;
}
}
/**
* Service start error
*/
export class ServiceStartError extends ServiceError {
exitCode;
stderr;
constructor(service, message, exitCode, stderr, context) {
super(message, service, 'SERVICE_START_ERROR', true, context);
this.exitCode = exitCode;
this.stderr = stderr;
}
getUserMessage() {
let message = `Failed to start ${this.service}: ${this.message}`;
if (this.stderr) {
message += `\nError output: ${this.stderr}`;
}
return message;
}
}
/**
* File system errors
*/
export class FileSystemError extends OatsError {
path;
operation;
constructor(message, path, operation, recoverable = false, context) {
super(message, 'FILESYSTEM_ERROR', recoverable, context);
this.path = path;
this.operation = operation;
}
getUserMessage() {
return `File system error during ${this.operation} on ${this.path}: ${this.message}`;
}
}
/**
* API specification errors
*/
export class ApiSpecError extends OatsError {
specPath;
constructor(message, specPath, recoverable = true, context) {
super(message, 'API_SPEC_ERROR', recoverable, context);
this.specPath = specPath;
}
}
/**
* Generator errors
*/
export class GeneratorError extends OatsError {
generator;
phase;
constructor(message, generator, phase, recoverable = true, context) {
super(message, 'GENERATOR_ERROR', recoverable, context);
this.generator = generator;
this.phase = phase;
}
getUserMessage() {
return `Generator error during ${this.phase} phase (${this.generator}): ${this.message}`;
}
}
/**
* Network-related errors
*/
export class NetworkError extends OatsError {
url;
statusCode;
constructor(message, url, statusCode, context) {
super(message, 'NETWORK_ERROR', true, context);
this.url = url;
this.statusCode = statusCode;
}
}
/**
* Dependency errors
*/
export class DependencyError extends OatsError {
dependency;
requiredVersion;
installedVersion;
constructor(message, dependency, requiredVersion, installedVersion, context) {
super(message, 'DEPENDENCY_ERROR', false, context);
this.dependency = dependency;
this.requiredVersion = requiredVersion;
this.installedVersion = installedVersion;
}
getUserMessage() {
let message = `Dependency error: ${this.dependency} - ${this.message}`;
if (this.requiredVersion) {
message += `\nRequired: ${this.requiredVersion}`;
}
if (this.installedVersion) {
message += `\nInstalled: ${this.installedVersion}`;
}
return message;
}
}
/**
* Command execution errors
*/
export class CommandError extends OatsError {
command;
exitCode;
stdout;
stderr;
constructor(message, command, exitCode, stdout, stderr, context) {
super(message, 'COMMAND_ERROR', true, context);
this.command = command;
this.exitCode = exitCode;
this.stdout = stdout;
this.stderr = stderr;
}
getUserMessage() {
let message = `Command failed: ${this.command}\n`;
message += `Exit code: ${this.exitCode}\n`;
if (this.stderr) {
message += `Error: ${this.stderr}`;
}
return message;
}
}
/**
* Timeout errors
*/
export class TimeoutError extends OatsError {
operation;
timeoutMs;
constructor(operation, timeoutMs, context) {
super(`Operation '${operation}' timed out after ${timeoutMs}ms`, 'TIMEOUT_ERROR', true, context);
this.operation = operation;
this.timeoutMs = timeoutMs;
}
}
/**
* User cancellation error
*/
export class UserCancelledError extends OatsError {
constructor(operation, context) {
super(`User cancelled: ${operation}`, 'USER_CANCELLED', false, context);
}
}
/**
* Creates an error with a suggestion for fixing it
*/
export class ErrorWithSuggestion extends OatsError {
suggestion;
constructor(message, code, suggestion, recoverable = false, context) {
super(message, code, recoverable, context);
this.suggestion = suggestion;
}
getUserMessage() {
return `${this.message}\n\nš” Suggestion: ${this.suggestion}`;
}
}
/**
* Error handler utility
*/
export class ErrorHandler {
/**
* Handles an error and returns a user-friendly message
*/
static handle(error) {
if (error instanceof OatsError) {
return error.getUserMessage();
}
if (error instanceof Error) {
return `Unexpected error: ${error.message}`;
}
return 'An unknown error occurred';
}
/**
* Logs error details for debugging
*/
static log(error, logger) {
const log = logger || console.error;
if (error instanceof OatsError) {
log(JSON.stringify(error.getDetails(), null, 2));
}
else if (error instanceof Error) {
log(error.stack || error.message);
}
else {
log(String(error));
}
}
/**
* Determines if an error is recoverable
*/
static isRecoverable(error) {
if (error instanceof OatsError) {
return error.recoverable;
}
return false;
}
/**
* Wraps an async function with error handling
*/
static async wrap(fn, context) {
try {
return await fn();
}
catch (error) {
const message = this.handle(error);
console.error(`Error in ${context}: ${message}`);
if (!this.isRecoverable(error)) {
throw error;
}
return undefined;
}
}
}
//# sourceMappingURL=index.js.map