UNPKG

thrilled-be-core

Version:

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

271 lines (270 loc) 9.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MetricsPlugin = exports.AuthenticationPlugin = void 0; exports.createExampleApplication = createExampleApplication; const __1 = require("../"); class AuthenticationPlugin extends __1.BasePlugin { name = 'authentication'; version = '2.0.0'; config; async setup(config) { this.config = { ...config, jwtSecret: config.jwtSecret || 'default-secret', tokenExpiry: config.tokenExpiry || '1h', publicRoutes: config.publicRoutes || ['/login', '/register', '/health'], }; this.logger.info('Authentication plugin configured', { tokenExpiry: this.config.tokenExpiry, publicRoutes: this.config.publicRoutes.length, }); } registerMiddleware(app) { // JWT validation middleware app.use('/api', (req, res, next) => { const path = req.path; // Skip auth for public routes if (this.config.publicRoutes.includes(path)) { return next(); } const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) { this.logger.warn('Unauthorized access attempt', { path, ip: req.ip, userAgent: req.get('User-Agent'), }); res.status(401).json({ success: false, message: 'No token provided', statusCode: 401, }); return; } // In a real implementation, you would verify the JWT token here this.logger.debug('Token validated for protected route', { path }); // Add user info to request req.user = { id: 1, username: 'john_doe', }; next(); }); } registerRoutes(app) { // Login endpoint app.post('/api/login', (req, res) => { const { username, password } = req.body; this.logger.info('Login attempt', { username }); // In a real implementation, verify credentials if (username && password) { const token = `fake-jwt-token-${Date.now()}`; this.logger.info('Login successful', { username }); res.json({ success: true, data: { token, user: { username }, expiresIn: this.config.tokenExpiry, }, }); } else { this.logger.warn('Login failed - invalid credentials', { username }); res.status(401).json({ success: false, message: 'Invalid credentials', statusCode: 401, }); } }); // User profile endpoint (protected) app.get('/api/profile', (req, res) => { const user = req .user; this.logger.debug('Profile accessed', { userId: user.id }); res.json({ success: true, data: { id: user.id, username: user.username, profile: { email: `${user.username}@example.com`, role: 'user', }, }, }); }); } registerErrorHandlers(app) { // Auth-specific error handler app.use('/api', (err, req, res, next) => { if (err.name === 'JsonWebTokenError') { this.logger.warn('JWT validation error', { error: err.message, path: req.path, }); res.status(401).json({ success: false, message: 'Invalid token', statusCode: 401, }); return; } next(err); }); } } exports.AuthenticationPlugin = AuthenticationPlugin; class MetricsPlugin extends __1.BasePlugin { name = 'metrics'; version = '1.5.0'; config; metrics = { requests: 0, errors: 0, responseTime: [], }; setup(config) { this.config = { ...config, enabled: config.enabled !== undefined ? config.enabled : true, endpoint: config.endpoint || '/metrics', collectSystemMetrics: config.collectSystemMetrics !== undefined ? config.collectSystemMetrics : true, }; if (!this.config.enabled) { this.logger.info('Metrics collection disabled'); return; } this.logger.info('Metrics plugin initialized', { endpoint: this.config.endpoint, systemMetrics: this.config.collectSystemMetrics, }); // Start system metrics collection if (this.config.collectSystemMetrics) { this.startSystemMetricsCollection(); } } startSystemMetricsCollection() { setInterval(() => { const memUsage = process.memoryUsage(); this.logger.debug('System metrics collected', { memory: { rss: Math.round(memUsage.rss / 1024 / 1024), heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024), heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024), }, uptime: Math.round(process.uptime()), }); }, 30000); // Collect every 30 seconds } registerMiddleware(app) { if (!this.config.enabled) return; // Request counting and timing middleware app.use((req, res, next) => { const startTime = Date.now(); // Count request this.metrics.requests++; // Capture response time res.on('finish', () => { const responseTime = Date.now() - startTime; this.metrics.responseTime.push(responseTime); // Keep only last 1000 response times if (this.metrics.responseTime.length > 1000) { this.metrics.responseTime = this.metrics.responseTime.slice(-1000); } // Count errors if (res.statusCode >= 400) { this.metrics.errors++; } this.logger.debug('Request completed', { method: req.method, path: req.path, statusCode: res.statusCode, responseTime, }); }); next(); }); } registerRoutes(app) { if (!this.config.enabled) return; app.get(this.config.endpoint, (req, res) => { const avgResponseTime = this.metrics.responseTime.length > 0 ? this.metrics.responseTime.reduce((a, b) => a + b, 0) / this.metrics.responseTime.length : 0; const memUsage = process.memoryUsage(); const metricsData = { application: { requests: this.metrics.requests, errors: this.metrics.errors, errorRate: this.metrics.requests > 0 ? (this.metrics.errors / this.metrics.requests) * 100 : 0, avgResponseTime: Math.round(avgResponseTime), uptime: Math.round(process.uptime()), }, system: { memory: { rss: Math.round(memUsage.rss / 1024 / 1024), heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024), heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024), external: Math.round(memUsage.external / 1024 / 1024), }, cpu: { usage: process.cpuUsage(), }, }, timestamp: new Date().toISOString(), }; this.logger.debug('Metrics requested', { requestedBy: req.ip }); res.json({ success: true, data: metricsData, }); }); } } exports.MetricsPlugin = MetricsPlugin; /** * Example: How to use these plugins in an application */ function createExampleApplication() { const { BaseApp } = require('../'); const app = new BaseApp({ name: 'Plugin Example API', port: 3002, environment: 'development', logging: { level: 'debug', dir: './logs/plugin-example', }, }); // Register authentication plugin with custom config app.use(new AuthenticationPlugin(), { jwtSecret: 'super-secret-key', tokenExpiry: '24h', publicRoutes: ['/health', '/metrics', '/api/login'], }); // Register metrics plugin app.use(new MetricsPlugin(), { enabled: true, endpoint: '/metrics', collectSystemMetrics: true, }); // Add some test routes app.getApp().get('/api/test', (req, res) => { res.json({ success: true, message: 'This is a protected route', user: req.user, }); }); return app; } console.log('Plugin development examples created. Use createExampleApplication() to test.');