mastercontroller 1.2.11 → 1.2.13
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/CSPConfig.js +319 -0
- package/EventHandlerValidator.js +464 -0
- package/MasterAction.js +296 -72
- package/MasterBackendErrorHandler.js +769 -0
- package/MasterBenchmark.js +89 -0
- package/MasterBuildOptimizer.js +376 -0
- package/MasterBundleAnalyzer.js +108 -0
- package/MasterCache.js +400 -0
- package/MasterControl.js +77 -7
- package/MasterErrorHandler.js +487 -0
- package/MasterErrorLogger.js +360 -0
- package/MasterErrorMiddleware.js +407 -0
- package/MasterHtml.js +101 -14
- package/MasterMemoryMonitor.js +188 -0
- package/MasterProfiler.js +409 -0
- package/MasterRouter.js +273 -66
- package/MasterSanitizer.js +429 -0
- package/MasterTemplate.js +96 -3
- package/MasterValidator.js +546 -0
- package/README.md +0 -44
- package/SecurityMiddleware.js +486 -0
- package/SessionSecurity.js +416 -0
- package/package.json +2 -2
- package/ssr/ErrorBoundary.js +353 -0
- package/ssr/HTMLUtils.js +15 -0
- package/ssr/HydrationMismatch.js +265 -0
- package/ssr/PerformanceMonitor.js +233 -0
- package/ssr/SSRErrorHandler.js +273 -0
- package/ssr/hydration-client.js +93 -0
- package/ssr/runtime-ssr.cjs +553 -0
- package/ssr/ssr-shims.js +73 -0
- package/examples/FileServingExample.js +0 -88
package/MasterCache.js
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
// version 1.0.0
|
|
2
|
+
// MasterController Cache System - Runtime Performance Optimization
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Multi-level cache system for MasterController
|
|
6
|
+
* - Event manifest caching
|
|
7
|
+
* - Component render caching
|
|
8
|
+
* - Template caching
|
|
9
|
+
* - LRU eviction
|
|
10
|
+
* - TTL support
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { logger } = require('./MasterErrorLogger');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* LRU Cache with TTL support
|
|
17
|
+
*/
|
|
18
|
+
class LRUCache {
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.maxSize = options.maxSize || 100;
|
|
21
|
+
this.ttl = options.ttl || 3600000; // 1 hour default
|
|
22
|
+
this.cache = new Map();
|
|
23
|
+
this.accessOrder = [];
|
|
24
|
+
|
|
25
|
+
// Statistics
|
|
26
|
+
this.hits = 0;
|
|
27
|
+
this.misses = 0;
|
|
28
|
+
this.evictions = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get value from cache
|
|
33
|
+
*/
|
|
34
|
+
get(key) {
|
|
35
|
+
const entry = this.cache.get(key);
|
|
36
|
+
|
|
37
|
+
if (!entry) {
|
|
38
|
+
this.misses++;
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Check TTL
|
|
43
|
+
if (Date.now() > entry.expiry) {
|
|
44
|
+
this.cache.delete(key);
|
|
45
|
+
this.accessOrder = this.accessOrder.filter(k => k !== key);
|
|
46
|
+
this.misses++;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Update access order (move to end)
|
|
51
|
+
this.accessOrder = this.accessOrder.filter(k => k !== key);
|
|
52
|
+
this.accessOrder.push(key);
|
|
53
|
+
|
|
54
|
+
this.hits++;
|
|
55
|
+
return entry.value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Set value in cache
|
|
60
|
+
*/
|
|
61
|
+
set(key, value, ttl = null) {
|
|
62
|
+
// Remove if already exists
|
|
63
|
+
if (this.cache.has(key)) {
|
|
64
|
+
this.accessOrder = this.accessOrder.filter(k => k !== key);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Evict if at capacity
|
|
68
|
+
if (this.cache.size >= this.maxSize) {
|
|
69
|
+
const oldestKey = this.accessOrder.shift();
|
|
70
|
+
this.cache.delete(oldestKey);
|
|
71
|
+
this.evictions++;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add new entry
|
|
75
|
+
this.cache.set(key, {
|
|
76
|
+
value,
|
|
77
|
+
expiry: Date.now() + (ttl || this.ttl)
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
this.accessOrder.push(key);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if key exists
|
|
85
|
+
*/
|
|
86
|
+
has(key) {
|
|
87
|
+
return this.get(key) !== null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Delete entry
|
|
92
|
+
*/
|
|
93
|
+
delete(key) {
|
|
94
|
+
this.cache.delete(key);
|
|
95
|
+
this.accessOrder = this.accessOrder.filter(k => k !== key);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Clear cache
|
|
100
|
+
*/
|
|
101
|
+
clear() {
|
|
102
|
+
this.cache.clear();
|
|
103
|
+
this.accessOrder = [];
|
|
104
|
+
this.hits = 0;
|
|
105
|
+
this.misses = 0;
|
|
106
|
+
this.evictions = 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get cache statistics
|
|
111
|
+
*/
|
|
112
|
+
getStats() {
|
|
113
|
+
const total = this.hits + this.misses;
|
|
114
|
+
const hitRate = total > 0 ? (this.hits / total * 100).toFixed(2) : 0;
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
size: this.cache.size,
|
|
118
|
+
maxSize: this.maxSize,
|
|
119
|
+
hits: this.hits,
|
|
120
|
+
misses: this.misses,
|
|
121
|
+
evictions: this.evictions,
|
|
122
|
+
hitRate: `${hitRate}%`
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* MasterController Cache Manager
|
|
129
|
+
*/
|
|
130
|
+
class MasterCache {
|
|
131
|
+
constructor(options = {}) {
|
|
132
|
+
// Event manifest cache
|
|
133
|
+
this.manifestCache = new LRUCache({
|
|
134
|
+
maxSize: options.manifestCacheSize || 50,
|
|
135
|
+
ttl: options.manifestTTL || 3600000 // 1 hour
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Component render cache
|
|
139
|
+
this.renderCache = new LRUCache({
|
|
140
|
+
maxSize: options.renderCacheSize || 200,
|
|
141
|
+
ttl: options.renderTTL || 300000 // 5 minutes
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Template cache
|
|
145
|
+
this.templateCache = new LRUCache({
|
|
146
|
+
maxSize: options.templateCacheSize || 100,
|
|
147
|
+
ttl: options.templateTTL || 3600000 // 1 hour
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Module cache (for require/import)
|
|
151
|
+
this.moduleCache = new Map();
|
|
152
|
+
|
|
153
|
+
// Enabled flag
|
|
154
|
+
this.enabled = options.enabled !== false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Cache event manifest
|
|
159
|
+
*/
|
|
160
|
+
cacheManifest(componentName, manifest) {
|
|
161
|
+
if (!this.enabled) return;
|
|
162
|
+
|
|
163
|
+
const key = `manifest:${componentName}`;
|
|
164
|
+
this.manifestCache.set(key, manifest);
|
|
165
|
+
|
|
166
|
+
logger.debug({
|
|
167
|
+
code: 'MC_CACHE_MANIFEST',
|
|
168
|
+
message: `Cached manifest for ${componentName}`,
|
|
169
|
+
size: JSON.stringify(manifest).length
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get cached event manifest
|
|
175
|
+
*/
|
|
176
|
+
getManifest(componentName) {
|
|
177
|
+
if (!this.enabled) return null;
|
|
178
|
+
|
|
179
|
+
const key = `manifest:${componentName}`;
|
|
180
|
+
return this.manifestCache.get(key);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Cache component render output
|
|
185
|
+
*/
|
|
186
|
+
cacheRender(componentName, props, html) {
|
|
187
|
+
if (!this.enabled) return;
|
|
188
|
+
|
|
189
|
+
// Create cache key from component name and props
|
|
190
|
+
const propsKey = JSON.stringify(props || {});
|
|
191
|
+
const key = `render:${componentName}:${this.hashString(propsKey)}`;
|
|
192
|
+
|
|
193
|
+
this.renderCache.set(key, html);
|
|
194
|
+
|
|
195
|
+
logger.debug({
|
|
196
|
+
code: 'MC_CACHE_RENDER',
|
|
197
|
+
message: `Cached render for ${componentName}`,
|
|
198
|
+
size: html.length
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get cached component render
|
|
204
|
+
*/
|
|
205
|
+
getCachedRender(componentName, props) {
|
|
206
|
+
if (!this.enabled) return null;
|
|
207
|
+
|
|
208
|
+
const propsKey = JSON.stringify(props || {});
|
|
209
|
+
const key = `render:${componentName}:${this.hashString(propsKey)}`;
|
|
210
|
+
|
|
211
|
+
return this.renderCache.get(key);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Cache template
|
|
216
|
+
*/
|
|
217
|
+
cacheTemplate(templatePath, compiled) {
|
|
218
|
+
if (!this.enabled) return;
|
|
219
|
+
|
|
220
|
+
const key = `template:${templatePath}`;
|
|
221
|
+
this.templateCache.set(key, compiled);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get cached template
|
|
226
|
+
*/
|
|
227
|
+
getTemplate(templatePath) {
|
|
228
|
+
if (!this.enabled) return null;
|
|
229
|
+
|
|
230
|
+
const key = `template:${templatePath}`;
|
|
231
|
+
return this.templateCache.get(key);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Cache module (require/import result)
|
|
236
|
+
*/
|
|
237
|
+
cacheModule(modulePath, exports) {
|
|
238
|
+
if (!this.enabled) return;
|
|
239
|
+
|
|
240
|
+
this.moduleCache.set(modulePath, exports);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get cached module
|
|
245
|
+
*/
|
|
246
|
+
getModule(modulePath) {
|
|
247
|
+
if (!this.enabled) return null;
|
|
248
|
+
|
|
249
|
+
return this.moduleCache.get(modulePath);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Invalidate cache for component
|
|
254
|
+
*/
|
|
255
|
+
invalidateComponent(componentName) {
|
|
256
|
+
// Clear manifest
|
|
257
|
+
const manifestKey = `manifest:${componentName}`;
|
|
258
|
+
this.manifestCache.delete(manifestKey);
|
|
259
|
+
|
|
260
|
+
// Clear all renders for this component
|
|
261
|
+
// (We'd need to track which keys belong to which components for this)
|
|
262
|
+
// For now, just clear the entire render cache
|
|
263
|
+
this.renderCache.clear();
|
|
264
|
+
|
|
265
|
+
logger.info({
|
|
266
|
+
code: 'MC_CACHE_INVALIDATE',
|
|
267
|
+
message: `Cache invalidated for ${componentName}`
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Clear all caches
|
|
273
|
+
*/
|
|
274
|
+
clearAll() {
|
|
275
|
+
this.manifestCache.clear();
|
|
276
|
+
this.renderCache.clear();
|
|
277
|
+
this.templateCache.clear();
|
|
278
|
+
this.moduleCache.clear();
|
|
279
|
+
|
|
280
|
+
logger.info({
|
|
281
|
+
code: 'MC_CACHE_CLEAR',
|
|
282
|
+
message: 'All caches cleared'
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get cache statistics
|
|
288
|
+
*/
|
|
289
|
+
getStats() {
|
|
290
|
+
return {
|
|
291
|
+
manifest: this.manifestCache.getStats(),
|
|
292
|
+
render: this.renderCache.getStats(),
|
|
293
|
+
template: this.templateCache.getStats(),
|
|
294
|
+
module: {
|
|
295
|
+
size: this.moduleCache.size
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Log cache statistics
|
|
302
|
+
*/
|
|
303
|
+
logStats() {
|
|
304
|
+
const stats = this.getStats();
|
|
305
|
+
|
|
306
|
+
console.log('\n═══════════════════════════════════════════════════');
|
|
307
|
+
console.log('📊 MasterController Cache Statistics');
|
|
308
|
+
console.log('═══════════════════════════════════════════════════');
|
|
309
|
+
|
|
310
|
+
console.log('\nManifest Cache:');
|
|
311
|
+
console.log(` Size: ${stats.manifest.size}/${stats.manifest.maxSize}`);
|
|
312
|
+
console.log(` Hits: ${stats.manifest.hits}`);
|
|
313
|
+
console.log(` Misses: ${stats.manifest.misses}`);
|
|
314
|
+
console.log(` Hit Rate: ${stats.manifest.hitRate}`);
|
|
315
|
+
console.log(` Evictions: ${stats.manifest.evictions}`);
|
|
316
|
+
|
|
317
|
+
console.log('\nRender Cache:');
|
|
318
|
+
console.log(` Size: ${stats.render.size}/${stats.render.maxSize}`);
|
|
319
|
+
console.log(` Hits: ${stats.render.hits}`);
|
|
320
|
+
console.log(` Misses: ${stats.render.misses}`);
|
|
321
|
+
console.log(` Hit Rate: ${stats.render.hitRate}`);
|
|
322
|
+
console.log(` Evictions: ${stats.render.evictions}`);
|
|
323
|
+
|
|
324
|
+
console.log('\nTemplate Cache:');
|
|
325
|
+
console.log(` Size: ${stats.template.size}/${stats.template.maxSize}`);
|
|
326
|
+
console.log(` Hits: ${stats.template.hits}`);
|
|
327
|
+
console.log(` Misses: ${stats.template.misses}`);
|
|
328
|
+
console.log(` Hit Rate: ${stats.template.hitRate}`);
|
|
329
|
+
console.log(` Evictions: ${stats.template.evictions}`);
|
|
330
|
+
|
|
331
|
+
console.log('\nModule Cache:');
|
|
332
|
+
console.log(` Size: ${stats.module.size}`);
|
|
333
|
+
|
|
334
|
+
console.log('═══════════════════════════════════════════════════\n');
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Simple string hash function
|
|
339
|
+
*/
|
|
340
|
+
hashString(str) {
|
|
341
|
+
let hash = 0;
|
|
342
|
+
for (let i = 0; i < str.length; i++) {
|
|
343
|
+
const char = str.charCodeAt(i);
|
|
344
|
+
hash = ((hash << 5) - hash) + char;
|
|
345
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
346
|
+
}
|
|
347
|
+
return hash.toString(36);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Enable cache
|
|
352
|
+
*/
|
|
353
|
+
enable() {
|
|
354
|
+
this.enabled = true;
|
|
355
|
+
logger.info({
|
|
356
|
+
code: 'MC_CACHE_ENABLED',
|
|
357
|
+
message: 'Cache enabled'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Disable cache
|
|
363
|
+
*/
|
|
364
|
+
disable() {
|
|
365
|
+
this.enabled = false;
|
|
366
|
+
logger.info({
|
|
367
|
+
code: 'MC_CACHE_DISABLED',
|
|
368
|
+
message: 'Cache disabled'
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Create singleton instance
|
|
374
|
+
const cache = new MasterCache({
|
|
375
|
+
manifestCacheSize: 50,
|
|
376
|
+
renderCacheSize: 200,
|
|
377
|
+
templateCacheSize: 100,
|
|
378
|
+
manifestTTL: 3600000, // 1 hour
|
|
379
|
+
renderTTL: 300000, // 5 minutes
|
|
380
|
+
templateTTL: 3600000, // 1 hour
|
|
381
|
+
enabled: process.env.NODE_ENV === 'production' || process.env.MC_CACHE_ENABLED === 'true'
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Auto-cleanup interval (every 5 minutes)
|
|
385
|
+
setInterval(() => {
|
|
386
|
+
// Force garbage collection of expired entries
|
|
387
|
+
const stats = cache.getStats();
|
|
388
|
+
|
|
389
|
+
logger.debug({
|
|
390
|
+
code: 'MC_CACHE_CLEANUP',
|
|
391
|
+
message: 'Cache cleanup running',
|
|
392
|
+
stats
|
|
393
|
+
});
|
|
394
|
+
}, 300000);
|
|
395
|
+
|
|
396
|
+
module.exports = {
|
|
397
|
+
MasterCache,
|
|
398
|
+
LRUCache,
|
|
399
|
+
cache
|
|
400
|
+
};
|
package/MasterControl.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// MasterControl - by Alexander rich
|
|
2
|
-
// version 1.0.
|
|
2
|
+
// version 1.0.248
|
|
3
3
|
|
|
4
4
|
var url = require('url');
|
|
5
5
|
var fileserver = require('fs');
|
|
@@ -11,6 +11,47 @@ var url = require('url');
|
|
|
11
11
|
var path = require('path');
|
|
12
12
|
var globSearch = require("glob");
|
|
13
13
|
|
|
14
|
+
// Enhanced error handling - setup global handlers
|
|
15
|
+
const { setupGlobalErrorHandlers } = require('./MasterErrorMiddleware');
|
|
16
|
+
const { logger } = require('./MasterErrorLogger');
|
|
17
|
+
|
|
18
|
+
// Security - Initialize security features
|
|
19
|
+
const { security, securityHeaders } = require('./SecurityMiddleware');
|
|
20
|
+
const { csp } = require('./CSPConfig');
|
|
21
|
+
const { session } = require('./SessionSecurity');
|
|
22
|
+
|
|
23
|
+
// Initialize global error handling
|
|
24
|
+
setupGlobalErrorHandlers();
|
|
25
|
+
|
|
26
|
+
// Log framework start
|
|
27
|
+
logger.info({
|
|
28
|
+
code: 'MC_INFO_FRAMEWORK_START',
|
|
29
|
+
message: 'MasterController framework initializing',
|
|
30
|
+
context: {
|
|
31
|
+
version: '1.0.247',
|
|
32
|
+
nodeVersion: process.version,
|
|
33
|
+
platform: process.platform,
|
|
34
|
+
env: process.env.NODE_ENV || 'development'
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Log security status
|
|
39
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
40
|
+
logger.info({
|
|
41
|
+
code: 'MC_INFO_SECURITY_INITIALIZED',
|
|
42
|
+
message: 'Security features initialized',
|
|
43
|
+
context: {
|
|
44
|
+
environment: isProduction ? 'production' : 'development',
|
|
45
|
+
features: {
|
|
46
|
+
securityHeaders: true,
|
|
47
|
+
csp: csp.enabled,
|
|
48
|
+
csrf: security.csrfEnabled,
|
|
49
|
+
rateLimit: security.rateLimitEnabled,
|
|
50
|
+
sessionSecurity: true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
14
55
|
|
|
15
56
|
class MasterControl {
|
|
16
57
|
controllerList = {}
|
|
@@ -156,7 +197,7 @@ class MasterControl {
|
|
|
156
197
|
if(files && files.length > 0){
|
|
157
198
|
require(files[0]);
|
|
158
199
|
}else{
|
|
159
|
-
|
|
200
|
+
this.error.log(`Cannot find config file under ${rootFolderLocation}`, "error");
|
|
160
201
|
}
|
|
161
202
|
var routeFiles = globSearch.sync("**/*routes.js", { cwd: rootFolderLocation, absolute: true });
|
|
162
203
|
var route = routeFiles && routeFiles.length > 0 ? routeFiles[0] : null;
|
|
@@ -168,7 +209,7 @@ class MasterControl {
|
|
|
168
209
|
if(route){
|
|
169
210
|
require(route);
|
|
170
211
|
}else{
|
|
171
|
-
|
|
212
|
+
this.error.log(`Cannot find routes file under ${rootFolderLocation}`, "error");
|
|
172
213
|
}
|
|
173
214
|
}
|
|
174
215
|
|
|
@@ -203,6 +244,26 @@ class MasterControl {
|
|
|
203
244
|
setupServer(type, credentials ){
|
|
204
245
|
try {
|
|
205
246
|
var $that = this;
|
|
247
|
+
// Auto-load internal master tools so services (request, error, router, etc.) are available
|
|
248
|
+
// before user config initializes them.
|
|
249
|
+
try {
|
|
250
|
+
$that.addInternalTools([
|
|
251
|
+
'MasterAction',
|
|
252
|
+
'MasterActionFilters',
|
|
253
|
+
'MasterRouter',
|
|
254
|
+
'MasterRequest',
|
|
255
|
+
'MasterError',
|
|
256
|
+
'MasterCors',
|
|
257
|
+
'MasterSession',
|
|
258
|
+
'MasterSocket',
|
|
259
|
+
'MasterHtml',
|
|
260
|
+
'MasterTemplate',
|
|
261
|
+
'MasterTools',
|
|
262
|
+
'TemplateOverwrite'
|
|
263
|
+
]);
|
|
264
|
+
} catch (e) {
|
|
265
|
+
console.error('[MasterControl] Failed to load internal tools:', e && e.message);
|
|
266
|
+
}
|
|
206
267
|
if(type === "http"){
|
|
207
268
|
$that.serverProtocol = "http";
|
|
208
269
|
return http.createServer(async function(req, res) {
|
|
@@ -399,16 +460,25 @@ class MasterControl {
|
|
|
399
460
|
return;
|
|
400
461
|
}
|
|
401
462
|
|
|
463
|
+
// Apply CORS headers to ALL non-OPTIONS requests
|
|
464
|
+
try {
|
|
465
|
+
if (this.cors && typeof this.cors.load === 'function') {
|
|
466
|
+
this.cors.load({ request: req, response: res });
|
|
467
|
+
}
|
|
468
|
+
} catch (e) {
|
|
469
|
+
console.warn('CORS load failed for non-OPTIONS request:', e.message);
|
|
470
|
+
}
|
|
471
|
+
|
|
402
472
|
// parse URL
|
|
403
473
|
const parsedUrl = url.parse(req.url);
|
|
404
474
|
// extract URL path
|
|
405
475
|
let pathname = `.${parsedUrl.pathname}`;
|
|
406
|
-
|
|
476
|
+
|
|
407
477
|
// based on the URL path, extract the file extension. e.g. .js, .doc, ...
|
|
408
478
|
const ext = path.parse(pathname).ext;
|
|
409
|
-
|
|
479
|
+
|
|
410
480
|
// handle simple preflight configuration - might need a complex approch for all scenarios
|
|
411
|
-
|
|
481
|
+
|
|
412
482
|
|
|
413
483
|
// if extension exist then its a file.
|
|
414
484
|
if(ext === ""){
|
|
@@ -480,7 +550,7 @@ class MasterControl {
|
|
|
480
550
|
if(files && files.length > 0){
|
|
481
551
|
require(files[0]);
|
|
482
552
|
}else{
|
|
483
|
-
|
|
553
|
+
this.error.log(`Cannot find routes file under ${rootFolderLocation}`, "error");
|
|
484
554
|
}
|
|
485
555
|
}
|
|
486
556
|
|