UNPKG

thrilled-be-core

Version:

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

150 lines (149 loc) 4.88 kB
"use strict"; /** * Correlation ID Middleware for Request Tracking * * This middleware ensures that every request has a unique correlation ID * that can be used for tracking requests across the application, logs, * and external services. This is essential for distributed tracing and * debugging in microservices architectures. * * @package be-core * @since 1.0.0 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CorrelationIdMiddleware = void 0; exports.createCorrelationIdMiddleware = createCorrelationIdMiddleware; exports.correlationId = correlationId; const crypto_1 = require("crypto"); const Logger_1 = require("../logging/Logger"); /** * Correlation ID Middleware for tracking requests across distributed systems */ class CorrelationIdMiddleware { logger; options; constructor(options = {}) { this.logger = options.logger || new Logger_1.Logger({ level: 'info', dir: './logs' }); this.options = { logger: this.logger, headerName: 'X-Correlation-ID', propertyName: 'correlationId', generateId: () => (0, crypto_1.randomUUID)(), enforceHeader: false, logRequests: process.env.NODE_ENV !== 'test', ...options, }; } /** * Main correlation ID middleware */ handle() { return (req, res, next) => { const correlationId = this.extractOrGenerateCorrelationId(req); // Attach correlation ID to request using custom property name req[this.options.propertyName] = correlationId; // Also set the standard correlationId for compatibility req.correlationId = correlationId; req.requestId = correlationId; // Alias for compatibility // Set response header res.setHeader(this.options.headerName, correlationId); // Log request if enabled if (this.options.logRequests) { this.logRequest(req); } next(); }; } /** * Extract correlation ID from request or generate new one */ extractOrGenerateCorrelationId(req) { // Try to get correlation ID from various header names const headerSources = [ this.options.headerName, 'X-Request-ID', 'X-Trace-ID', 'Request-ID', 'Trace-ID', ]; for (const headerName of headerSources) { const value = req.get(headerName); if (value && this.isValidCorrelationId(value)) { return value; } } // Generate new correlation ID return this.options.generateId(); } /** * Validate correlation ID format */ isValidCorrelationId(id) { // Basic validation - should be non-empty string with reasonable length return typeof id === 'string' && id.length > 0 && id.length <= 128 && !/[<>"'&]/.test(id); // Basic XSS protection } /** * Log incoming request with correlation ID */ logRequest(req) { try { this.logger.info('Incoming request', { correlationId: req.correlationId, method: req.method, url: req.originalUrl, userAgent: req.get('User-Agent'), ip: req.ip, timestamp: new Date().toISOString(), }); } catch (error) { // Silently fail if logging fails - don't break the request flow // The correlation ID is still attached to the request } } /** * Get correlation ID from request */ static getCorrelationId(req) { return req.correlationId; } /** * Get correlation ID from request with fallback */ static getCorrelationIdSafe(req) { return req.correlationId || 'unknown'; } /** * Health check for correlation ID middleware */ healthCheck() { return { name: 'correlation-id-middleware', status: 'healthy', timestamp: new Date().toISOString(), details: { headerName: this.options.headerName, propertyName: this.options.propertyName, enforceHeader: this.options.enforceHeader, logRequests: this.options.logRequests, }, }; } } exports.CorrelationIdMiddleware = CorrelationIdMiddleware; /** * Factory function to create correlation ID middleware */ function createCorrelationIdMiddleware(options) { return new CorrelationIdMiddleware(options); } /** * Express middleware function for correlation ID */ function correlationId(options) { const middleware = new CorrelationIdMiddleware(options); return middleware.handle(); }