thrilled-be-core
Version:
Core Express backend package with middleware, logging, security, and base application setup
224 lines (223 loc) • 7.86 kB
JavaScript
"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;