UNPKG

shogun-core

Version:

SHOGUN CORE - Core library for Shogun Ecosystem

340 lines (339 loc) 14.3 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; /** * Types of errors that can occur in the application */ export var ErrorType; (function (ErrorType) { ErrorType["AUTHENTICATION"] = "AuthenticationError"; ErrorType["AUTHORIZATION"] = "AuthorizationError"; ErrorType["VALIDATION"] = "ValidationError"; ErrorType["NETWORK"] = "NetworkError"; ErrorType["DATABASE"] = "DatabaseError"; ErrorType["WALLET"] = "WalletError"; ErrorType["STORAGE"] = "StorageError"; ErrorType["ENCRYPTION"] = "EncryptionError"; ErrorType["SIGNATURE"] = "SignatureError"; ErrorType["ENVIRONMENT"] = "EnvironmentError"; ErrorType["SECURITY"] = "SecurityError"; ErrorType["GUN"] = "GunError"; ErrorType["STEALTH"] = "StealthError"; ErrorType["WEBAUTHN"] = "WebAuthnError"; ErrorType["PLUGIN"] = "PluginError"; ErrorType["UNKNOWN"] = "UnknownError"; ErrorType["CONNECTOR"] = "ConnectorError"; ErrorType["GENERAL"] = "GeneralError"; ErrorType["CONTRACT"] = "ContractError"; ErrorType["BIP32"] = "BIP32Error"; ErrorType["ETHEREUM"] = "EthereumError"; ErrorType["BITCOIN"] = "BitcoinError"; })(ErrorType || (ErrorType = {})); /** * Wrapper to standardize errors * @param type - Error type * @param code - Error code * @param message - Error message * @param originalError - Original error * @returns A structured error object */ export function createError(type, code, message, originalError) { return { type: type, code: code, message: message, originalError: originalError, timestamp: Date.now(), }; } /** * Centralized error handler */ var ErrorHandler = /** @class */ (function () { function ErrorHandler() { } /** * Set an external logging service for production error monitoring * @param logger - External logger function to send errors to a monitoring service */ ErrorHandler.setExternalLogger = function (logger) { this.externalLogger = logger; }; /** * Handles an error by logging it and notifying listeners * @param error - The error to handle */ ErrorHandler.handleError = function (error) { // Log essential errors only if (error.type === ErrorType.AUTHENTICATION || error.type === ErrorType.AUTHORIZATION || error.type === ErrorType.SECURITY) { // Ensure console.error is available and safe to use if (typeof console !== 'undefined' && console.error) { console.error("[".concat(error.type, "] ").concat(error.code, ": ").concat(error.message)); } } // Store the error in memory this.errors.push(error); // Keep only the last maxErrors if (this.errors.length > this.maxErrors) { this.errors = this.errors.slice(-this.maxErrors); } // Send to external logger if set (for production monitoring) if (this.externalLogger) { try { this.externalLogger(error); } catch (e) { // Fallback logging for external logger errors console.error('Failed to send error to external logger:', e); } } // Notify all listeners this.listeners.forEach(function (listener) { try { listener(error); } catch (e) { // Silent error to prevent infinite loops } }); }; /** * Handles a raw error by converting it to ShogunError * @param type - Error type * @param code - Error code * @param message - Error message * @param originalError - Original error * @param logLevel - Log level for the error */ ErrorHandler.handle = function (type, code, message, originalError, logLevel) { if (logLevel === void 0) { logLevel = 'error'; } // Create a formatted error message (tests expect the plain message) var finalMessage = message; // Log the error switch (logLevel) { case 'debug': console.log("[".concat(type, "] ").concat(code, ": ").concat(finalMessage)); break; case 'warn': console.log("[".concat(type, "] ").concat(code, ": ").concat(finalMessage)); break; case 'info': console.log("[".concat(type, "] ").concat(code, ": ").concat(finalMessage)); break; case 'error': default: console.log("[".concat(type, "] ").concat(code, ": ").concat(finalMessage)); break; } var error = createError(type, code, finalMessage, originalError); this.handleError(error); return error; }; /** * Handles errors and throws them as standardized ShogunError objects * @param type - Error type * @param code - Error code * @param message - Error message * @param originalError - Original error * @throws ShogunError */ ErrorHandler.handleAndThrow = function (type, code, message, originalError) { var error = this.handle(type, code, message, originalError); throw error; }; /** * Retrieves the last N errors * @param count - Number of errors to retrieve * @returns List of most recent errors */ ErrorHandler.getRecentErrors = function (count) { if (count === void 0) { count = 10; } return this.errors.slice(-Math.min(count, this.errors.length)); }; /** * Adds a listener for errors * @param listener - Function that will be called when an error occurs */ ErrorHandler.addListener = function (listener) { this.listeners.push(listener); }; /** * Removes an error listener * @param listener - Function to remove */ ErrorHandler.removeListener = function (listener) { var index = this.listeners.indexOf(listener); if (index !== -1) { this.listeners.splice(index, 1); } }; /** * Notifies all listeners of an error * @param error - Error to notify */ ErrorHandler.notifyListeners = function (error) { var e_1, _a; try { for (var _b = __values(this.listeners), _c = _b.next(); !_c.done; _c = _b.next()) { var listener = _c.value; try { listener(error); } catch (listenerError) { console.error("Error in error listener: ".concat(listenerError)); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } }; /** * Helper function to format error messages from native errors * @param error - Error to format * @returns Formatted error message */ ErrorHandler.formatError = function (error) { if (!error) { return 'Unknown error'; } if (error instanceof Error) { return "".concat(error.name, ": ").concat(error.message); } if (typeof error === 'string') { return error; } if (typeof error === 'object') { try { return JSON.stringify(error); } catch (e) { return "Object: ".concat(Object.prototype.toString.call(error)); } } return String(error); }; /** * Error handling with retry logic */ ErrorHandler.withRetry = function (fn_1, errorType_1, errorCode_1) { return __awaiter(this, arguments, void 0, function (fn, errorType, errorCode, maxRetries, retryDelay) { var lastError, _loop_1, attempt, state_1; if (maxRetries === void 0) { maxRetries = 3; } if (retryDelay === void 0) { retryDelay = 1000; } return __generator(this, function (_a) { switch (_a.label) { case 0: _loop_1 = function (attempt) { var _b, error_1, delay_1; return __generator(this, function (_c) { switch (_c.label) { case 0: _c.trys.push([0, 2, , 5]); _b = {}; return [4 /*yield*/, fn()]; case 1: return [2 /*return*/, (_b.value = _c.sent(), _b)]; case 2: error_1 = _c.sent(); lastError = error_1; delay_1 = retryDelay * attempt; if (!(attempt < maxRetries)) return [3 /*break*/, 4]; console.log("Retrying operation after ".concat(delay_1, "ms (attempt ").concat(attempt, "/").concat(maxRetries, ")")); return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, delay_1); })]; case 3: _c.sent(); _c.label = 4; case 4: return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }; attempt = 1; _a.label = 1; case 1: if (!(attempt <= maxRetries)) return [3 /*break*/, 4]; return [5 /*yield**/, _loop_1(attempt)]; case 2: state_1 = _a.sent(); if (typeof state_1 === "object") return [2 /*return*/, state_1.value]; _a.label = 3; case 3: attempt++; return [3 /*break*/, 1]; case 4: // If we got here, all retries failed. // Log the failure and rethrow the last error message for test expectations compatibility. this.handle(errorType, errorCode, "Operation failed after ".concat(maxRetries, " attempts"), lastError); // Prefer the original error message if available if (lastError instanceof Error) { throw new Error(lastError.message); } throw new Error(this.formatError(lastError)); } }); }); }; /** * Clear all stored errors */ ErrorHandler.clearErrors = function () { this.errors = []; }; ErrorHandler.errors = []; ErrorHandler.maxErrors = 100; ErrorHandler.listeners = []; ErrorHandler.externalLogger = null; return ErrorHandler; }()); export { ErrorHandler };