UNPKG

thrilled-be-core

Version:

Core Express backend package with middleware, logging, security, and base application setup

224 lines (223 loc) 7.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseApp = void 0; const tslib_1 = require("tslib"); require("reflect-metadata"); const express_1 = tslib_1.__importDefault(require("express")); const helmet_1 = tslib_1.__importDefault(require("helmet")); const compression_1 = tslib_1.__importDefault(require("compression")); const cors_1 = tslib_1.__importDefault(require("cors")); const express_rate_limit_1 = tslib_1.__importDefault(require("express-rate-limit")); const hpp_1 = tslib_1.__importDefault(require("hpp")); const morgan_1 = tslib_1.__importDefault(require("morgan")); const cookie_parser_1 = tslib_1.__importDefault(require("cookie-parser")); const Logger_js_1 = require("./logging/Logger.js"); const PluginManager_js_1 = require("./plugins/PluginManager.js"); const ValidationPlugin_js_1 = require("./plugins/ValidationPlugin.js"); const HealthCheck_js_1 = require("./utils/HealthCheck.js"); const GracefulShutdown_js_1 = require("./utils/GracefulShutdown.js"); class BaseApp { config; app; pluginManager; healthCheckManager; gracefulShutdown; logger; constructor(config) { this.config = config; this.app = (0, express_1.default)(); this.logger = Logger_js_1.Logger.create(config.logging || {}); this.pluginManager = new PluginManager_js_1.PluginManager(this.logger); this.healthCheckManager = new HealthCheck_js_1.HealthCheckManager(config.health, this.logger); this.gracefulShutdown = new GracefulShutdown_js_1.GracefulShutdown(config.gracefulShutdown, this.logger); this.initializeCore(); this.setupDefaultPlugins(); this.setupHealthChecks(); } /** * Add a plugin to the application */ use(plugin, config, enabled = true) { this.pluginManager.register(plugin, config, enabled); return this; } /** * Get the Express application instance */ getApp() { return this.app; } /** * Get the plugin manager instance */ getPluginManager() { return this.pluginManager; } /** * Get the logger instance */ getLogger() { return this.logger; } /** * Enable a plugin by name */ enablePlugin(name) { return this.pluginManager.enable(name); } /** * Disable a plugin by name */ disablePlugin(name) { return this.pluginManager.disable(name); } /** * Get list of all registered plugins */ listPlugins() { return this.pluginManager.list(); } /** * Setup default plugins that should be included by default */ setupDefaultPlugins() { // Add validation plugin by default if not explicitly disabled const validationConfig = this.config.validation || {}; const isValidationEnabled = validationConfig.enabled !== false; // Default to true if (isValidationEnabled) { const validationPlugin = new ValidationPlugin_js_1.CoreValidationPlugin(this.logger, validationConfig); this.use(validationPlugin, validationConfig); this.logger.info('Validation plugin automatically registered', { context: 'BaseApp' }); } else { this.logger.info('Validation plugin disabled via configuration', { context: 'BaseApp' }); } } /** * Get the validation plugin instance if it exists */ getValidationPlugin() { const plugin = this.pluginManager.get('validation'); return plugin; } /** * Start the application server */ async start() { try { await this.initializePlugins(); await this.listen(); } catch (error) { this.logger.error(error, { context: 'BaseApp.start' }); process.exit(1); } } /** * Initialize core middleware that should always be present */ initializeCore() { // Trust proxy configuration (must be set before other middleware) if (this.config.trustProxy !== undefined) { this.app.set('trust proxy', this.config.trustProxy); } // Security middleware this.app.use((0, helmet_1.default)()); this.app.use((0, hpp_1.default)()); // Performance middleware this.app.use((0, compression_1.default)()); // CORS configuration if (this.config.cors) { this.app.use((0, cors_1.default)(this.config.cors)); } // Rate limiting if (this.config.rateLimit) { this.app.use(this.createRateLimit(this.config.rateLimit)); } // Logging if (this.config.logging?.httpLogging !== false) { // Custom format: shows response time in milliseconds instead of response size const customFormat = ':method :url HTTP/:http-version" :status ==> :response-time ms'; this.app.use((0, morgan_1.default)(customFormat, { stream: { write: (message) => this.logger.info(message.trim()) }, })); } // Body parsing this.app.use(express_1.default.json({ limit: '10mb' })); this.app.use(express_1.default.urlencoded({ extended: true, limit: '10mb' })); // Cookie parsing this.app.use((0, cookie_parser_1.default)()); } /** * Initialize all registered plugins */ async initializePlugins() { await this.pluginManager.initializeAll(this.app); } /** * Create rate limiting middleware */ createRateLimit(config) { return (0, express_rate_limit_1.default)({ windowMs: config.windowMs || 15 * 60 * 1000, // 15 minutes max: config.max || 100, // limit each IP to 100 requests per windowMs message: config.message || 'Too many requests from this IP', standardHeaders: true, legacyHeaders: false, ...config, }); } /** * Start listening on the configured port */ async listen() { return new Promise((resolve) => { const environment = this.config.environment || this.config.env || 'development'; const appName = this.config.name || 'Application'; const appPort = this.config.port || 3000; this.app.listen(this.config.port || 3000, () => { // Log application startup information this.logger.info(`==================================================`); this.logger.info(`================ ENV: ${environment} =================`); this.logger.info(`🚀 ${appName || 'Base App'} is on port: ${appPort}`); this.logger.info(`==================================================`); this.logger.info(`Listening for incoming requests...`); resolve(); }); }); } /** * Setup default health checks */ setupHealthChecks() { // Add basic application health check this.healthCheckManager.register({ name: 'application', check: async () => ({ status: 'healthy', details: { uptime: process.uptime(), memory: process.memoryUsage(), pid: process.pid, }, }), }); // Setup health check endpoint this.healthCheckManager.setupEndpoint(this.app); } /** * Add a health check */ addHealthCheck(check) { this.healthCheckManager.register(check); return this; } /** * Add a shutdown handler */ addShutdownHandler(handler) { this.gracefulShutdown.addHandler(handler); return this; } } exports.BaseApp = BaseApp;