@reldens/server-utils 0.42.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -21,215 +21,74 @@ npm test
21
21
 
22
22
  ## Architecture
23
23
 
24
- ### Core Classes
25
-
26
- **FileHandler** (`lib/file-handler.js`):
27
- - Singleton wrapper for Node.js fs and path modules
28
- - Used instead of direct require('fs') or require('path') throughout Reldens
29
- - Key file operations:
30
- - `exists(filePath)` - Check if file/directory exists
31
- - `readFile(filePath)` - Read file contents
32
- - `writeFile(filePath, content)` - Write file
33
- - `createFolder(folderPath)` - Create directory recursively
34
- - `remove(fullPath)` - Remove file/folder recursively
35
- - `copyFile(from, to)` - Copy file
36
- - `copyFolderSync(from, to)` - Copy folder recursively
37
- - `moveFile(from, to)` - Move/rename file
38
- - Path operations:
39
- - `joinPaths(...paths)` - Join path segments
40
- - `getFileName(filePath)` - Get file name (basename)
41
- - `getFolderName(filePath)` - Get directory name (dirname)
42
- - `getRelativePath(from, to)` - Calculate relative path
43
- - `normalizePath(filePath)` - Normalize path
44
- - `isAbsolutePath(filePath)` - Check if path is absolute
45
- - File inspection:
46
- - `isFile(filePath)` - Check if path is a file
47
- - `isFolder(dirPath)` - Check if path is a folder
48
- - `getFileSize(filePath)` - Get file size in bytes
49
- - `getFileStats(filePath)` - Get file stats
50
- - `getFilesInFolder(dirPath, extensions)` - List files with optional filtering
51
- - `fetchSubFoldersList(folder, options)` - Get subfolder list
52
- - JSON operations:
53
- - `fetchFileJson(filePath)` - Read and parse JSON file
54
- - `isValidJson(filePath)` - Validate JSON file
55
- - Security features:
56
- - `generateSecureFilename(originalName)` - Generate secure random filename
57
- - `validateFileType(filePath, type, allowedTypes, maxSize)` - Validate file
58
- - `detectFileType(filePath)` - Detect MIME type from magic numbers
59
- - `quarantineFile(filePath, reason)` - Move suspicious file to quarantine
60
- - `isValidPath(filePath)` - Validate path for security
61
- - `sanitizePath(filePath)` - Sanitize path string
62
- - Advanced operations:
63
- - `walkDirectory(dirPath, callback)` - Recursively process directory tree
64
- - `getDirectorySize(dirPath)` - Calculate total directory size
65
- - `emptyDirectory(dirPath)` - Remove all contents from directory
66
- - `compareFiles(file1, file2)` - Compare file contents
67
- - `appendToFile(filePath, content)` - Append to file
68
- - `prependToFile(filePath, content)` - Prepend to file
69
- - `replaceInFile(filePath, searchValue, replaceValue)` - Replace in file
70
- - All methods include built-in error handling, no need for try/catch
71
- - DO NOT use FileHandler.exists to validate other FileHandler methods
72
- - DO NOT enclose FileHandler methods in try/catch blocks
24
+ See `.claude/package-architecture.md` for detailed information about:
25
+ - Design philosophy and independence principles
26
+ - Callback-based extensibility pattern
27
+ - Available callbacks (onError, onRequestSuccess, onRequestError, onEvent)
28
+ - Integration patterns
73
29
 
74
- **AppServerFactory** (`lib/app-server-factory.js`):
75
- - Creates Express app servers with modular security components
76
- - Supports HTTP, HTTPS, HTTP/2
77
- - Key features:
78
- - Virtual host management with SNI support
79
- - HTTP/2 CDN server integration
80
- - Reverse proxy with WebSocket support
81
- - Development mode detection and configuration
82
- - Security configurers (modular):
83
- - `DevelopmentModeDetector` - Auto-detect development environment
84
- - `ProtocolEnforcer` - HTTP/HTTPS protocol enforcement
85
- - `SecurityConfigurer` - Helmet integration and XSS protection
86
- - `CorsConfigurer` - CORS with dynamic origin validation
87
- - `RateLimitConfigurer` - Global and endpoint-specific rate limiting
88
- - `ReverseProxyConfigurer` - Domain-based reverse proxy
89
- - Methods:
90
- - `createAppServer(config)` - Create and configure server
91
- - `addDomain(domainConfig)` - Add virtual host domain
92
- - `addDevelopmentDomain(domain)` - Add development domain
93
- - `enableServeHome(app, callback)` - Enable homepage serving
94
- - `serveStatics(app, staticPath)` - Serve static files
95
- - `enableCSP(cspOptions)` - Enable Content Security Policy
96
- - `listen(port)` - Start server listening
97
- - `close()` - Gracefully close server
98
-
99
- **Encryptor** (`lib/encryptor.js`):
100
- - Singleton for cryptographic operations
101
- - Password hashing:
102
- - `encryptPassword(password)` - Hash password with PBKDF2 (100k iterations, SHA-512)
103
- - `validatePassword(password, storedPassword)` - Validate password against hash
104
- - Data encryption:
105
- - `encryptData(data, key)` - Encrypt data with AES-256-GCM
106
- - `decryptData(encryptedData, key)` - Decrypt AES-256-GCM data
107
- - `generateSecretKey()` - Generate 256-bit secret key
108
- - Token generation:
109
- - `generateSecureToken(length)` - Generate cryptographically secure token
110
- - `generateTOTP(secret, timeStep)` - Generate time-based OTP
111
- - Hashing and verification:
112
- - `hashData(data, algorithm)` - Hash with SHA-256, SHA-512, or MD5
113
- - `generateHMAC(data, secret, algorithm)` - Generate HMAC signature
114
- - `verifyHMAC(data, secret, signature, algorithm)` - Verify HMAC signature
115
- - `constantTimeCompare(a, b)` - Constant-time string comparison
116
-
117
- **UploaderFactory** (`lib/uploader-factory.js`):
118
- - File upload handling with Multer
119
- - Multi-level security validation:
120
- - Filename security validation
121
- - MIME type validation
122
- - File extension validation
123
- - File size validation
124
- - Content validation using magic numbers
125
- - Dangerous extension filtering
126
- - Features:
127
- - Multiple file upload support with field mapping
128
- - Secure filename generation option
129
- - Automatic cleanup on validation failure
130
- - Custom error response handling
131
- - Per-field destination mapping
132
- - Methods:
133
- - `createUploader(fields, buckets, allowedFileTypes)` - Create upload middleware
134
- - `validateFilenameSecurity(filename)` - Validate filename
135
- - `validateFile(file, allowedType, callback)` - Validate during upload
136
- - `validateFileContents(file, allowedType)` - Validate after upload
137
- - `convertToRegex(key)` - Convert MIME type patterns to regex
138
-
139
- **Http2CdnServer** (`lib/http2-cdn-server.js`):
140
- - HTTP/2 secure server for CDN-like static file serving
141
- - Features:
142
- - Optimized for CSS, JavaScript, images, and fonts
143
- - Dynamic CORS origin validation with regex pattern support
144
- - Configurable cache headers per file extension
145
- - Comprehensive MIME type detection
146
- - HTTP/1.1 fallback support
147
- - Security headers (X-Content-Type-Options, X-Frame-Options, Vary)
148
- - Query string stripping for cache optimization
149
- - Methods:
150
- - `create()` - Create HTTP/2 secure server
151
- - `listen()` - Start listening on configured port
152
- - `close()` - Gracefully close server
153
- - `handleStream(stream, headers)` - Handle HTTP/2 stream
154
- - `resolveFilePath(requestPath)` - Resolve file path from request
155
-
156
- ### Utility Classes
157
-
158
- **ServerDefaultConfigurations** (`lib/server-default-configurations.js`):
159
- - Static class providing default configurations
160
- - `mimeTypes` - Comprehensive MIME type mappings for common file extensions
161
- - `cacheConfig` - Default cache max-age settings (1 year for CSS/JS/fonts, 30 days for images)
162
-
163
- **ServerFactoryUtils** (`lib/server-factory-utils.js`):
164
- - Static utility methods for server operations
165
- - `getCacheConfigForPath(path, cacheConfig)` - Get cache config for file path
166
- - `validateOrigin(origin, corsOrigins, corsAllowAll)` - Validate CORS origin (supports strings and RegExp)
167
- - `stripQueryString(url)` - Remove query string from URL
168
-
169
- **ServerHeaders** (`lib/server-headers.js`):
170
- - Centralized header management
171
- - HTTP/2 headers configuration
172
- - Express security headers
173
- - Cache control headers
174
- - Proxy forwarding headers
175
- - `buildCacheControlHeader(maxAge)` - Build cache control header string
176
-
177
- ### Security Configurers (in `lib/app-server-factory/`)
178
-
179
- **DevelopmentModeDetector** (`development-mode-detector.js`):
180
- - Auto-detects development environment
181
- - Checks NODE_ENV, domain patterns, and configured domains
182
- - Built-in patterns: localhost, 127.0.0.1, .local, .test, .dev, .staging, etc.
183
- - `detect(config)` - Detect if in development mode
184
- - `matchesPattern(domain)` - Check if domain matches development pattern
185
-
186
- **ProtocolEnforcer** (`protocol-enforcer.js`):
187
- - Enforces HTTP/HTTPS protocol consistency
188
- - Development mode awareness
189
- - Automatic redirects when protocol doesn't match configuration
190
- - `setup(app, config)` - Setup protocol enforcement middleware
191
-
192
- **SecurityConfigurer** (`security-configurer.js`):
193
- - Helmet integration with CSP management
194
- - XSS protection with request body sanitization
195
- - Development-friendly CSP configuration
196
- - Supports CSP directive merging or override
197
- - `setupHelmet(app, config)` - Setup Helmet middleware
198
- - `setupXssProtection(app, config)` - Setup XSS protection
199
- - `enableCSP(app, cspOptions)` - Enable Content Security Policy
200
- - `addExternalDomainsToCsp(directives, externalDomains)` - Add external domains to CSP
201
-
202
- **CorsConfigurer** (`cors-configurer.js`):
203
- - Dynamic CORS origin validation
204
- - Development domain support with automatic port variations
205
- - Credential support configuration
206
- - `setup(app, config)` - Setup CORS middleware
207
- - `extractDevelopmentOrigins(domainMapping)` - Extract development origins
208
- - `normalizeHost(originOrHost)` - Normalize host string
209
-
210
- **RateLimitConfigurer** (`rate-limit-configurer.js`):
211
- - Global and endpoint-specific rate limiting
212
- - Development mode multiplier for lenient limits
213
- - IP-based key generation option
214
- - `setup(app, config)` - Setup global rate limiting
215
- - `createHomeLimiter()` - Create homepage-specific limiter
216
-
217
- **ReverseProxyConfigurer** (`reverse-proxy-configurer.js`):
218
- - Domain-based reverse proxy routing
219
- - WebSocket support
220
- - SSL termination
221
- - Header preservation (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host)
222
- - Virtual host integration
223
- - Graceful error handling (502 Bad Gateway, 504 Gateway Timeout)
224
- - `setup(app, config)` - Setup reverse proxy
225
- - `createProxyMiddleware(rule)` - Create proxy middleware for rule
226
- - `handleProxyError(err, req, res)` - Handle proxy errors
30
+ See `.claude/api-reference.md` for complete API documentation of all classes and methods.
31
+
32
+ ## Core Classes Summary
33
+
34
+ **FileHandler** - Singleton wrapper for Node.js fs and path modules. Used instead of direct require('fs') or require('path') throughout Reldens.
35
+
36
+ **AppServerFactory** - Creates Express app servers with modular security components. Supports HTTP, HTTPS, HTTP/2, virtual hosts, CDN integration, reverse proxy, and callback-based logging.
37
+
38
+ **Encryptor** - Singleton for cryptographic operations including password hashing, data encryption, token generation, and HMAC verification.
39
+
40
+ **UploaderFactory** - File upload handling with Multer and multi-level security validation.
41
+
42
+ **Http2CdnServer** - HTTP/2 secure server for CDN-like static file serving with CORS, cache headers, and callback-based logging.
43
+
44
+ ## Utility Classes Summary
45
+
46
+ **RequestLogger** - Express middleware for request logging that invokes callbacks based on status codes.
47
+
48
+ **EventDispatcher** - Static utility for dispatching lifecycle events with structured event data.
49
+
50
+ **ServerErrorHandler** - Centralized error handling with structured error context.
51
+
52
+ **ServerDefaultConfigurations** - Static class providing MIME types and cache configurations.
53
+
54
+ **ServerFactoryUtils** - Static utility methods for cache config, CORS validation, and URL manipulation.
55
+
56
+ **ServerHeaders** - Centralized header management for HTTP/2, security, cache, and proxy headers.
57
+
58
+ ## Security Configurers Summary
59
+
60
+ Located in `lib/app-server-factory/`:
61
+ - **DevelopmentModeDetector** - Auto-detect development environment
62
+ - **ProtocolEnforcer** - HTTP/HTTPS protocol enforcement
63
+ - **SecurityConfigurer** - Helmet integration and XSS protection
64
+ - **CorsConfigurer** - CORS with dynamic origin validation
65
+ - **RateLimitConfigurer** - Global and endpoint-specific rate limiting
66
+ - **ReverseProxyConfigurer** - Domain-based reverse proxy with WebSocket support
227
67
 
228
68
  ## Important Notes
229
69
 
70
+ ### FileHandler Usage
230
71
  - **ALWAYS use FileHandler** instead of Node.js fs/path modules
231
72
  - FileHandler methods have built-in error handling - no try/catch needed
232
73
  - DO NOT enclose FileHandler methods in try/catch blocks
233
74
  - DO NOT use FileHandler.exists to validate other FileHandler methods (e.g., before createFolder)
75
+
76
+ ### Callback System
77
+ - Package provides callback hooks (onError, onRequestSuccess, onRequestError, onEvent)
78
+ - Applications provide implementations via configuration
79
+ - Package does NOT import @reldens/utils Logger
80
+ - Applications wire callbacks to their own logging/monitoring systems
81
+
82
+ ### Server Configuration
234
83
  - AppServerFactory handles all Express server configuration
235
84
  - All server utilities support both HTTP and HTTPS
85
+ - Virtual hosts with SNI support for multiple domains
86
+ - HTTP/2 CDN server integration for static file serving
87
+ - Reverse proxy with WebSocket support
88
+
89
+ ### Security
90
+ - Multi-level validation for file uploads
91
+ - XSS protection with request body sanitization
92
+ - CSP management with Helmet integration
93
+ - CORS with dynamic origin validation (supports strings and RegExp)
94
+ - Rate limiting with development mode awareness
package/README.md CHANGED
@@ -25,6 +25,7 @@ A Node.js server toolkit providing secure application server creation, HTTP/2 CD
25
25
  - Static file serving with security headers
26
26
  - Compression middleware with smart filtering
27
27
  - Input validation utilities
28
+ - Custom error handling with callback support
28
29
 
29
30
  ### Http2CdnServer
30
31
  - Dedicated HTTP/2 server for static asset delivery
@@ -37,6 +38,8 @@ A Node.js server toolkit providing secure application server creation, HTTP/2 CD
37
38
  - Standalone or integrated with AppServerFactory
38
39
  - Multiple static path support
39
40
  - Separate SSL certificate support from main server
41
+ - Comprehensive error handling (server, TLS, session, stream errors)
42
+ - Custom error handler callback support
40
43
 
41
44
  #### Modular Security Components
42
45
  The AppServerFactory now uses specialized security configurers:
@@ -47,6 +50,7 @@ The AppServerFactory now uses specialized security configurers:
47
50
  - **RateLimitConfigurer** - Global and endpoint-specific rate limiting
48
51
  - **ReverseProxyConfigurer** - Domain-based reverse proxy with WebSocket support
49
52
  - **SecurityConfigurer** - Helmet integration with CSP management and XSS protection
53
+ - **ServerErrorHandler** - Centralized error handling with custom callback support
50
54
 
51
55
  ### FileHandler
52
56
  - Secure file system operations with path validation
@@ -63,6 +67,8 @@ The AppServerFactory now uses specialized security configurers:
63
67
  - Directory walking with callback processing
64
68
  - File comparison and relative path calculations
65
69
  - Comprehensive error handling with detailed context
70
+ - Read stream creation for efficient file streaming
71
+ - File modification time retrieval
66
72
 
67
73
  ### Encryptor
68
74
  - Password hashing using PBKDF2 with configurable iterations
@@ -174,6 +180,34 @@ if(cdnServer.create()){
174
180
  }
175
181
  ```
176
182
 
183
+ ### Custom Error Handling
184
+
185
+ Configure custom error handlers for server errors:
186
+
187
+ ```javascript
188
+ let appServerFactory = new AppServerFactory();
189
+
190
+ appServerFactory.onError = (errorData) => {
191
+ console.error('Server error:', errorData.key);
192
+ console.error('Error details:', errorData.error);
193
+ console.error('Context:', errorData);
194
+ };
195
+
196
+ let serverResult = appServerFactory.createAppServer({
197
+ port: 443,
198
+ useHttps: true,
199
+ http2CdnEnabled: true,
200
+ autoListen: true
201
+ });
202
+ ```
203
+
204
+ The `onError` callback receives structured error data:
205
+ - `instanceName` - Name of the component (e.g., 'http2CdnServer', 'appServerFactory')
206
+ - `instance` - Reference to the component instance
207
+ - `key` - Error type identifier (e.g., 'server-error', 'tls-client-error', 'proxy-error')
208
+ - `error` - The actual error object
209
+ - `...context` - Additional context data (port, path, hostname, etc.)
210
+
177
211
  ### HTTPS Server with Optimized Caching
178
212
 
179
213
  ```javascript
@@ -225,6 +259,18 @@ if(FileHandler.createFolder('/path/to/new/folder')){
225
259
  // Generate a secure filename
226
260
  let secureFilename = FileHandler.generateSecureFilename('user-upload.jpg');
227
261
  console.log('Secure filename:', secureFilename);
262
+
263
+ // Create a read stream for efficient file handling
264
+ let stream = FileHandler.createReadStream('/path/to/large-file.txt');
265
+ if(stream){
266
+ stream.pipe(response);
267
+ }
268
+
269
+ // Get file modification time
270
+ let modTime = FileHandler.getFileModificationTime('/path/to/file.txt');
271
+ if(modTime){
272
+ console.log('Last modified:', modTime);
273
+ }
228
274
  ```
229
275
 
230
276
  ### Password Encryption
@@ -515,7 +561,10 @@ let serverResult = appServerFactory.createAppServer({
515
561
  - Header preservation (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host)
516
562
  - Virtual host integration
517
563
  - Path-based routing
518
- - Graceful error handling
564
+ - Comprehensive error handling with proper HTTP status codes:
565
+ - 502 Bad Gateway for connection refused errors
566
+ - 504 Gateway Timeout for timeout errors
567
+ - 500 Internal Server Error for other proxy errors
519
568
 
520
569
  #### Rule Properties
521
570
 
@@ -569,6 +618,15 @@ reverseProxyRules: [
569
618
  - `reverseProxyEnabled` - Enable reverse proxy (default: false)
570
619
  - `reverseProxyRules` - Array of proxy rules (default: [])
571
620
 
621
+ ### AppServerFactory Error Handling
622
+
623
+ - `onError` - Custom error handler callback function receiving error data:
624
+ - `instanceName` - Component name (e.g., 'appServerFactory', 'http2CdnServer')
625
+ - `instance` - Component instance reference
626
+ - `key` - Error type identifier (e.g., 'server-error', 'virtual-host-error')
627
+ - `error` - The error object
628
+ - Additional context data (port, hostname, path, etc.)
629
+
572
630
  ### Http2CdnServer Methods
573
631
 
574
632
  - `create()` - Creates HTTP/2 secure server
@@ -591,6 +649,7 @@ reverseProxyRules: [
591
649
  - `securityHeaders` - Custom security headers
592
650
  - `varyHeader` - Vary header value (default: 'Accept-Encoding, Origin')
593
651
  - `mimeTypes` - MIME type mappings
652
+ - `onError` - Custom error handler callback
594
653
 
595
654
  ### FileHandler Methods
596
655
 
@@ -620,6 +679,8 @@ reverseProxyRules: [
620
679
  - `walkDirectory(path, callback)` - Recursively processes a directory tree
621
680
  - `getDirectorySize(path)` - Calculates total directory size
622
681
  - `emptyDirectory(path)` - Removes all contents from directory
682
+ - `createReadStream(path, options)` - Creates readable stream for file
683
+ - `getFileModificationTime(path)` - Gets file last modification time
623
684
 
624
685
  ### Encryptor Methods
625
686
 
@@ -643,6 +704,16 @@ reverseProxyRules: [
643
704
  - `validateFileContents(file, allowedType)` - Validates file content after upload
644
705
  - `convertToRegex(key)` - Converts MIME type patterns to regex
645
706
 
707
+ ### ServerErrorHandler Methods
708
+
709
+ - `handleError(onErrorCallback, instanceName, instance, key, error, context)` - Static method for centralized error handling
710
+ - `onErrorCallback` - Custom error handler function (optional)
711
+ - `instanceName` - Name of the component ('http2CdnServer', 'appServerFactory', etc.)
712
+ - `instance` - Reference to the component instance
713
+ - `key` - Error type identifier
714
+ - `error` - The error object
715
+ - `context` - Additional context object (port, hostname, path, etc.)
716
+
646
717
  ## Security Features
647
718
 
648
719
  ### Path Traversal Protection
@@ -668,7 +739,15 @@ Industry-standard encryption using PBKDF2 for passwords, AES-256-GCM for data en
668
739
 
669
740
  ## Error Handling
670
741
 
671
- All methods include comprehensive error handling with detailed error objects containing context information. Errors are logged appropriately and never expose sensitive system information.
742
+ All server components include comprehensive error handling with centralized error management through the ServerErrorHandler class. Custom error handlers can be configured via the `onError` callback to process errors according to application requirements. Errors are logged appropriately and never expose sensitive system information.
743
+
744
+ Error handling features:
745
+ - Centralized error management with ServerErrorHandler
746
+ - Custom error callback support across all components
747
+ - Structured error context with instance details and metadata
748
+ - Graceful HTTP status codes for proxy errors (502, 504, 500)
749
+ - TLS and session error handling for HTTP/2 servers
750
+ - Virtual host and SNI certificate error handling
672
751
 
673
752
  ---
674
753
 
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  const cors = require('cors');
8
+ const { EventDispatcher } = require('../event-dispatcher');
8
9
 
9
10
  class CorsConfigurer
10
11
  {
@@ -18,6 +19,7 @@ class CorsConfigurer
18
19
  this.corsHeaders = ['Content-Type','Authorization'];
19
20
  this.developmentCorsOrigins = [];
20
21
  this.developmentPorts = [];
22
+ this.onEvent = null;
21
23
  }
22
24
 
23
25
  setup(app, config)
@@ -28,6 +30,7 @@ class CorsConfigurer
28
30
  this.corsMethods = config.corsMethods || this.corsMethods;
29
31
  this.corsHeaders = config.corsHeaders || this.corsHeaders;
30
32
  this.developmentPorts = config.developmentPorts || this.developmentPorts;
33
+ this.onEvent = config.onEvent || null;
31
34
  if(!this.useCors){
32
35
  return;
33
36
  }
@@ -58,6 +61,13 @@ class CorsConfigurer
58
61
  };
59
62
  }
60
63
  app.use(cors(corsOptions));
64
+ EventDispatcher.dispatch(
65
+ this.onEvent,
66
+ 'cors-configured',
67
+ 'corsConfigurer',
68
+ this,
69
+ {useCors: this.useCors, isDevelopmentMode: this.isDevelopmentMode, corsOrigin: this.corsOrigin}
70
+ );
61
71
  }
62
72
 
63
73
  extractDevelopmentOrigins(domainMapping)
@@ -4,6 +4,8 @@
4
4
  *
5
5
  */
6
6
 
7
+ const { EventDispatcher } = require('../event-dispatcher');
8
+
7
9
  class DevelopmentModeDetector
8
10
  {
9
11
 
@@ -27,10 +29,12 @@ class DevelopmentModeDetector
27
29
  ];
28
30
  this.developmentEnvironments = ['development', 'dev', 'test'];
29
31
  this.env = process?.env?.NODE_ENV || 'production';
32
+ this.onEvent = null;
30
33
  }
31
34
 
32
35
  detect(config = {})
33
36
  {
37
+ this.onEvent = config.onEvent || null;
34
38
  if(config.developmentPatterns){
35
39
  this.developmentPatterns = config.developmentPatterns;
36
40
  }
@@ -38,11 +42,25 @@ class DevelopmentModeDetector
38
42
  this.developmentEnvironments = config.developmentEnvironments;
39
43
  }
40
44
  if(this.developmentEnvironments.includes(this.env)){
45
+ EventDispatcher.dispatch(
46
+ this.onEvent,
47
+ 'development-mode-detected',
48
+ 'developmentModeDetector',
49
+ this,
50
+ {detectionMethod: 'environment', env: this.env}
51
+ );
41
52
  return true;
42
53
  }
43
54
  if(config.developmentDomains && 0 < config.developmentDomains.length){
44
55
  for(let domain of config.developmentDomains){
45
56
  if(this.matchesPattern(domain)){
57
+ EventDispatcher.dispatch(
58
+ this.onEvent,
59
+ 'development-mode-detected',
60
+ 'developmentModeDetector',
61
+ this,
62
+ {detectionMethod: 'developmentDomain', domain: domain}
63
+ );
46
64
  return true;
47
65
  }
48
66
  }
@@ -53,6 +71,13 @@ class DevelopmentModeDetector
53
71
  continue;
54
72
  }
55
73
  if(this.matchesPattern(domainConfig.hostname)){
74
+ EventDispatcher.dispatch(
75
+ this.onEvent,
76
+ 'development-mode-detected',
77
+ 'developmentModeDetector',
78
+ this,
79
+ {detectionMethod: 'domainPattern', hostname: domainConfig.hostname}
80
+ );
56
81
  return true;
57
82
  }
58
83
  }
@@ -4,6 +4,8 @@
4
4
  *
5
5
  */
6
6
 
7
+ const { EventDispatcher } = require('../event-dispatcher');
8
+
7
9
  class ProtocolEnforcer
8
10
  {
9
11
 
@@ -12,6 +14,7 @@ class ProtocolEnforcer
12
14
  this.isDevelopmentMode = false;
13
15
  this.useHttps = false;
14
16
  this.enforceProtocol = true;
17
+ this.onEvent = null;
15
18
  }
16
19
 
17
20
  setup(app, config)
@@ -19,6 +22,7 @@ class ProtocolEnforcer
19
22
  this.isDevelopmentMode = config.isDevelopmentMode || false;
20
23
  this.useHttps = config.useHttps || false;
21
24
  this.enforceProtocol = config.enforceProtocol !== false;
25
+ this.onEvent = config.onEvent || null;
22
26
  app.use((req, res, next) => {
23
27
  let forwardedProto = req.get('X-Forwarded-Proto');
24
28
  let protocol = (forwardedProto || req.protocol || '').toLowerCase();
@@ -41,6 +45,13 @@ class ProtocolEnforcer
41
45
  res.set('X-Forwarded-Proto', protocol);
42
46
  next();
43
47
  });
48
+ EventDispatcher.dispatch(
49
+ this.onEvent,
50
+ 'protocol-enforcement-enabled',
51
+ 'protocolEnforcer',
52
+ this,
53
+ {isDevelopmentMode: this.isDevelopmentMode, useHttps: this.useHttps, enforceProtocol: this.enforceProtocol}
54
+ );
44
55
  }
45
56
 
46
57
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  const rateLimit = require('express-rate-limit');
8
+ const { EventDispatcher } = require('../event-dispatcher');
8
9
 
9
10
  class RateLimitConfigurer
10
11
  {
@@ -19,6 +20,7 @@ class RateLimitConfigurer
19
20
  this.applyKeyGenerator = false;
20
21
  this.tooManyRequestsMessage = 'Too many requests, please try again later.';
21
22
  this.rateLimit = rateLimit;
23
+ this.onEvent = null;
22
24
  }
23
25
 
24
26
  setup(app, config)
@@ -30,6 +32,7 @@ class RateLimitConfigurer
30
32
  this.developmentMultiplier = Number(config.developmentMultiplier || this.developmentMultiplier);
31
33
  this.applyKeyGenerator = config.applyKeyGenerator || false;
32
34
  this.tooManyRequestsMessage = config.tooManyRequestsMessage || this.tooManyRequestsMessage;
35
+ this.onEvent = config.onEvent || null;
33
36
  if(!this.globalRateLimit){
34
37
  return;
35
38
  }
@@ -49,6 +52,13 @@ class RateLimitConfigurer
49
52
  };
50
53
  }
51
54
  app.use(this.rateLimit(limiterParams));
55
+ EventDispatcher.dispatch(
56
+ this.onEvent,
57
+ 'rate-limiting-configured',
58
+ 'rateLimitConfigurer',
59
+ this,
60
+ {globalRateLimit: this.globalRateLimit, maxRequests: limiterParams.limit, windowMs: this.windowMs}
61
+ );
52
62
  }
53
63
 
54
64
  createHomeLimiter()
@@ -6,6 +6,8 @@
6
6
 
7
7
  const { createProxyMiddleware } = require('http-proxy-middleware');
8
8
  const { ServerHeaders } = require('../server-headers');
9
+ const { ServerErrorHandler } = require('../server-error-handler');
10
+ const { EventDispatcher } = require('../event-dispatcher');
9
11
 
10
12
  class ReverseProxyConfigurer
11
13
  {
@@ -22,6 +24,8 @@ class ReverseProxyConfigurer
22
24
  logLevel: 'warn'
23
25
  };
24
26
  this.serverHeaders = new ServerHeaders();
27
+ this.onError = null;
28
+ this.onEvent = null;
25
29
  }
26
30
 
27
31
  setup(app, config)
@@ -30,10 +34,19 @@ class ReverseProxyConfigurer
30
34
  this.useVirtualHosts = config.useVirtualHosts || false;
31
35
  this.reverseProxyRules = config.reverseProxyRules || [];
32
36
  this.reverseProxyOptions = config.reverseProxyOptions || this.reverseProxyOptions;
37
+ this.onError = config.onError || null;
38
+ this.onEvent = config.onEvent || null;
33
39
  if(0 === this.reverseProxyRules.length){
34
40
  return;
35
41
  }
36
42
  this.applyRules(app);
43
+ EventDispatcher.dispatch(
44
+ this.onEvent,
45
+ 'reverse-proxy-configured',
46
+ 'reverseProxyConfigurer',
47
+ this,
48
+ {rulesCount: this.reverseProxyRules.length, useVirtualHosts: this.useVirtualHosts}
49
+ );
37
50
  }
38
51
 
39
52
  applyRules(app)
@@ -100,7 +113,9 @@ class ReverseProxyConfigurer
100
113
  options.logLevel = rule.logLevel;
101
114
  }
102
115
  options.target = rule.target;
103
- options.onError = this.handleProxyError.bind(this);
116
+ options.onError = (err, req, res) => {
117
+ this.handleProxyError(err, req, res);
118
+ };
104
119
  options.onProxyReq = (proxyReq, req) => {
105
120
  if(req.headers['x-forwarded-for']){
106
121
  return;
@@ -115,6 +130,16 @@ class ReverseProxyConfigurer
115
130
 
116
131
  handleProxyError(err, req, res)
117
132
  {
133
+ let hostname = req.get('host') || 'unknown';
134
+ let requestPath = req.path || req.url || 'unknown';
135
+ ServerErrorHandler.handleError(
136
+ this.onError,
137
+ 'reverseProxyConfigurer',
138
+ this,
139
+ 'proxy-error',
140
+ err,
141
+ {request: req, response: res, hostname: hostname, path: requestPath}
142
+ );
118
143
  if(res.headersSent){
119
144
  return;
120
145
  }