@keypo/synapse-storage-sdk
Version:
TypeScript SDK for encrypted file storage on Filecoin via Synapse
239 lines (238 loc) • 8.97 kB
JavaScript
/**
* Error handling system for Synapse Storage SDK
*/
export var ErrorCategory;
(function (ErrorCategory) {
ErrorCategory["CONFIG"] = "CONFIGURATION";
ErrorCategory["NETWORK"] = "NETWORK";
ErrorCategory["FILE"] = "FILE";
ErrorCategory["PERMISSION"] = "PERMISSION";
ErrorCategory["VALIDATION"] = "VALIDATION";
ErrorCategory["ENCRYPTION"] = "ENCRYPTION";
ErrorCategory["CONTRACT"] = "CONTRACT";
ErrorCategory["PAYMENT"] = "PAYMENT";
ErrorCategory["STORAGE"] = "STORAGE";
ErrorCategory["UNKNOWN"] = "UNKNOWN";
})(ErrorCategory || (ErrorCategory = {}));
export var ErrorSeverity;
(function (ErrorSeverity) {
ErrorSeverity["INFO"] = "info";
ErrorSeverity["WARNING"] = "warning";
ErrorSeverity["ERROR"] = "error";
ErrorSeverity["FATAL"] = "fatal";
})(ErrorSeverity || (ErrorSeverity = {}));
/**
* Base error class for SDK errors
*/
export class SDKError extends Error {
category;
severity;
cause;
details;
userMessage;
code;
recoverable;
timestamp;
constructor(message, options = {}) {
super(message);
this.name = 'SDKError';
this.category = options.category || ErrorCategory.UNKNOWN;
this.severity = options.severity || ErrorSeverity.ERROR;
this.cause = options.cause;
this.details = options.details;
this.userMessage = options.userMessage || message;
this.code = options.code;
this.recoverable = options.recoverable ?? false;
this.timestamp = new Date();
// Maintain proper stack trace
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
/**
* Convert error to a plain object for serialization
*/
toJSON() {
return {
name: this.name,
message: this.message,
category: this.category,
severity: this.severity,
userMessage: this.userMessage,
code: this.code,
recoverable: this.recoverable,
timestamp: this.timestamp,
details: this.details,
stack: this.stack
};
}
}
/**
* Error handler utility class
*/
export class ErrorHandler {
/**
* Normalize any error to SDKError
*/
static normalize(error) {
if (error instanceof SDKError) {
return error;
}
if (error instanceof Error) {
const category = ErrorHandler.categorizeError(error);
const severity = ErrorHandler.determineSeverity(error);
return new SDKError(error.message, {
category,
severity,
cause: error,
userMessage: ErrorHandler.createUserMessage(error, category),
recoverable: ErrorHandler.isRecoverable(error, category)
});
}
// Handle non-Error objects
return new SDKError('An unknown error occurred', {
category: ErrorCategory.UNKNOWN,
severity: ErrorSeverity.ERROR,
cause: error,
userMessage: 'An unexpected error occurred. Please try again.',
recoverable: false
});
}
static categorizeError(error) {
const message = error.message.toLowerCase();
if (message.includes('environment') || message.includes('config')) {
return ErrorCategory.CONFIG;
}
if (message.includes('network') || message.includes('timeout') || message.includes('connection')) {
return ErrorCategory.NETWORK;
}
if (message.includes('file') || message.includes('enoent') || message.includes('directory')) {
return ErrorCategory.FILE;
}
if (message.includes('permission') || message.includes('access') || message.includes('denied')) {
return ErrorCategory.PERMISSION;
}
if (message.includes('encrypt') || message.includes('decrypt') || message.includes('lit protocol')) {
return ErrorCategory.ENCRYPTION;
}
if (message.includes('contract') || message.includes('revert') || message.includes('useroperation')) {
return ErrorCategory.CONTRACT;
}
if (message.includes('balance') || message.includes('insufficient') || message.includes('usdfc')) {
return ErrorCategory.PAYMENT;
}
if (message.includes('storage') || message.includes('synapse') || message.includes('filecoin')) {
return ErrorCategory.STORAGE;
}
return ErrorCategory.UNKNOWN;
}
static determineSeverity(error) {
const message = error.message.toLowerCase();
if (message.includes('warning') || message.includes('deprecated')) {
return ErrorSeverity.WARNING;
}
if (message.includes('fatal') || message.includes('critical')) {
return ErrorSeverity.FATAL;
}
return ErrorSeverity.ERROR;
}
static createUserMessage(error, category) {
const baseMessages = {
[ErrorCategory.CONFIG]: 'Configuration error. Please check your SDK configuration.',
[ErrorCategory.NETWORK]: 'Network connection issue. Please check your internet connection.',
[ErrorCategory.FILE]: 'File operation failed. Please check the file path and permissions.',
[ErrorCategory.PERMISSION]: 'Permission denied. You may not have access to this resource.',
[ErrorCategory.VALIDATION]: 'Validation failed. Please check your input.',
[ErrorCategory.ENCRYPTION]: 'Encryption/decryption operation failed.',
[ErrorCategory.CONTRACT]: 'Smart contract operation failed.',
[ErrorCategory.PAYMENT]: 'Payment or balance issue.',
[ErrorCategory.STORAGE]: 'Storage operation failed.',
[ErrorCategory.UNKNOWN]: 'An unexpected error occurred.'
};
// Add specific guidance for common errors
const message = error.message.toLowerCase();
if (message.includes('insufficient usdfc')) {
return 'Insufficient USDFC balance. Please deposit funds.';
}
if (message.includes('private_key')) {
return 'Private key not configured.';
}
if (message.includes('not found') && category === ErrorCategory.FILE) {
return 'File not found. Please check that the file exists and the path is correct.';
}
if (message.includes('useroperation reverted')) {
return 'Smart contract transaction failed. This may be due to network congestion or insufficient gas.';
}
if (message.includes('failed to verify signature')) {
return 'Signature verification failed. Please ensure you are using the correct wallet.';
}
return baseMessages[category];
}
static isRecoverable(error, category) {
// Network errors are often recoverable with retry
if (category === ErrorCategory.NETWORK) {
return true;
}
// Some contract errors can be recovered with retry
if (category === ErrorCategory.CONTRACT) {
const message = error.message.toLowerCase();
return message.includes('congestion') || message.includes('timeout');
}
// Configuration and validation errors are not recoverable
if (category === ErrorCategory.CONFIG || category === ErrorCategory.VALIDATION) {
return false;
}
return false;
}
}
// Convenience functions for creating specific error types
export const createConfigError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.CONFIG,
severity: ErrorSeverity.FATAL
});
};
export const createNetworkError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.NETWORK,
recoverable: true
});
};
export const createFileError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.FILE
});
};
export const createPaymentError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.PAYMENT
});
};
export const createEncryptionError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.ENCRYPTION
});
};
export const createContractError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.CONTRACT
});
};
export const createStorageError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.STORAGE
});
};
export const createValidationError = (message, options) => {
return new SDKError(message, {
...options,
category: ErrorCategory.VALIDATION
});
};