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,409 @@
1
+ // version 1.0.1
2
+ // MasterController Performance Profiler - Component and Request Profiling
3
+
4
+ /**
5
+ * Performance profiler for MasterController
6
+ * - Component render time tracking
7
+ * - Slow component detection
8
+ * - Request profiling
9
+ * - Performance bottleneck identification
10
+ * - Detailed performance reports
11
+ */
12
+
13
+ const { logger } = require('../error/MasterErrorLogger');
14
+
15
+ class MasterProfiler {
16
+ constructor(options = {}) {
17
+ this.enabled = options.enabled !== false;
18
+ this.slowThreshold = options.slowThreshold || 100; // 100ms
19
+ this.verySlowThreshold = options.verySlowThreshold || 500; // 500ms
20
+
21
+ // Performance data
22
+ this.componentMetrics = new Map();
23
+ this.requestMetrics = [];
24
+ this.currentRequest = null;
25
+
26
+ // Marks
27
+ this.marks = new Map();
28
+
29
+ // Statistics
30
+ this.totalComponents = 0;
31
+ this.slowComponents = 0;
32
+ this.verySlowComponents = 0;
33
+ }
34
+
35
+ /**
36
+ * Start profiling a component render
37
+ */
38
+ startComponentRender(componentName, props = {}) {
39
+ if (!this.enabled) return null;
40
+
41
+ const id = `${componentName}-${Date.now()}-${Math.random()}`;
42
+
43
+ this.mark(`${id}:start`);
44
+
45
+ return {
46
+ id,
47
+ componentName,
48
+ props,
49
+ startTime: Date.now()
50
+ };
51
+ }
52
+
53
+ /**
54
+ * End profiling a component render
55
+ */
56
+ endComponentRender(profile) {
57
+ if (!this.enabled || !profile) return;
58
+
59
+ this.mark(`${profile.id}:end`);
60
+
61
+ const duration = this.measure(
62
+ `${profile.id}:render`,
63
+ `${profile.id}:start`,
64
+ `${profile.id}:end`
65
+ );
66
+
67
+ // Store metrics
68
+ if (!this.componentMetrics.has(profile.componentName)) {
69
+ this.componentMetrics.set(profile.componentName, {
70
+ componentName: profile.componentName,
71
+ renders: [],
72
+ totalRenders: 0,
73
+ totalTime: 0,
74
+ avgTime: 0,
75
+ minTime: Infinity,
76
+ maxTime: 0,
77
+ slowRenders: 0,
78
+ verySlowRenders: 0
79
+ });
80
+ }
81
+
82
+ const metrics = this.componentMetrics.get(profile.componentName);
83
+ metrics.renders.push({
84
+ duration,
85
+ timestamp: profile.startTime,
86
+ props: profile.props
87
+ });
88
+
89
+ metrics.totalRenders++;
90
+ metrics.totalTime += duration;
91
+ metrics.avgTime = metrics.totalTime / metrics.totalRenders;
92
+ metrics.minTime = Math.min(metrics.minTime, duration);
93
+ metrics.maxTime = Math.max(metrics.maxTime, duration);
94
+
95
+ if (duration > this.slowThreshold) {
96
+ metrics.slowRenders++;
97
+ this.slowComponents++;
98
+
99
+ if (duration > this.verySlowThreshold) {
100
+ metrics.verySlowRenders++;
101
+ this.verySlowComponents++;
102
+
103
+ logger.warn({
104
+ code: 'MC_PERF_VERY_SLOW_COMPONENT',
105
+ message: `Very slow component render detected: ${profile.componentName}`,
106
+ duration: `${duration}ms`,
107
+ threshold: `${this.verySlowThreshold}ms`
108
+ });
109
+ }
110
+ }
111
+
112
+ this.totalComponents++;
113
+
114
+ // Keep only last 100 renders per component
115
+ if (metrics.renders.length > 100) {
116
+ metrics.renders.shift();
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Start profiling a request
122
+ */
123
+ startRequest(path, method = 'GET') {
124
+ if (!this.enabled) return null;
125
+
126
+ const id = `request-${Date.now()}-${Math.random()}`;
127
+
128
+ this.mark(`${id}:start`);
129
+
130
+ this.currentRequest = {
131
+ id,
132
+ path,
133
+ method,
134
+ startTime: Date.now(),
135
+ components: []
136
+ };
137
+
138
+ return this.currentRequest;
139
+ }
140
+
141
+ /**
142
+ * End profiling a request
143
+ */
144
+ endRequest(requestProfile) {
145
+ if (!this.enabled || !requestProfile) return;
146
+
147
+ this.mark(`${requestProfile.id}:end`);
148
+
149
+ const duration = this.measure(
150
+ `${requestProfile.id}:request`,
151
+ `${requestProfile.id}:start`,
152
+ `${requestProfile.id}:end`
153
+ );
154
+
155
+ requestProfile.duration = duration;
156
+ requestProfile.endTime = Date.now();
157
+
158
+ this.requestMetrics.push(requestProfile);
159
+
160
+ // Keep only last 1000 requests
161
+ if (this.requestMetrics.length > 1000) {
162
+ this.requestMetrics.shift();
163
+ }
164
+
165
+ // Log slow requests
166
+ if (duration > 1000) {
167
+ logger.warn({
168
+ code: 'MC_PERF_SLOW_REQUEST',
169
+ message: `Slow request detected: ${requestProfile.method} ${requestProfile.path}`,
170
+ duration: `${duration}ms`
171
+ });
172
+ }
173
+
174
+ this.currentRequest = null;
175
+ }
176
+
177
+ /**
178
+ * Create a performance mark
179
+ */
180
+ mark(name) {
181
+ if (!this.enabled) return;
182
+
183
+ this.marks.set(name, {
184
+ name,
185
+ timestamp: Date.now()
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Measure duration between two marks
191
+ */
192
+ measure(name, startMark, endMark) {
193
+ if (!this.enabled) return 0;
194
+
195
+ const start = this.marks.get(startMark);
196
+ const end = this.marks.get(endMark);
197
+
198
+ if (!start || !end) {
199
+ return 0;
200
+ }
201
+
202
+ return end.timestamp - start.timestamp;
203
+ }
204
+
205
+ /**
206
+ * Get component performance metrics
207
+ */
208
+ getComponentMetrics(componentName = null) {
209
+ if (componentName) {
210
+ return this.componentMetrics.get(componentName) || null;
211
+ }
212
+
213
+ return Array.from(this.componentMetrics.values());
214
+ }
215
+
216
+ /**
217
+ * Get request performance metrics
218
+ */
219
+ getRequestMetrics(limit = 100) {
220
+ return this.requestMetrics.slice(-limit);
221
+ }
222
+
223
+ /**
224
+ * Get slow components
225
+ */
226
+ getSlowComponents(threshold = null) {
227
+ threshold = threshold || this.slowThreshold;
228
+
229
+ return Array.from(this.componentMetrics.values())
230
+ .filter(m => m.avgTime > threshold)
231
+ .sort((a, b) => b.avgTime - a.avgTime);
232
+ }
233
+
234
+ /**
235
+ * Get slow requests
236
+ */
237
+ getSlowRequests(threshold = 1000, limit = 100) {
238
+ return this.requestMetrics
239
+ .filter(r => r.duration > threshold)
240
+ .slice(-limit)
241
+ .sort((a, b) => b.duration - a.duration);
242
+ }
243
+
244
+ /**
245
+ * Generate performance report
246
+ */
247
+ generateReport() {
248
+ const components = this.getComponentMetrics();
249
+ const slowComponents = this.getSlowComponents();
250
+ const requests = this.getRequestMetrics();
251
+ const slowRequests = this.getSlowRequests();
252
+
253
+ // Calculate statistics
254
+ const totalRenderTime = components.reduce((sum, c) => sum + c.totalTime, 0);
255
+ const avgRenderTime = components.length > 0
256
+ ? totalRenderTime / components.reduce((sum, c) => sum + c.totalRenders, 0)
257
+ : 0;
258
+
259
+ const totalRequestTime = requests.reduce((sum, r) => sum + r.duration, 0);
260
+ const avgRequestTime = requests.length > 0 ? totalRequestTime / requests.length : 0;
261
+
262
+ return {
263
+ summary: {
264
+ totalComponents: this.totalComponents,
265
+ uniqueComponents: components.length,
266
+ slowComponents: this.slowComponents,
267
+ verySlowComponents: this.verySlowComponents,
268
+ totalRequests: requests.length,
269
+ slowRequests: slowRequests.length,
270
+ avgRenderTime: Math.round(avgRenderTime),
271
+ avgRequestTime: Math.round(avgRequestTime)
272
+ },
273
+ components: {
274
+ all: components,
275
+ slow: slowComponents.slice(0, 10)
276
+ },
277
+ requests: {
278
+ recent: requests.slice(-10),
279
+ slow: slowRequests.slice(0, 10)
280
+ }
281
+ };
282
+ }
283
+
284
+ /**
285
+ * Print performance report
286
+ */
287
+ printReport() {
288
+ const report = this.generateReport();
289
+
290
+ console.log('\n═══════════════════════════════════════════════════');
291
+ console.log('⚡ MasterController Performance Report');
292
+ console.log('═══════════════════════════════════════════════════');
293
+
294
+ console.log('\n📊 Summary:');
295
+ console.log(` Total Component Renders: ${report.summary.totalComponents}`);
296
+ console.log(` Unique Components: ${report.summary.uniqueComponents}`);
297
+ console.log(` Slow Components (>${this.slowThreshold}ms): ${report.summary.slowComponents}`);
298
+ console.log(` Very Slow Components (>${this.verySlowThreshold}ms): ${report.summary.verySlowComponents}`);
299
+ console.log(` Average Render Time: ${report.summary.avgRenderTime}ms`);
300
+ console.log(` Total Requests: ${report.summary.totalRequests}`);
301
+ console.log(` Slow Requests (>1000ms): ${report.summary.slowRequests}`);
302
+ console.log(` Average Request Time: ${report.summary.avgRequestTime}ms`);
303
+
304
+ if (report.components.slow.length > 0) {
305
+ console.log('\n🐌 Slowest Components:');
306
+ report.components.slow.forEach((comp, i) => {
307
+ console.log(` ${i + 1}. ${comp.componentName}`);
308
+ console.log(` Avg: ${Math.round(comp.avgTime)}ms | Max: ${Math.round(comp.maxTime)}ms | Renders: ${comp.totalRenders}`);
309
+ console.log(` Slow Renders: ${comp.slowRenders} | Very Slow: ${comp.verySlowRenders}`);
310
+ });
311
+ }
312
+
313
+ if (report.requests.slow.length > 0) {
314
+ console.log('\n🐌 Slowest Requests:');
315
+ report.requests.slow.forEach((req, i) => {
316
+ console.log(` ${i + 1}. ${req.method} ${req.path}`);
317
+ console.log(` Duration: ${Math.round(req.duration)}ms`);
318
+ });
319
+ }
320
+
321
+ console.log('\n💡 Recommendations:');
322
+ if (report.summary.verySlowComponents > 0) {
323
+ console.log(' ⚠️ Some components are very slow (>500ms)');
324
+ console.log(' - Consider code splitting');
325
+ console.log(' - Optimize expensive operations');
326
+ console.log(' - Use memoization for computed values');
327
+ }
328
+
329
+ if (report.summary.slowComponents > 10) {
330
+ console.log(' ⚠️ Many slow components detected');
331
+ console.log(' - Review component implementations');
332
+ console.log(' - Enable render caching');
333
+ console.log(' - Consider lazy loading');
334
+ }
335
+
336
+ if (report.summary.slowRequests > 5) {
337
+ console.log(' ⚠️ Multiple slow requests detected');
338
+ console.log(' - Review database queries');
339
+ console.log(' - Add caching');
340
+ console.log(' - Optimize expensive operations');
341
+ }
342
+
343
+ console.log('═══════════════════════════════════════════════════\n');
344
+
345
+ return report;
346
+ }
347
+
348
+ /**
349
+ * Reset profiler
350
+ */
351
+ reset() {
352
+ this.componentMetrics.clear();
353
+ this.requestMetrics = [];
354
+ this.marks.clear();
355
+ this.totalComponents = 0;
356
+ this.slowComponents = 0;
357
+ this.verySlowComponents = 0;
358
+ this.currentRequest = null;
359
+
360
+ logger.info({
361
+ code: 'MC_PERF_RESET',
362
+ message: 'Profiler reset'
363
+ });
364
+ }
365
+
366
+ /**
367
+ * Enable profiler
368
+ */
369
+ enable() {
370
+ this.enabled = true;
371
+ logger.info({
372
+ code: 'MC_PERF_ENABLED',
373
+ message: 'Profiler enabled'
374
+ });
375
+ }
376
+
377
+ /**
378
+ * Disable profiler
379
+ */
380
+ disable() {
381
+ this.enabled = false;
382
+ logger.info({
383
+ code: 'MC_PERF_DISABLED',
384
+ message: 'Profiler disabled'
385
+ });
386
+ }
387
+ }
388
+
389
+ // Create singleton instance
390
+ const profiler = new MasterProfiler({
391
+ enabled: process.env.NODE_ENV === 'development' || process.env.MC_PROFILER_ENABLED === 'true',
392
+ slowThreshold: parseInt(process.env.MC_SLOW_THRESHOLD) || 100,
393
+ verySlowThreshold: parseInt(process.env.MC_VERY_SLOW_THRESHOLD) || 500
394
+ });
395
+
396
+ // Auto-print report every 5 minutes in development
397
+ if (process.env.NODE_ENV === 'development') {
398
+ setInterval(() => {
399
+ const report = profiler.generateReport();
400
+ if (report.summary.totalComponents > 0) {
401
+ profiler.printReport();
402
+ }
403
+ }, 300000); // 5 minutes
404
+ }
405
+
406
+ module.exports = {
407
+ MasterProfiler,
408
+ profiler
409
+ };
@@ -0,0 +1,233 @@
1
+ /**
2
+ * PerformanceMonitor - Track and report SSR performance metrics
3
+ * Version: 1.0.1
4
+ */
5
+
6
+ const { MasterControllerError } = require('../error/MasterErrorHandler');
7
+
8
+ const isDevelopment = process.env.NODE_ENV !== 'production' && process.env.master === 'development';
9
+
10
+ // Performance thresholds (milliseconds)
11
+ const THRESHOLDS = {
12
+ SLOW_RENDER: 100, // Warn if component takes >100ms to render
13
+ VERY_SLOW_RENDER: 500, // Error if component takes >500ms
14
+ TOTAL_SSR: 3000 // Warn if total SSR time exceeds 3s
15
+ };
16
+
17
+ class PerformanceMonitor {
18
+ constructor() {
19
+ this.metrics = {
20
+ totalStartTime: null,
21
+ totalEndTime: null,
22
+ components: new Map(),
23
+ slowComponents: [],
24
+ totalRenderTime: 0,
25
+ componentCount: 0
26
+ };
27
+
28
+ this.enabled = isDevelopment || process.env.MC_PERF_MONITOR === 'true';
29
+ }
30
+
31
+ /**
32
+ * Start monitoring SSR session
33
+ */
34
+ startSession() {
35
+ if (!this.enabled) return;
36
+ this.metrics.totalStartTime = Date.now();
37
+ this.metrics.components.clear();
38
+ this.metrics.slowComponents = [];
39
+ this.metrics.totalRenderTime = 0;
40
+ this.metrics.componentCount = 0;
41
+ }
42
+
43
+ /**
44
+ * Record component render time
45
+ */
46
+ recordComponent(componentName, renderTime, filePath = null) {
47
+ if (!this.enabled) return;
48
+
49
+ this.metrics.componentCount++;
50
+ this.metrics.totalRenderTime += renderTime;
51
+
52
+ // Store component metrics
53
+ if (!this.metrics.components.has(componentName)) {
54
+ this.metrics.components.set(componentName, {
55
+ name: componentName,
56
+ renderTime,
57
+ renderCount: 1,
58
+ filePath
59
+ });
60
+ } else {
61
+ const existing = this.metrics.components.get(componentName);
62
+ existing.renderTime += renderTime;
63
+ existing.renderCount++;
64
+ }
65
+
66
+ // Track slow components
67
+ if (renderTime > THRESHOLDS.SLOW_RENDER) {
68
+ this.metrics.slowComponents.push({
69
+ name: componentName,
70
+ renderTime,
71
+ filePath,
72
+ severity: renderTime > THRESHOLDS.VERY_SLOW_RENDER ? 'error' : 'warning'
73
+ });
74
+
75
+ // Warn immediately about slow renders in development
76
+ if (isDevelopment) {
77
+ const severity = renderTime > THRESHOLDS.VERY_SLOW_RENDER ? 'error' : 'warning';
78
+ const message = renderTime > THRESHOLDS.VERY_SLOW_RENDER
79
+ ? `Component rendering VERY slowly (${renderTime}ms > ${THRESHOLDS.VERY_SLOW_RENDER}ms threshold)`
80
+ : `Component rendering slowly (${renderTime}ms > ${THRESHOLDS.SLOW_RENDER}ms threshold)`;
81
+
82
+ const error = new MasterControllerError({
83
+ code: 'MC_ERR_SLOW_RENDER',
84
+ message,
85
+ component: componentName,
86
+ file: filePath,
87
+ details: this._getSuggestions(componentName, renderTime)
88
+ });
89
+
90
+ if (severity === 'error') {
91
+ console.error(error.format());
92
+ } else {
93
+ console.warn(error.format());
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ /**
100
+ * End monitoring session and generate report
101
+ */
102
+ endSession() {
103
+ if (!this.enabled) return null;
104
+
105
+ this.metrics.totalEndTime = Date.now();
106
+ const totalTime = this.metrics.totalEndTime - this.metrics.totalStartTime;
107
+
108
+ // Warn about slow total SSR time
109
+ if (totalTime > THRESHOLDS.TOTAL_SSR && isDevelopment) {
110
+ console.warn(
111
+ new MasterControllerError({
112
+ code: 'MC_ERR_SLOW_RENDER',
113
+ message: `Total SSR time exceeded threshold (${totalTime}ms > ${THRESHOLDS.TOTAL_SSR}ms)`,
114
+ details: `Rendered ${this.metrics.componentCount} components. Consider optimizing slow components or using lazy loading.`
115
+ }).format()
116
+ );
117
+ }
118
+
119
+ const report = this._generateReport(totalTime);
120
+
121
+ // Print report in development
122
+ if (isDevelopment) {
123
+ this._printReport(report);
124
+ }
125
+
126
+ return report;
127
+ }
128
+
129
+ /**
130
+ * Generate performance report
131
+ */
132
+ _generateReport(totalTime) {
133
+ // Sort components by render time
134
+ const sortedComponents = Array.from(this.metrics.components.values())
135
+ .sort((a, b) => b.renderTime - a.renderTime);
136
+
137
+ return {
138
+ totalTime,
139
+ componentCount: this.metrics.componentCount,
140
+ averageRenderTime: this.metrics.componentCount > 0
141
+ ? Math.round(this.metrics.totalRenderTime / this.metrics.componentCount)
142
+ : 0,
143
+ slowComponents: this.metrics.slowComponents,
144
+ topComponents: sortedComponents.slice(0, 10),
145
+ summary: {
146
+ fast: sortedComponents.filter(c => c.renderTime <= THRESHOLDS.SLOW_RENDER).length,
147
+ slow: sortedComponents.filter(c => c.renderTime > THRESHOLDS.SLOW_RENDER && c.renderTime <= THRESHOLDS.VERY_SLOW_RENDER).length,
148
+ verySlow: sortedComponents.filter(c => c.renderTime > THRESHOLDS.VERY_SLOW_RENDER).length
149
+ }
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Print formatted performance report
155
+ */
156
+ _printReport(report) {
157
+ console.log('\n' + '═'.repeat(80));
158
+ console.log('🚀 MasterController SSR Performance Report');
159
+ console.log('═'.repeat(80));
160
+ console.log(`Total SSR Time: ${report.totalTime}ms`);
161
+ console.log(`Components Rendered: ${report.componentCount}`);
162
+ console.log(`Average Render Time: ${report.averageRenderTime}ms`);
163
+ console.log(`\nPerformance Summary:`);
164
+ console.log(` ✅ Fast (<${THRESHOLDS.SLOW_RENDER}ms): ${report.summary.fast}`);
165
+ console.log(` ⚠️ Slow (${THRESHOLDS.SLOW_RENDER}-${THRESHOLDS.VERY_SLOW_RENDER}ms): ${report.summary.slow}`);
166
+ console.log(` ❌ Very Slow (>${THRESHOLDS.VERY_SLOW_RENDER}ms): ${report.summary.verySlow}`);
167
+
168
+ if (report.topComponents.length > 0) {
169
+ console.log(`\nTop ${Math.min(10, report.topComponents.length)} Slowest Components:`);
170
+ report.topComponents.forEach((comp, index) => {
171
+ const icon = comp.renderTime > THRESHOLDS.VERY_SLOW_RENDER ? '❌' :
172
+ comp.renderTime > THRESHOLDS.SLOW_RENDER ? '⚠️' : '✅';
173
+ console.log(` ${icon} ${index + 1}. ${comp.name}: ${comp.renderTime}ms (${comp.renderCount} render${comp.renderCount > 1 ? 's' : ''})`);
174
+ });
175
+ }
176
+
177
+ console.log('═'.repeat(80) + '\n');
178
+ }
179
+
180
+ /**
181
+ * Get optimization suggestions for slow components
182
+ */
183
+ _getSuggestions(componentName, renderTime) {
184
+ const suggestions = [
185
+ 'Reduce the amount of data rendered initially',
186
+ 'Use pagination or virtual scrolling for large lists',
187
+ 'Move expensive calculations to data fetching layer',
188
+ 'Consider lazy loading or code splitting',
189
+ 'Cache computed values',
190
+ 'Optimize database queries if data-fetching is involved'
191
+ ];
192
+
193
+ let details = `\nOptimization Suggestions:\n`;
194
+ suggestions.forEach((suggestion, index) => {
195
+ details += `${index + 1}. ${suggestion}\n`;
196
+ });
197
+
198
+ return details;
199
+ }
200
+
201
+ /**
202
+ * Get current metrics snapshot
203
+ */
204
+ getMetrics() {
205
+ return {
206
+ ...this.metrics,
207
+ currentTime: Date.now() - (this.metrics.totalStartTime || Date.now())
208
+ };
209
+ }
210
+
211
+ /**
212
+ * Reset metrics
213
+ */
214
+ reset() {
215
+ this.metrics = {
216
+ totalStartTime: null,
217
+ totalEndTime: null,
218
+ components: new Map(),
219
+ slowComponents: [],
220
+ totalRenderTime: 0,
221
+ componentCount: 0
222
+ };
223
+ }
224
+ }
225
+
226
+ // Singleton instance
227
+ const monitor = new PerformanceMonitor();
228
+
229
+ module.exports = {
230
+ PerformanceMonitor,
231
+ monitor,
232
+ THRESHOLDS
233
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "qs" : "^6.14.0",
4
4
  "formidable": "^3.5.4",
5
5
  "cookie": "^1.0.2",
6
- "winston": "^3.18.3",
6
+ "winston": "^3.17.0",
7
7
  "glob" :"^11.0.3"
8
8
  },
9
9
  "description": "A class library that makes using the Master Framework a breeze",
@@ -18,5 +18,5 @@
18
18
  "scripts": {
19
19
  "test": "echo \"Error: no test specified\" && exit 1"
20
20
  },
21
- "version": "1.2.12"
22
- }
21
+ "version": "1.2.14"
22
+ }