UNPKG

express-hale

Version:

šŸš€ Interactive Express.js scaffold CLI with comprehensive error handling, TypeScript/JavaScript, database integrations, Git Flow, and development tools

447 lines (384 loc) • 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MiddlewareTemplates = void 0; const base_renderer_1 = require("./base-renderer"); class MiddlewareTemplates extends base_renderer_1.BaseRenderer { renderErrorHandlerMiddleware(language) { if (language === 'typescript') { return `import { Request, Response, NextFunction } from 'express'; // Custom Error Class export class CustomError extends Error { statusCode: number; isOperational: boolean; constructor(message: string, statusCode: number = 500) { super(message); this.statusCode = statusCode; this.isOperational = true; Error.captureStackTrace(this, this.constructor); } } // Async error wrapper export const asyncHandler = ( fn: (req: Request, res: Response, next: NextFunction) => Promise<void> ) => { return (req: Request, res: Response, next: NextFunction) => { Promise.resolve(fn(req, res, next)).catch(next); }; }; // Global error handler export const errorHandler = ( err: Error, req: Request, res: Response, next: NextFunction ): void => { let error = { ...err }; error.message = err.message; // Log error console.error('Error:', err); // Mongoose bad ObjectId if (err.name === 'CastError') { const message = 'Resource not found'; error = new CustomError(message, 404); } // Mongoose duplicate key if ((err as any).code === 11000) { const message = 'Duplicate field value entered'; error = new CustomError(message, 400); } // Mongoose validation error if (err.name === 'ValidationError') { const message = Object.values((err as any).errors).map((val: any) => val.message); error = new CustomError(message.join(', '), 400); } res.status((error as CustomError).statusCode || 500).json({ status: 'error', message: error.message || 'Server Error', ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) }); }; // 404 handler export const notFoundHandler = (req: Request, res: Response, next: NextFunction): void => { const error = new CustomError(\`Not found - \${req.originalUrl}\`, 404); next(error); };`; } else { return `// Custom Error Class class CustomError extends Error { constructor(message, statusCode = 500) { super(message); this.statusCode = statusCode; this.isOperational = true; Error.captureStackTrace(this, this.constructor); } } // Async error wrapper const asyncHandler = (fn) => { return (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; }; // Global error handler const errorHandler = (err, req, res, next) => { let error = { ...err }; error.message = err.message; // Log error console.error('Error:', err); // Mongoose bad ObjectId if (err.name === 'CastError') { const message = 'Resource not found'; error = new CustomError(message, 404); } // Mongoose duplicate key if (err.code === 11000) { const message = 'Duplicate field value entered'; error = new CustomError(message, 400); } // Mongoose validation error if (err.name === 'ValidationError') { const message = Object.values(err.errors).map(val => val.message); error = new CustomError(message.join(', '), 400); } res.status(error.statusCode || 500).json({ status: 'error', message: error.message || 'Server Error', ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) }); }; // 404 handler const notFoundHandler = (req, res, next) => { const error = new CustomError(\`Not found - \${req.originalUrl}\`, 404); next(error); }; module.exports = { CustomError, asyncHandler, errorHandler, notFoundHandler, };`; } } renderGracefulShutdownUtil(language) { if (language === 'typescript') { return `import { Server } from 'http'; export const setupGracefulShutdown = (server: Server): void => { const gracefulShutdown = (signal: string) => { console.log(\`\\nšŸ“” Received \${signal}. Starting graceful shutdown...\`); server.close(() => { console.log('šŸ”Œ HTTP server closed.'); // Close database connections // Add your database cleanup here console.log('āœ… Graceful shutdown completed.'); process.exit(0); }); // Force close server after 30 seconds setTimeout(() => { console.error( 'āŒ Could not close connections in time, forcefully shutting down' ); process.exit(1); }, 30000); }; // Listen for termination signals process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); process.on('SIGINT', () => gracefulShutdown('SIGINT')); // Handle uncaught exceptions process.on('uncaughtException', (error) => { console.error('āŒ Uncaught Exception:', error); gracefulShutdown('uncaughtException'); }); // Handle unhandled promise rejections process.on( 'unhandledRejection', (reason, promise) => { console.error('āŒ Unhandled Rejection at:', promise, 'reason:', reason); gracefulShutdown('unhandledRejection'); } ); };`; } else { return `const setupGracefulShutdown = (server) => { const gracefulShutdown = (signal) => { console.log(\`\\nšŸ“” Received \${signal}. Starting graceful shutdown...\`); server.close(() => { console.log('šŸ”Œ HTTP server closed.'); // Close database connections // Add your database cleanup here console.log('āœ… Graceful shutdown completed.'); process.exit(0); }); // Force close server after 30 seconds setTimeout(() => { console.error( 'āŒ Could not close connections in time, forcefully shutting down' ); process.exit(1); }, 30000); }; // Listen for termination signals process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); process.on('SIGINT', () => gracefulShutdown('SIGINT')); // Handle uncaught exceptions process.on('uncaughtException', (error) => { console.error('āŒ Uncaught Exception:', error); gracefulShutdown('uncaughtException'); }); // Handle unhandled promise rejections process.on( 'unhandledRejection', (reason, promise) => { console.error('āŒ Unhandled Rejection at:', promise, 'reason:', reason); gracefulShutdown('unhandledRejection'); } ); }; module.exports = { setupGracefulShutdown };`; } } renderErrorMonitoringConfig(language) { if (language === 'typescript') { return `export interface ErrorReport { error: Error; context: { timestamp: string; method?: string; url?: string; ip?: string; userAgent?: string; userId?: string; requestId?: string; }; level: 'error' | 'warning' | 'info'; tags?: string[]; } interface RequestLike { method?: string; originalUrl?: string; ip?: string; get?: (header: string) => string | undefined; user?: { id?: string }; id?: string; headers?: { [key: string]: string | string[] | undefined }; } export class ErrorMonitor { private static instance: ErrorMonitor; private isEnabled: boolean; private constructor() { this.isEnabled = process.env.NODE_ENV === 'production'; } static getInstance(): ErrorMonitor { if (!ErrorMonitor.instance) { ErrorMonitor.instance = new ErrorMonitor(); } return ErrorMonitor.instance; } async reportError(report: ErrorReport): Promise<void> { if (!this.isEnabled) { return; } try { // Log to console (in production, this might go to a logging service) console.error('Error Report:', JSON.stringify(report, null, 2)); // TODO: Send to external monitoring service // await this.sendToMonitoringService(report); } catch (monitoringError) { console.error('Failed to report error:', monitoringError); } } // Placeholder for external monitoring service integration private async sendToMonitoringService(): Promise<void> { // Example integrations: // - Sentry: Sentry.captureException(report.error, { extra: report.context }); // - Bugsnag: Bugsnag.notify(report.error, report.context); // - Custom webhook or API endpoint console.log('Sending error report to monitoring service...'); } // Create error report from Express error createErrorReport( error: Error, req?: RequestLike, level: 'error' | 'warning' | 'info' = 'error', tags?: string[] ): ErrorReport { return { error, context: { timestamp: new Date().toISOString(), method: req?.method, url: req?.originalUrl, ip: req?.ip, userAgent: req?.get?.('User-Agent'), userId: req?.user?.id, requestId: req?.id || req?.headers?.['x-request-id'], }, level, tags, }; } } // Global error monitoring setup export const setupErrorMonitoring = (): void => { const monitor = ErrorMonitor.getInstance(); // Monitor uncaught exceptions process.on('uncaughtException', (error: Error) => { const report = monitor.createErrorReport( error, null, 'error', ['uncaught-exception'] ); monitor.reportError(report); }); // Monitor unhandled promise rejections process.on('unhandledRejection', (reason: unknown) => { const error = reason instanceof Error ? reason : new Error(String(reason)); const report = monitor.createErrorReport( error, null, 'error', ['unhandled-rejection'] ); monitor.reportError(report); }); };`; } else { return `class ErrorMonitor { constructor() { if (ErrorMonitor.instance) { return ErrorMonitor.instance; } this.isEnabled = process.env.NODE_ENV === 'production'; ErrorMonitor.instance = this; } static getInstance() { if (!ErrorMonitor.instance) { ErrorMonitor.instance = new ErrorMonitor(); } return ErrorMonitor.instance; } async reportError(report) { if (!this.isEnabled) { return; } try { // Log to console (in production, this might go to a logging service) console.error('Error Report:', JSON.stringify(report, null, 2)); // TODO: Send to external monitoring service // await this.sendToMonitoringService(report); } catch (monitoringError) { console.error('Failed to report error:', monitoringError); } } // Placeholder for external monitoring service integration async sendToMonitoringService() { // Example integrations: // - Sentry: Sentry.captureException(report.error, { extra: report.context }); // - Bugsnag: Bugsnag.notify(report.error, report.context); // - Custom webhook or API endpoint console.log('Sending error report to monitoring service...'); } // Create error report from Express error createErrorReport(error, req = null, level = 'error', tags = []) { return { error, context: { timestamp: new Date().toISOString(), method: req?.method, url: req?.originalUrl, ip: req?.ip, userAgent: req?.get?.('User-Agent'), userId: req?.user?.id, requestId: req?.id || req?.headers?.['x-request-id'] }, level, tags }; } } // Global error monitoring setup const setupErrorMonitoring = () => { const monitor = ErrorMonitor.getInstance(); // Monitor uncaught exceptions process.on('uncaughtException', (error) => { const report = monitor.createErrorReport(error, null, 'error', ['uncaught-exception']); monitor.reportError(report); }); // Monitor unhandled promise rejections process.on('unhandledRejection', (reason) => { const error = reason instanceof Error ? reason : new Error(String(reason)); const report = monitor.createErrorReport(error, null, 'error', ['unhandled-rejection']); monitor.reportError(report); }); }; module.exports = { ErrorMonitor, setupErrorMonitoring, };`; } } } exports.MiddlewareTemplates = MiddlewareTemplates; //# sourceMappingURL=middleware-templates.js.map