UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

404 lines (403 loc) 14 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ErrorContextManager = exports.BreadcrumbLevel = exports.ErrorLevel = void 0; exports.createErrorContextManager = createErrorContextManager; exports.getGlobalErrorContext = getGlobalErrorContext; exports.setGlobalErrorContext = setGlobalErrorContext; const events_1 = require("events"); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const os = __importStar(require("os")); var ErrorLevel; (function (ErrorLevel) { ErrorLevel[ErrorLevel["DEBUG"] = 0] = "DEBUG"; ErrorLevel[ErrorLevel["INFO"] = 1] = "INFO"; ErrorLevel[ErrorLevel["WARNING"] = 2] = "WARNING"; ErrorLevel[ErrorLevel["ERROR"] = 3] = "ERROR"; ErrorLevel[ErrorLevel["FATAL"] = 4] = "FATAL"; })(ErrorLevel || (exports.ErrorLevel = ErrorLevel = {})); var BreadcrumbLevel; (function (BreadcrumbLevel) { BreadcrumbLevel[BreadcrumbLevel["DEBUG"] = 0] = "DEBUG"; BreadcrumbLevel[BreadcrumbLevel["INFO"] = 1] = "INFO"; BreadcrumbLevel[BreadcrumbLevel["WARNING"] = 2] = "WARNING"; BreadcrumbLevel[BreadcrumbLevel["ERROR"] = 3] = "ERROR"; })(BreadcrumbLevel || (exports.BreadcrumbLevel = BreadcrumbLevel = {})); class ErrorContextManager extends events_1.EventEmitter { constructor(options = {}) { super(); this.breadcrumbs = []; this.context = {}; this.tags = {}; this.maxBreadcrumbs = options.maxBreadcrumbs ?? 100; this.maxContextSize = options.maxContextSize ?? 10000; this.enableStackTrace = options.enableStackTrace ?? true; this.enableEnvironment = options.enableEnvironment ?? true; this.enableMemoryInfo = options.enableMemoryInfo ?? true; this.enableFileContext = options.enableFileContext ?? false; this.storageDir = options.storageDir ?? path.join(process.cwd(), '.re-shell', 'errors'); this.autoCapture = options.autoCapture ?? true; if (this.autoCapture) { this.setupAutoCapture(); } } setupAutoCapture() { // Capture unhandled exceptions process.on('uncaughtException', (error) => { this.captureException(error, { level: ErrorLevel.FATAL, command: 'unknown', args: {}, options: {} }); }); // Capture unhandled promise rejections process.on('unhandledRejection', (reason, promise) => { const error = reason instanceof Error ? reason : new Error(String(reason)); this.captureException(error, { level: ErrorLevel.ERROR, command: 'unknown', args: {}, options: {}, context: { promise: promise.toString() } }); }); } captureException(error, context) { const errorId = this.generateErrorId(); const errorContext = { id: errorId, timestamp: new Date(), command: context.command, args: context.args, options: context.options, error, stack: this.enableStackTrace ? this.captureStackTrace(error) : '', environment: this.enableEnvironment ? this.captureEnvironment() : {}, context: { ...this.context, ...context.context }, breadcrumbs: [...this.breadcrumbs], tags: { ...this.tags, ...context.tags }, level: context.level ?? ErrorLevel.ERROR }; // Store error context this.storeErrorContext(errorContext); // Emit event this.emit('error:captured', errorContext); return errorId; } generateErrorId() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 8); return `${timestamp}-${random}`; } captureStackTrace(error) { if (error.stack) { return error.stack; } // Capture current stack if error doesn't have one const stackTrace = new Error().stack; return stackTrace?.split('\n').slice(2).join('\n') || ''; } captureEnvironment() { const memUsage = process.memoryUsage(); return { platform: os.platform(), arch: os.arch(), nodeVersion: process.version, cliVersion: this.getCliVersion(), cwd: process.cwd(), memory: { rss: memUsage.rss, heapTotal: memUsage.heapTotal, heapUsed: memUsage.heapUsed, external: memUsage.external }, timing: { uptime: os.uptime(), processUptime: process.uptime() } }; } getCliVersion() { try { const packagePath = path.join(__dirname, '..', '..', 'package.json'); const pkg = fs.readJsonSync(packagePath); return pkg.version; } catch { return 'unknown'; } } storeErrorContext(errorContext) { try { // Ensure directory exists fs.ensureDirSync(this.storageDir); // Write error context to file const filename = `error-${errorContext.id}.json`; const filepath = path.join(this.storageDir, filename); const data = { ...errorContext, error: { name: errorContext.error.name, message: errorContext.error.message, stack: errorContext.error.stack } }; fs.writeJsonSync(filepath, data, { spaces: 2 }); // Clean up old error files (keep last 50) this.cleanupOldErrors(); } catch (storeError) { // Don't throw errors from error storage console.error('Failed to store error context:', storeError); } } cleanupOldErrors() { try { const files = fs.readdirSync(this.storageDir) .filter(f => f.startsWith('error-') && f.endsWith('.json')) .sort(); if (files.length > 50) { const toDelete = files.slice(0, files.length - 50); for (const file of toDelete) { fs.unlinkSync(path.join(this.storageDir, file)); } } } catch { // Ignore cleanup errors } } addBreadcrumb(breadcrumb) { const fullBreadcrumb = { ...breadcrumb, timestamp: new Date() }; this.breadcrumbs.push(fullBreadcrumb); // Trim breadcrumbs if needed if (this.breadcrumbs.length > this.maxBreadcrumbs) { this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs); } this.emit('breadcrumb:added', fullBreadcrumb); } setContext(key, value) { this.context[key] = value; // Check context size const contextSize = JSON.stringify(this.context).length; if (contextSize > this.maxContextSize) { // Remove oldest entries const keys = Object.keys(this.context); const toRemove = Math.ceil(keys.length * 0.1); // Remove 10% for (let i = 0; i < toRemove; i++) { delete this.context[keys[i]]; } } this.emit('context:set', { key, value }); } removeContext(key) { delete this.context[key]; this.emit('context:removed', { key }); } getContext() { return { ...this.context }; } setTag(key, value) { this.tags[key] = value; this.emit('tag:set', { key, value }); } removeTag(key) { delete this.tags[key]; this.emit('tag:removed', { key }); } getTags() { return { ...this.tags }; } getBreadcrumbs() { return [...this.breadcrumbs]; } clearBreadcrumbs() { this.breadcrumbs = []; this.emit('breadcrumbs:cleared'); } clearContext() { this.context = {}; this.emit('context:cleared'); } clearTags() { this.tags = {}; this.emit('tags:cleared'); } clear() { this.clearBreadcrumbs(); this.clearContext(); this.clearTags(); this.emit('cleared'); } getErrorContext(errorId) { try { const filepath = path.join(this.storageDir, `error-${errorId}.json`); if (fs.existsSync(filepath)) { const data = fs.readJsonSync(filepath); return data; } } catch { // Ignore read errors } return null; } getAllErrorContexts() { try { const files = fs.readdirSync(this.storageDir) .filter(f => f.startsWith('error-') && f.endsWith('.json')) .sort() .reverse(); // Most recent first const contexts = []; for (const file of files) { try { const filepath = path.join(this.storageDir, file); const data = fs.readJsonSync(filepath); contexts.push(data); } catch { // Skip corrupted files } } return contexts; } catch { return []; } } deleteErrorContext(errorId) { try { const filepath = path.join(this.storageDir, `error-${errorId}.json`); if (fs.existsSync(filepath)) { fs.unlinkSync(filepath); this.emit('error:deleted', { errorId }); return true; } } catch { // Ignore delete errors } return false; } getRecentErrors(count = 10) { return this.getAllErrorContexts().slice(0, count); } searchErrors(query) { const allErrors = this.getAllErrorContexts(); return allErrors.filter(error => { if (query.command && !error.command.includes(query.command)) { return false; } if (query.level !== undefined && error.level !== query.level) { return false; } if (query.tag && !Object.keys(error.tags).includes(query.tag)) { return false; } if (query.dateFrom && error.timestamp < query.dateFrom) { return false; } if (query.dateTo && error.timestamp > query.dateTo) { return false; } return true; }); } generateReport() { const allErrors = this.getAllErrorContexts(); const now = new Date(); const day = 24 * 60 * 60 * 1000; const errorsByLevel = {}; const errorsByCommand = {}; let last24Hours = 0; let last7Days = 0; let last30Days = 0; for (const error of allErrors) { // Count by level const level = ErrorLevel[error.level]; errorsByLevel[level] = (errorsByLevel[level] || 0) + 1; // Count by command errorsByCommand[error.command] = (errorsByCommand[error.command] || 0) + 1; // Count by time periods const errorTime = new Date(error.timestamp).getTime(); const timeDiff = now.getTime() - errorTime; if (timeDiff <= day) last24Hours++; if (timeDiff <= 7 * day) last7Days++; if (timeDiff <= 30 * day) last30Days++; } return { summary: { totalErrors: allErrors.length, errorsByLevel, errorsByCommand, recentErrors: last24Hours }, trends: { last24Hours, last7Days, last30Days } }; } } exports.ErrorContextManager = ErrorContextManager; // Global error context manager let globalErrorContext = null; function createErrorContextManager(options) { return new ErrorContextManager(options); } function getGlobalErrorContext() { if (!globalErrorContext) { globalErrorContext = new ErrorContextManager(); } return globalErrorContext; } function setGlobalErrorContext(manager) { globalErrorContext = manager; }