mastercontroller 1.2.12 → 1.2.14

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.
@@ -0,0 +1,400 @@
1
+ // version 1.0.1
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('../error/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
+ };
@@ -0,0 +1,188 @@
1
+ // version 1.0.1
2
+ // MasterController Memory Monitor - Memory Leak Detection
3
+
4
+ /**
5
+ * Memory monitor for detecting memory leaks
6
+ * - Heap usage tracking
7
+ * - Memory leak detection
8
+ * - Garbage collection monitoring
9
+ * - Memory alerts
10
+ */
11
+
12
+ const { logger } = require('../error/MasterErrorLogger');
13
+
14
+ class MasterMemoryMonitor {
15
+ constructor(options = {}) {
16
+ this.enabled = options.enabled !== false;
17
+ this.checkInterval = options.checkInterval || 30000; // 30 seconds
18
+ this.leakThreshold = options.leakThreshold || 50; // 50MB growth
19
+ this.alertThreshold = options.alertThreshold || 500; // 500MB
20
+
21
+ this.snapshots = [];
22
+ this.maxSnapshots = 100;
23
+ this.intervalId = null;
24
+ }
25
+
26
+ /**
27
+ * Start monitoring
28
+ */
29
+ start() {
30
+ if (!this.enabled || this.intervalId) return;
31
+
32
+ this.takeSnapshot();
33
+
34
+ this.intervalId = setInterval(() => {
35
+ this.takeSnapshot();
36
+ this.checkForLeaks();
37
+ }, this.checkInterval);
38
+
39
+ logger.info({
40
+ code: 'MC_MEMORY_MONITOR_START',
41
+ message: 'Memory monitoring started',
42
+ interval: `${this.checkInterval}ms`
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Stop monitoring
48
+ */
49
+ stop() {
50
+ if (this.intervalId) {
51
+ clearInterval(this.intervalId);
52
+ this.intervalId = null;
53
+
54
+ logger.info({
55
+ code: 'MC_MEMORY_MONITOR_STOP',
56
+ message: 'Memory monitoring stopped'
57
+ });
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Take memory snapshot
63
+ */
64
+ takeSnapshot() {
65
+ const usage = process.memoryUsage();
66
+
67
+ const snapshot = {
68
+ timestamp: Date.now(),
69
+ heapUsed: usage.heapUsed,
70
+ heapTotal: usage.heapTotal,
71
+ external: usage.external,
72
+ rss: usage.rss
73
+ };
74
+
75
+ this.snapshots.push(snapshot);
76
+
77
+ // Keep only last N snapshots
78
+ if (this.snapshots.length > this.maxSnapshots) {
79
+ this.snapshots.shift();
80
+ }
81
+
82
+ // Alert if memory usage is high
83
+ const heapUsedMB = usage.heapUsed / 1024 / 1024;
84
+ if (heapUsedMB > this.alertThreshold) {
85
+ logger.warn({
86
+ code: 'MC_MEMORY_HIGH',
87
+ message: 'High memory usage detected',
88
+ heapUsed: `${heapUsedMB.toFixed(2)} MB`,
89
+ threshold: `${this.alertThreshold} MB`
90
+ });
91
+ }
92
+
93
+ return snapshot;
94
+ }
95
+
96
+ /**
97
+ * Check for memory leaks
98
+ */
99
+ checkForLeaks() {
100
+ if (this.snapshots.length < 10) return;
101
+
102
+ // Compare first 5 and last 5 snapshots
103
+ const oldSnapshots = this.snapshots.slice(0, 5);
104
+ const newSnapshots = this.snapshots.slice(-5);
105
+
106
+ const oldAvg = oldSnapshots.reduce((sum, s) => sum + s.heapUsed, 0) / oldSnapshots.length;
107
+ const newAvg = newSnapshots.reduce((sum, s) => sum + s.heapUsed, 0) / newSnapshots.length;
108
+
109
+ const growthBytes = newAvg - oldAvg;
110
+ const growthMB = growthBytes / 1024 / 1024;
111
+
112
+ if (growthMB > this.leakThreshold) {
113
+ logger.warn({
114
+ code: 'MC_MEMORY_LEAK_DETECTED',
115
+ message: 'Potential memory leak detected',
116
+ growth: `${growthMB.toFixed(2)} MB`,
117
+ oldAvg: `${(oldAvg / 1024 / 1024).toFixed(2)} MB`,
118
+ newAvg: `${(newAvg / 1024 / 1024).toFixed(2)} MB`,
119
+ suggestion: 'Review component lifecycle and event listener cleanup'
120
+ });
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Get current memory usage
126
+ */
127
+ getCurrentUsage() {
128
+ const usage = process.memoryUsage();
129
+
130
+ return {
131
+ heapUsed: `${(usage.heapUsed / 1024 / 1024).toFixed(2)} MB`,
132
+ heapTotal: `${(usage.heapTotal / 1024 / 1024).toFixed(2)} MB`,
133
+ external: `${(usage.external / 1024 / 1024).toFixed(2)} MB`,
134
+ rss: `${(usage.rss / 1024 / 1024).toFixed(2)} MB`
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Print memory report
140
+ */
141
+ printReport() {
142
+ if (this.snapshots.length === 0) {
143
+ console.log('No memory snapshots available');
144
+ return;
145
+ }
146
+
147
+ const current = this.snapshots[this.snapshots.length - 1];
148
+ const first = this.snapshots[0];
149
+
150
+ const growth = current.heapUsed - first.heapUsed;
151
+ const growthPercent = (growth / first.heapUsed * 100).toFixed(2);
152
+
153
+ console.log('\n═══════════════════════════════════════════════════');
154
+ console.log('💾 MasterController Memory Report');
155
+ console.log('═══════════════════════════════════════════════════');
156
+
157
+ console.log('\nCurrent Usage:');
158
+ console.log(` Heap Used: ${(current.heapUsed / 1024 / 1024).toFixed(2)} MB`);
159
+ console.log(` Heap Total: ${(current.heapTotal / 1024 / 1024).toFixed(2)} MB`);
160
+ console.log(` External: ${(current.external / 1024 / 1024).toFixed(2)} MB`);
161
+ console.log(` RSS: ${(current.rss / 1024 / 1024).toFixed(2)} MB`);
162
+
163
+ console.log('\nMemory Growth:');
164
+ console.log(` Initial: ${(first.heapUsed / 1024 / 1024).toFixed(2)} MB`);
165
+ console.log(` Current: ${(current.heapUsed / 1024 / 1024).toFixed(2)} MB`);
166
+ console.log(` Growth: ${(growth / 1024 / 1024).toFixed(2)} MB (${growthPercent}%)`);
167
+
168
+ console.log(`\nSnapshots: ${this.snapshots.length}`);
169
+ console.log(`Duration: ${((current.timestamp - first.timestamp) / 1000 / 60).toFixed(2)} minutes`);
170
+
171
+ console.log('═══════════════════════════════════════════════════\n');
172
+ }
173
+ }
174
+
175
+ // Create singleton
176
+ const memoryMonitor = new MasterMemoryMonitor({
177
+ enabled: process.env.MC_MEMORY_MONITOR === 'true',
178
+ checkInterval: 30000,
179
+ leakThreshold: 50,
180
+ alertThreshold: 500
181
+ });
182
+
183
+ // Auto-start in development
184
+ if (process.env.NODE_ENV === 'development') {
185
+ memoryMonitor.start();
186
+ }
187
+
188
+ module.exports = { MasterMemoryMonitor, memoryMonitor };