create-fluxstack 1.14.0 โ†’ 1.16.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.
Files changed (76) hide show
  1. package/LLMD/INDEX.md +4 -3
  2. package/LLMD/resources/live-binary-delta.md +507 -0
  3. package/LLMD/resources/live-components.md +208 -12
  4. package/LLMD/resources/live-rooms.md +731 -333
  5. package/app/client/.live-stubs/LiveAdminPanel.js +5 -0
  6. package/app/client/.live-stubs/LiveCounter.js +9 -0
  7. package/app/client/.live-stubs/LiveForm.js +11 -0
  8. package/app/client/.live-stubs/LiveLocalCounter.js +8 -0
  9. package/app/client/.live-stubs/LivePingPong.js +10 -0
  10. package/app/client/.live-stubs/LiveRoomChat.js +11 -0
  11. package/app/client/.live-stubs/LiveSharedCounter.js +10 -0
  12. package/app/client/.live-stubs/LiveUpload.js +15 -0
  13. package/app/client/src/App.tsx +19 -7
  14. package/app/client/src/components/AppLayout.tsx +18 -10
  15. package/app/client/src/live/PingPongDemo.tsx +199 -0
  16. package/app/client/src/live/RoomChatDemo.tsx +187 -22
  17. package/app/client/src/live/SharedCounterDemo.tsx +142 -0
  18. package/app/server/auth/DevAuthProvider.ts +2 -2
  19. package/app/server/auth/JWTAuthProvider.example.ts +2 -2
  20. package/app/server/index.ts +2 -2
  21. package/app/server/live/LiveAdminPanel.ts +1 -1
  22. package/app/server/live/LivePingPong.ts +61 -0
  23. package/app/server/live/LiveProtectedChat.ts +1 -1
  24. package/app/server/live/LiveRoomChat.ts +106 -38
  25. package/app/server/live/LiveSharedCounter.ts +73 -0
  26. package/app/server/live/rooms/ChatRoom.ts +68 -0
  27. package/app/server/live/rooms/CounterRoom.ts +51 -0
  28. package/app/server/live/rooms/DirectoryRoom.ts +42 -0
  29. package/app/server/live/rooms/PingRoom.ts +40 -0
  30. package/app/server/routes/room.routes.ts +1 -2
  31. package/core/build/live-components-generator.ts +11 -2
  32. package/core/build/vite-plugins.ts +28 -0
  33. package/core/client/hooks/useLiveUpload.ts +3 -4
  34. package/core/client/index.ts +25 -35
  35. package/core/framework/server.ts +1 -1
  36. package/core/server/index.ts +1 -2
  37. package/core/server/live/auto-generated-components.ts +5 -8
  38. package/core/server/live/index.ts +90 -21
  39. package/core/server/live/websocket-plugin.ts +54 -1079
  40. package/core/types/types.ts +76 -1025
  41. package/core/utils/version.ts +1 -1
  42. package/create-fluxstack.ts +1 -1
  43. package/package.json +100 -95
  44. package/plugins/crypto-auth/index.ts +1 -1
  45. package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +2 -2
  46. package/tsconfig.json +4 -1
  47. package/vite.config.ts +40 -12
  48. package/app/client/src/live/ChatDemo.tsx +0 -107
  49. package/app/client/src/live/LiveDebuggerPanel.tsx +0 -779
  50. package/app/server/live/LiveChat.ts +0 -78
  51. package/core/client/LiveComponentsProvider.tsx +0 -531
  52. package/core/client/components/Live.tsx +0 -111
  53. package/core/client/components/LiveDebugger.tsx +0 -1324
  54. package/core/client/hooks/AdaptiveChunkSizer.ts +0 -215
  55. package/core/client/hooks/state-validator.ts +0 -130
  56. package/core/client/hooks/useChunkedUpload.ts +0 -359
  57. package/core/client/hooks/useLiveChunkedUpload.ts +0 -87
  58. package/core/client/hooks/useLiveComponent.ts +0 -853
  59. package/core/client/hooks/useLiveDebugger.ts +0 -392
  60. package/core/client/hooks/useRoom.ts +0 -409
  61. package/core/client/hooks/useRoomProxy.ts +0 -382
  62. package/core/server/live/ComponentRegistry.ts +0 -1128
  63. package/core/server/live/FileUploadManager.ts +0 -446
  64. package/core/server/live/LiveComponentPerformanceMonitor.ts +0 -931
  65. package/core/server/live/LiveDebugger.ts +0 -462
  66. package/core/server/live/LiveLogger.ts +0 -144
  67. package/core/server/live/LiveRoomManager.ts +0 -278
  68. package/core/server/live/RoomEventBus.ts +0 -234
  69. package/core/server/live/RoomStateManager.ts +0 -172
  70. package/core/server/live/SingleConnectionManager.ts +0 -0
  71. package/core/server/live/StateSignature.ts +0 -705
  72. package/core/server/live/WebSocketConnectionManager.ts +0 -710
  73. package/core/server/live/auth/LiveAuthContext.ts +0 -71
  74. package/core/server/live/auth/LiveAuthManager.ts +0 -304
  75. package/core/server/live/auth/index.ts +0 -19
  76. package/core/server/live/auth/types.ts +0 -179
@@ -1,931 +0,0 @@
1
- // ๐Ÿ“Š FluxStack Live Component Performance Monitor
2
- // Advanced performance monitoring, metrics collection, and optimization suggestions
3
-
4
- import { EventEmitter } from 'events'
5
- import { liveLog, liveWarn } from './LiveLogger'
6
-
7
- export interface PerformanceMetrics {
8
- componentId: string
9
- componentName: string
10
- renderMetrics: RenderMetrics
11
- actionMetrics: ActionMetrics
12
- memoryMetrics: MemoryMetrics
13
- networkMetrics: NetworkMetrics
14
- userInteractionMetrics: UserInteractionMetrics
15
- timestamp: Date
16
- }
17
-
18
- export interface RenderMetrics {
19
- totalRenders: number
20
- averageRenderTime: number
21
- minRenderTime: number
22
- maxRenderTime: number
23
- lastRenderTime: number
24
- renderTimeHistory: number[]
25
- slowRenderCount: number // renders > threshold
26
- renderErrorCount: number
27
- }
28
-
29
- export interface ActionMetrics {
30
- totalActions: number
31
- averageActionTime: number
32
- minActionTime: number
33
- maxActionTime: number
34
- actionsByType: Record<string, ActionTypeMetrics>
35
- failedActions: number
36
- timeoutActions: number
37
- }
38
-
39
- export interface ActionTypeMetrics {
40
- count: number
41
- averageTime: number
42
- minTime: number
43
- maxTime: number
44
- errorCount: number
45
- lastExecuted: Date
46
- }
47
-
48
- export interface MemoryMetrics {
49
- currentUsage: number // bytes
50
- peakUsage: number
51
- averageUsage: number
52
- memoryLeakDetected: boolean
53
- gcCount: number
54
- stateSize: number // serialized state size
55
- stateSizeHistory: number[]
56
- }
57
-
58
- export interface NetworkMetrics {
59
- messagesSent: number
60
- messagesReceived: number
61
- bytesTransferred: number
62
- averageLatency: number
63
- connectionDrops: number
64
- reconnectCount: number
65
- queuedMessages: number
66
- }
67
-
68
- export interface UserInteractionMetrics {
69
- clickCount: number
70
- inputChangeCount: number
71
- formSubmissions: number
72
- averageInteractionTime: number
73
- bounceRate: number // percentage of single interactions
74
- engagementScore: number // calculated engagement metric
75
- }
76
-
77
- export interface PerformanceAlert {
78
- id: string
79
- componentId: string
80
- type: 'warning' | 'critical'
81
- category: 'render' | 'action' | 'memory' | 'network' | 'interaction'
82
- message: string
83
- threshold: number
84
- currentValue: number
85
- timestamp: Date
86
- resolved: boolean
87
- }
88
-
89
- export interface OptimizationSuggestion {
90
- id: string
91
- componentId: string
92
- type: 'render' | 'memory' | 'network' | 'state' | 'action'
93
- priority: 'low' | 'medium' | 'high' | 'critical'
94
- title: string
95
- description: string
96
- impact: string
97
- implementation: string
98
- estimatedImprovement: string
99
- timestamp: Date
100
- }
101
-
102
- export interface PerformanceDashboard {
103
- overview: {
104
- totalComponents: number
105
- healthyComponents: number
106
- degradedComponents: number
107
- unhealthyComponents: number
108
- averageRenderTime: number
109
- averageMemoryUsage: number
110
- totalAlerts: number
111
- criticalAlerts: number
112
- }
113
- topPerformers: PerformanceMetrics[]
114
- worstPerformers: PerformanceMetrics[]
115
- recentAlerts: PerformanceAlert[]
116
- suggestions: OptimizationSuggestion[]
117
- trends: {
118
- renderTimetrend: number[] // last 24 hours
119
- memoryUsageTrend: number[]
120
- actionTimeTrend: number[]
121
- }
122
- }
123
-
124
- export interface MonitoringConfig {
125
- enabled: boolean
126
- sampleRate: number // 0-1, percentage of operations to monitor
127
- renderTimeThreshold: number // ms
128
- memoryThreshold: number // bytes
129
- actionTimeThreshold: number // ms
130
- alertCooldown: number // ms between same type alerts
131
- historyRetention: number // ms to keep historical data
132
- dashboardUpdateInterval: number // ms
133
- }
134
-
135
- export class LiveComponentPerformanceMonitor extends EventEmitter {
136
- private metrics = new Map<string, PerformanceMetrics>()
137
- private alerts = new Map<string, PerformanceAlert[]>() // componentId -> alerts
138
- private suggestions = new Map<string, OptimizationSuggestion[]>()
139
- private config: MonitoringConfig
140
- private dashboardUpdateInterval!: NodeJS.Timeout
141
- private alertCooldowns = new Map<string, number>() // alertType -> lastAlertTime
142
- private performanceObserver?: any
143
-
144
- constructor(config?: Partial<MonitoringConfig>) {
145
- super()
146
-
147
- this.config = {
148
- enabled: true,
149
- sampleRate: 1.0, // Monitor 100% by default
150
- renderTimeThreshold: 100, // 100ms
151
- memoryThreshold: 50 * 1024 * 1024, // 50MB
152
- actionTimeThreshold: 1000, // 1 second
153
- alertCooldown: 60000, // 1 minute
154
- historyRetention: 24 * 60 * 60 * 1000, // 24 hours
155
- dashboardUpdateInterval: 30000, // 30 seconds
156
- ...config
157
- }
158
-
159
- if (this.config.enabled) {
160
- this.setupPerformanceObserver()
161
- this.setupDashboardUpdates()
162
- this.setupCleanupTasks()
163
- }
164
- }
165
-
166
- /**
167
- * Setup performance observer for native performance monitoring
168
- */
169
- private setupPerformanceObserver(): void {
170
- try {
171
- // Use Node.js performance hooks if available
172
- const { PerformanceObserver, performance } = require('perf_hooks')
173
-
174
- this.performanceObserver = new PerformanceObserver((list: any) => {
175
- const entries = list.getEntries()
176
- for (const entry of entries) {
177
- if (entry.name.startsWith('live-component-')) {
178
- this.processPerformanceEntry(entry)
179
- }
180
- }
181
- })
182
-
183
- this.performanceObserver.observe({ entryTypes: ['measure', 'mark'] })
184
- // Performance observer ready (logged at DEBUG level to keep startup clean)
185
- } catch (error) {
186
- console.warn('โš ๏ธ Performance observer not available:', error)
187
- }
188
- }
189
-
190
- /**
191
- * Process performance entry from observer
192
- */
193
- private processPerformanceEntry(entry: any): void {
194
- const [, componentId, operation] = entry.name.split('-')
195
-
196
- if (operation === 'render') {
197
- this.recordRenderTime(componentId, entry.duration)
198
- } else if (operation === 'action') {
199
- this.recordActionTime(componentId, 'unknown', entry.duration)
200
- }
201
- }
202
-
203
- /**
204
- * Setup dashboard update interval
205
- */
206
- private setupDashboardUpdates(): void {
207
- this.dashboardUpdateInterval = setInterval(() => {
208
- this.updateDashboard()
209
- }, this.config.dashboardUpdateInterval)
210
- }
211
-
212
- /**
213
- * Setup cleanup tasks
214
- */
215
- private setupCleanupTasks(): void {
216
- // Clean up old data every hour
217
- setInterval(() => {
218
- this.cleanupOldData()
219
- }, 60 * 60 * 1000)
220
- }
221
-
222
- /**
223
- * Initialize metrics for a component
224
- */
225
- initializeComponent(componentId: string, componentName: string): void {
226
- if (!this.config.enabled || !this.shouldSample()) return
227
-
228
- const metrics: PerformanceMetrics = {
229
- componentId,
230
- componentName,
231
- renderMetrics: {
232
- totalRenders: 0,
233
- averageRenderTime: 0,
234
- minRenderTime: Infinity,
235
- maxRenderTime: 0,
236
- lastRenderTime: 0,
237
- renderTimeHistory: [],
238
- slowRenderCount: 0,
239
- renderErrorCount: 0
240
- },
241
- actionMetrics: {
242
- totalActions: 0,
243
- averageActionTime: 0,
244
- minActionTime: Infinity,
245
- maxActionTime: 0,
246
- actionsByType: {},
247
- failedActions: 0,
248
- timeoutActions: 0
249
- },
250
- memoryMetrics: {
251
- currentUsage: 0,
252
- peakUsage: 0,
253
- averageUsage: 0,
254
- memoryLeakDetected: false,
255
- gcCount: 0,
256
- stateSize: 0,
257
- stateSizeHistory: []
258
- },
259
- networkMetrics: {
260
- messagesSent: 0,
261
- messagesReceived: 0,
262
- bytesTransferred: 0,
263
- averageLatency: 0,
264
- connectionDrops: 0,
265
- reconnectCount: 0,
266
- queuedMessages: 0
267
- },
268
- userInteractionMetrics: {
269
- clickCount: 0,
270
- inputChangeCount: 0,
271
- formSubmissions: 0,
272
- averageInteractionTime: 0,
273
- bounceRate: 0,
274
- engagementScore: 0
275
- },
276
- timestamp: new Date()
277
- }
278
-
279
- this.metrics.set(componentId, metrics)
280
- this.alerts.set(componentId, [])
281
- this.suggestions.set(componentId, [])
282
-
283
- liveLog('performance', componentId, `๐Ÿ“Š Performance monitoring initialized for component: ${componentId}`)
284
- }
285
-
286
- /**
287
- * Record render performance
288
- */
289
- recordRenderTime(componentId: string, renderTime: number, error?: Error): void {
290
- if (!this.config.enabled || !this.shouldSample()) return
291
-
292
- const metrics = this.metrics.get(componentId)
293
- if (!metrics) return
294
-
295
- const renderMetrics = metrics.renderMetrics
296
-
297
- if (error) {
298
- renderMetrics.renderErrorCount++
299
- this.createAlert(componentId, 'warning', 'render', `Render error: ${error.message}`, 0, 1)
300
- return
301
- }
302
-
303
- // Update render metrics
304
- renderMetrics.totalRenders++
305
- renderMetrics.lastRenderTime = renderTime
306
- renderMetrics.minRenderTime = Math.min(renderMetrics.minRenderTime, renderTime)
307
- renderMetrics.maxRenderTime = Math.max(renderMetrics.maxRenderTime, renderTime)
308
-
309
- // Update average
310
- renderMetrics.averageRenderTime =
311
- (renderMetrics.averageRenderTime * (renderMetrics.totalRenders - 1) + renderTime) / renderMetrics.totalRenders
312
-
313
- // Track history (keep last 100 renders)
314
- renderMetrics.renderTimeHistory.push(renderTime)
315
- if (renderMetrics.renderTimeHistory.length > 100) {
316
- renderMetrics.renderTimeHistory.shift()
317
- }
318
-
319
- // Check for slow renders
320
- if (renderTime > this.config.renderTimeThreshold) {
321
- renderMetrics.slowRenderCount++
322
-
323
- if (renderTime > this.config.renderTimeThreshold * 2) {
324
- this.createAlert(componentId, 'warning', 'render',
325
- `Slow render detected: ${renderTime.toFixed(2)}ms`,
326
- this.config.renderTimeThreshold, renderTime)
327
- }
328
- }
329
-
330
- // Generate optimization suggestions
331
- this.analyzeRenderPerformance(componentId, metrics)
332
-
333
- metrics.timestamp = new Date()
334
- }
335
-
336
- /**
337
- * Record action performance
338
- */
339
- recordActionTime(componentId: string, actionName: string, actionTime: number, error?: Error): void {
340
- if (!this.config.enabled || !this.shouldSample()) return
341
-
342
- const metrics = this.metrics.get(componentId)
343
- if (!metrics) return
344
-
345
- const actionMetrics = metrics.actionMetrics
346
-
347
- if (error) {
348
- actionMetrics.failedActions++
349
- this.createAlert(componentId, 'warning', 'action',
350
- `Action failed: ${actionName} - ${error.message}`, 0, 1)
351
- return
352
- }
353
-
354
- // Update overall action metrics
355
- actionMetrics.totalActions++
356
- actionMetrics.minActionTime = Math.min(actionMetrics.minActionTime, actionTime)
357
- actionMetrics.maxActionTime = Math.max(actionMetrics.maxActionTime, actionTime)
358
- actionMetrics.averageActionTime =
359
- (actionMetrics.averageActionTime * (actionMetrics.totalActions - 1) + actionTime) / actionMetrics.totalActions
360
-
361
- // Update action type metrics
362
- if (!actionMetrics.actionsByType[actionName]) {
363
- actionMetrics.actionsByType[actionName] = {
364
- count: 0,
365
- averageTime: 0,
366
- minTime: Infinity,
367
- maxTime: 0,
368
- errorCount: 0,
369
- lastExecuted: new Date()
370
- }
371
- }
372
-
373
- const typeMetrics = actionMetrics.actionsByType[actionName]
374
- typeMetrics.count++
375
- typeMetrics.minTime = Math.min(typeMetrics.minTime, actionTime)
376
- typeMetrics.maxTime = Math.max(typeMetrics.maxTime, actionTime)
377
- typeMetrics.averageTime =
378
- (typeMetrics.averageTime * (typeMetrics.count - 1) + actionTime) / typeMetrics.count
379
- typeMetrics.lastExecuted = new Date()
380
-
381
- // Check for slow actions
382
- if (actionTime > this.config.actionTimeThreshold) {
383
- this.createAlert(componentId, 'warning', 'action',
384
- `Slow action detected: ${actionName} took ${actionTime.toFixed(2)}ms`,
385
- this.config.actionTimeThreshold, actionTime)
386
- }
387
-
388
- // Generate optimization suggestions
389
- this.analyzeActionPerformance(componentId, actionName, metrics)
390
-
391
- metrics.timestamp = new Date()
392
- }
393
-
394
- /**
395
- * Record memory usage
396
- */
397
- recordMemoryUsage(componentId: string, memoryUsage: number, stateSize?: number): void {
398
- if (!this.config.enabled || !this.shouldSample()) return
399
-
400
- const metrics = this.metrics.get(componentId)
401
- if (!metrics) return
402
-
403
- const memoryMetrics = metrics.memoryMetrics
404
-
405
- // Update memory metrics
406
- memoryMetrics.currentUsage = memoryUsage
407
- memoryMetrics.peakUsage = Math.max(memoryMetrics.peakUsage, memoryUsage)
408
-
409
- // Calculate average (simple moving average)
410
- const sampleCount = Math.min(100, memoryMetrics.gcCount + 1)
411
- memoryMetrics.averageUsage =
412
- (memoryMetrics.averageUsage * (sampleCount - 1) + memoryUsage) / sampleCount
413
-
414
- if (stateSize !== undefined) {
415
- memoryMetrics.stateSize = stateSize
416
- memoryMetrics.stateSizeHistory.push(stateSize)
417
-
418
- // Keep last 100 state sizes
419
- if (memoryMetrics.stateSizeHistory.length > 100) {
420
- memoryMetrics.stateSizeHistory.shift()
421
- }
422
- }
423
-
424
- // Check for memory issues
425
- if (memoryUsage > this.config.memoryThreshold) {
426
- this.createAlert(componentId, 'critical', 'memory',
427
- `High memory usage: ${(memoryUsage / 1024 / 1024).toFixed(2)}MB`,
428
- this.config.memoryThreshold, memoryUsage)
429
- }
430
-
431
- // Detect memory leaks (increasing trend over time)
432
- if (memoryMetrics.stateSizeHistory.length >= 10) {
433
- const recentSizes = memoryMetrics.stateSizeHistory.slice(-10)
434
- const trend = this.calculateTrend(recentSizes)
435
-
436
- if (trend > 0.1) { // 10% increase trend
437
- memoryMetrics.memoryLeakDetected = true
438
- this.createAlert(componentId, 'critical', 'memory',
439
- 'Potential memory leak detected - state size increasing', 0, trend)
440
- }
441
- }
442
-
443
- // Generate optimization suggestions
444
- this.analyzeMemoryPerformance(componentId, metrics)
445
-
446
- metrics.timestamp = new Date()
447
- }
448
-
449
- /**
450
- * Record network metrics
451
- */
452
- recordNetworkActivity(componentId: string, type: 'sent' | 'received', bytes: number, latency?: number): void {
453
- if (!this.config.enabled || !this.shouldSample()) return
454
-
455
- const metrics = this.metrics.get(componentId)
456
- if (!metrics) return
457
-
458
- const networkMetrics = metrics.networkMetrics
459
-
460
- if (type === 'sent') {
461
- networkMetrics.messagesSent++
462
- } else {
463
- networkMetrics.messagesReceived++
464
- }
465
-
466
- networkMetrics.bytesTransferred += bytes
467
-
468
- if (latency !== undefined) {
469
- const totalMessages = networkMetrics.messagesSent + networkMetrics.messagesReceived
470
- networkMetrics.averageLatency =
471
- (networkMetrics.averageLatency * (totalMessages - 1) + latency) / totalMessages
472
- }
473
-
474
- metrics.timestamp = new Date()
475
- }
476
-
477
- /**
478
- * Record user interaction
479
- */
480
- recordUserInteraction(componentId: string, type: 'click' | 'input' | 'submit', interactionTime?: number): void {
481
- if (!this.config.enabled || !this.shouldSample()) return
482
-
483
- const metrics = this.metrics.get(componentId)
484
- if (!metrics) return
485
-
486
- const interactionMetrics = metrics.userInteractionMetrics
487
-
488
- switch (type) {
489
- case 'click':
490
- interactionMetrics.clickCount++
491
- break
492
- case 'input':
493
- interactionMetrics.inputChangeCount++
494
- break
495
- case 'submit':
496
- interactionMetrics.formSubmissions++
497
- break
498
- }
499
-
500
- if (interactionTime !== undefined) {
501
- const totalInteractions = interactionMetrics.clickCount +
502
- interactionMetrics.inputChangeCount +
503
- interactionMetrics.formSubmissions
504
-
505
- interactionMetrics.averageInteractionTime =
506
- (interactionMetrics.averageInteractionTime * (totalInteractions - 1) + interactionTime) / totalInteractions
507
- }
508
-
509
- // Calculate engagement score
510
- interactionMetrics.engagementScore = this.calculateEngagementScore(interactionMetrics)
511
-
512
- metrics.timestamp = new Date()
513
- }
514
-
515
- /**
516
- * Calculate engagement score based on interactions
517
- */
518
- private calculateEngagementScore(metrics: UserInteractionMetrics): number {
519
- const totalInteractions = metrics.clickCount + metrics.inputChangeCount + metrics.formSubmissions
520
- const timeWeight = Math.min(metrics.averageInteractionTime / 1000, 10) // Cap at 10 seconds
521
- const diversityBonus = (metrics.clickCount > 0 ? 1 : 0) +
522
- (metrics.inputChangeCount > 0 ? 1 : 0) +
523
- (metrics.formSubmissions > 0 ? 1 : 0)
524
-
525
- return Math.min(100, (totalInteractions * timeWeight * diversityBonus) / 10)
526
- }
527
-
528
- /**
529
- * Create performance alert
530
- */
531
- private createAlert(
532
- componentId: string,
533
- type: 'warning' | 'critical',
534
- category: 'render' | 'action' | 'memory' | 'network' | 'interaction',
535
- message: string,
536
- threshold: number,
537
- currentValue: number
538
- ): void {
539
- const alertKey = `${componentId}-${category}-${type}`
540
- const now = Date.now()
541
-
542
- // Check cooldown
543
- const lastAlert = this.alertCooldowns.get(alertKey)
544
- if (lastAlert && (now - lastAlert) < this.config.alertCooldown) {
545
- return
546
- }
547
-
548
- const alert: PerformanceAlert = {
549
- id: `alert-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
550
- componentId,
551
- type,
552
- category,
553
- message,
554
- threshold,
555
- currentValue,
556
- timestamp: new Date(),
557
- resolved: false
558
- }
559
-
560
- const componentAlerts = this.alerts.get(componentId) || []
561
- componentAlerts.push(alert)
562
- this.alerts.set(componentId, componentAlerts)
563
-
564
- this.alertCooldowns.set(alertKey, now)
565
-
566
- liveWarn('performance', componentId, `โš ๏ธ Performance alert [${type}]: ${message}`)
567
- this.emit('performanceAlert', alert)
568
- }
569
-
570
- /**
571
- * Analyze render performance and generate suggestions
572
- */
573
- private analyzeRenderPerformance(componentId: string, metrics: PerformanceMetrics): void {
574
- const renderMetrics = metrics.renderMetrics
575
-
576
- // Check for consistently slow renders
577
- if (renderMetrics.averageRenderTime > this.config.renderTimeThreshold * 0.8) {
578
- this.createSuggestion(componentId, 'render', 'medium',
579
- 'Optimize Render Performance',
580
- 'Component renders are consistently slow. Consider optimizing state updates and reducing re-renders.',
581
- 'Improved user experience and responsiveness',
582
- 'Use React.memo, useMemo, or useCallback to prevent unnecessary re-renders. Optimize state structure.',
583
- `${((this.config.renderTimeThreshold - renderMetrics.averageRenderTime) / renderMetrics.averageRenderTime * 100).toFixed(1)}% faster renders`
584
- )
585
- }
586
-
587
- // Check for render time variance
588
- if (renderMetrics.renderTimeHistory.length >= 10) {
589
- const variance = this.calculateVariance(renderMetrics.renderTimeHistory)
590
- if (variance > renderMetrics.averageRenderTime * 0.5) {
591
- this.createSuggestion(componentId, 'render', 'low',
592
- 'Reduce Render Time Variance',
593
- 'Render times are inconsistent, which can cause jank.',
594
- 'Smoother user experience',
595
- 'Identify and optimize conditional rendering logic. Consider lazy loading heavy components.',
596
- 'More consistent performance'
597
- )
598
- }
599
- }
600
- }
601
-
602
- /**
603
- * Analyze action performance and generate suggestions
604
- */
605
- private analyzeActionPerformance(componentId: string, actionName: string, metrics: PerformanceMetrics): void {
606
- const actionMetrics = metrics.actionMetrics
607
- const typeMetrics = actionMetrics.actionsByType[actionName]
608
-
609
- // Check for slow actions
610
- if (typeMetrics.averageTime > this.config.actionTimeThreshold * 0.8) {
611
- this.createSuggestion(componentId, 'action', 'high',
612
- `Optimize ${actionName} Action`,
613
- `The ${actionName} action is taking longer than expected to complete.`,
614
- 'Better user experience and responsiveness',
615
- 'Consider adding loading states, optimizing database queries, or implementing caching.',
616
- `${((this.config.actionTimeThreshold - typeMetrics.averageTime) / typeMetrics.averageTime * 100).toFixed(1)}% faster actions`
617
- )
618
- }
619
-
620
- // Check for high error rate
621
- const errorRate = typeMetrics.errorCount / typeMetrics.count
622
- if (errorRate > 0.1) { // 10% error rate
623
- this.createSuggestion(componentId, 'action', 'critical',
624
- `Fix ${actionName} Action Errors`,
625
- `High error rate detected for ${actionName} action (${(errorRate * 100).toFixed(1)}%).`,
626
- 'Improved reliability and user experience',
627
- 'Add proper error handling, input validation, and retry mechanisms.',
628
- `${((1 - errorRate) * 100).toFixed(1)}% success rate improvement`
629
- )
630
- }
631
- }
632
-
633
- /**
634
- * Analyze memory performance and generate suggestions
635
- */
636
- private analyzeMemoryPerformance(componentId: string, metrics: PerformanceMetrics): void {
637
- const memoryMetrics = metrics.memoryMetrics
638
-
639
- // Check for large state size
640
- if (memoryMetrics.stateSize > 100 * 1024) { // 100KB
641
- this.createSuggestion(componentId, 'memory', 'medium',
642
- 'Optimize State Size',
643
- 'Component state is larger than recommended, which can impact performance.',
644
- 'Reduced memory usage and faster serialization',
645
- 'Consider normalizing state structure, removing unused data, or implementing state compression.',
646
- `${((memoryMetrics.stateSize - 50 * 1024) / 1024).toFixed(1)}KB reduction potential`
647
- )
648
- }
649
-
650
- // Check for memory leak
651
- if (memoryMetrics.memoryLeakDetected) {
652
- this.createSuggestion(componentId, 'memory', 'critical',
653
- 'Fix Memory Leak',
654
- 'Potential memory leak detected - memory usage is continuously increasing.',
655
- 'Prevent application crashes and improve stability',
656
- 'Review event listeners, timers, and subscriptions for proper cleanup. Use weak references where appropriate.',
657
- 'Stable memory usage'
658
- )
659
- }
660
- }
661
-
662
- /**
663
- * Create optimization suggestion
664
- */
665
- private createSuggestion(
666
- componentId: string,
667
- type: 'render' | 'memory' | 'network' | 'state' | 'action',
668
- priority: 'low' | 'medium' | 'high' | 'critical',
669
- title: string,
670
- description: string,
671
- impact: string,
672
- implementation: string,
673
- estimatedImprovement: string
674
- ): void {
675
- const suggestions = this.suggestions.get(componentId) || []
676
-
677
- // Check if similar suggestion already exists
678
- const existingSuggestion = suggestions.find(s => s.title === title && !s.timestamp ||
679
- (Date.now() - s.timestamp.getTime()) < 24 * 60 * 60 * 1000) // 24 hours
680
-
681
- if (existingSuggestion) return
682
-
683
- const suggestion: OptimizationSuggestion = {
684
- id: `suggestion-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
685
- componentId,
686
- type,
687
- priority,
688
- title,
689
- description,
690
- impact,
691
- implementation,
692
- estimatedImprovement,
693
- timestamp: new Date()
694
- }
695
-
696
- suggestions.push(suggestion)
697
- this.suggestions.set(componentId, suggestions)
698
-
699
- liveLog('performance', componentId, `๐Ÿ’ก Optimization suggestion for ${componentId}: ${title}`)
700
- this.emit('optimizationSuggestion', suggestion)
701
- }
702
-
703
- /**
704
- * Calculate trend from array of numbers
705
- */
706
- private calculateTrend(values: number[]): number {
707
- if (values.length < 2) return 0
708
-
709
- const n = values.length
710
- const sumX = (n * (n - 1)) / 2
711
- const sumY = values.reduce((sum, val) => sum + val, 0)
712
- const sumXY = values.reduce((sum, val, index) => sum + (index * val), 0)
713
- const sumX2 = (n * (n - 1) * (2 * n - 1)) / 6
714
-
715
- const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX)
716
- return slope / (sumY / n) // Normalize by average
717
- }
718
-
719
- /**
720
- * Calculate variance from array of numbers
721
- */
722
- private calculateVariance(values: number[]): number {
723
- if (values.length < 2) return 0
724
-
725
- const mean = values.reduce((sum, val) => sum + val, 0) / values.length
726
- const squaredDiffs = values.map(val => Math.pow(val - mean, 2))
727
- return squaredDiffs.reduce((sum, val) => sum + val, 0) / values.length
728
- }
729
-
730
- /**
731
- * Should sample this operation based on sample rate
732
- */
733
- private shouldSample(): boolean {
734
- return Math.random() < this.config.sampleRate
735
- }
736
-
737
- /**
738
- * Update dashboard data
739
- */
740
- private updateDashboard(): void {
741
- const dashboard = this.generateDashboard()
742
- this.emit('dashboardUpdate', dashboard)
743
- }
744
-
745
- /**
746
- * Generate performance dashboard
747
- */
748
- generateDashboard(): PerformanceDashboard {
749
- const allMetrics = Array.from(this.metrics.values())
750
- const allAlerts = Array.from(this.alerts.values()).flat()
751
- const allSuggestions = Array.from(this.suggestions.values()).flat()
752
-
753
- // Calculate overview stats
754
- const totalComponents = allMetrics.length
755
- const healthyComponents = allMetrics.filter(m => this.isComponentHealthy(m)).length
756
- const degradedComponents = allMetrics.filter(m => this.isComponentDegraded(m)).length
757
- const unhealthyComponents = totalComponents - healthyComponents - degradedComponents
758
-
759
- const averageRenderTime = allMetrics.reduce((sum, m) => sum + m.renderMetrics.averageRenderTime, 0) / totalComponents || 0
760
- const averageMemoryUsage = allMetrics.reduce((sum, m) => sum + m.memoryMetrics.currentUsage, 0) / totalComponents || 0
761
-
762
- const totalAlerts = allAlerts.filter(a => !a.resolved).length
763
- const criticalAlerts = allAlerts.filter(a => a.type === 'critical' && !a.resolved).length
764
-
765
- // Get top and worst performers
766
- const sortedByRender = [...allMetrics].sort((a, b) => a.renderMetrics.averageRenderTime - b.renderMetrics.averageRenderTime)
767
- const topPerformers = sortedByRender.slice(0, 5)
768
- const worstPerformers = sortedByRender.slice(-5).reverse()
769
-
770
- // Get recent alerts
771
- const recentAlerts = allAlerts
772
- .filter(a => !a.resolved)
773
- .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
774
- .slice(0, 10)
775
-
776
- // Get top suggestions
777
- const topSuggestions = allSuggestions
778
- .sort((a, b) => {
779
- const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 }
780
- return priorityOrder[b.priority] - priorityOrder[a.priority]
781
- })
782
- .slice(0, 10)
783
-
784
- // Generate trends (simplified - would need historical data storage for real trends)
785
- const renderTimeHistory = allMetrics.map(m => m.renderMetrics.averageRenderTime)
786
- const memoryUsageHistory = allMetrics.map(m => m.memoryMetrics.currentUsage)
787
- const actionTimeHistory = allMetrics.map(m => m.actionMetrics.averageActionTime)
788
-
789
- return {
790
- overview: {
791
- totalComponents,
792
- healthyComponents,
793
- degradedComponents,
794
- unhealthyComponents,
795
- averageRenderTime,
796
- averageMemoryUsage,
797
- totalAlerts,
798
- criticalAlerts
799
- },
800
- topPerformers,
801
- worstPerformers,
802
- recentAlerts,
803
- suggestions: topSuggestions,
804
- trends: {
805
- renderTimetrend: renderTimeHistory,
806
- memoryUsageTrend: memoryUsageHistory,
807
- actionTimeTrend: actionTimeHistory
808
- }
809
- }
810
- }
811
-
812
- /**
813
- * Check if component is healthy
814
- */
815
- private isComponentHealthy(metrics: PerformanceMetrics): boolean {
816
- return metrics.renderMetrics.averageRenderTime < this.config.renderTimeThreshold * 0.5 &&
817
- metrics.memoryMetrics.currentUsage < this.config.memoryThreshold * 0.5 &&
818
- metrics.actionMetrics.failedActions / Math.max(metrics.actionMetrics.totalActions, 1) < 0.05
819
- }
820
-
821
- /**
822
- * Check if component is degraded
823
- */
824
- private isComponentDegraded(metrics: PerformanceMetrics): boolean {
825
- return !this.isComponentHealthy(metrics) && !this.isComponentUnhealthy(metrics)
826
- }
827
-
828
- /**
829
- * Check if component is unhealthy
830
- */
831
- private isComponentUnhealthy(metrics: PerformanceMetrics): boolean {
832
- return metrics.renderMetrics.averageRenderTime > this.config.renderTimeThreshold ||
833
- metrics.memoryMetrics.currentUsage > this.config.memoryThreshold ||
834
- metrics.actionMetrics.failedActions / Math.max(metrics.actionMetrics.totalActions, 1) > 0.2 ||
835
- metrics.memoryMetrics.memoryLeakDetected
836
- }
837
-
838
- /**
839
- * Get component metrics
840
- */
841
- getComponentMetrics(componentId: string): PerformanceMetrics | null {
842
- return this.metrics.get(componentId) || null
843
- }
844
-
845
- /**
846
- * Get component alerts
847
- */
848
- getComponentAlerts(componentId: string): PerformanceAlert[] {
849
- return this.alerts.get(componentId) || []
850
- }
851
-
852
- /**
853
- * Get component suggestions
854
- */
855
- getComponentSuggestions(componentId: string): OptimizationSuggestion[] {
856
- return this.suggestions.get(componentId) || []
857
- }
858
-
859
- /**
860
- * Resolve alert
861
- */
862
- resolveAlert(alertId: string): boolean {
863
- for (const alerts of this.alerts.values()) {
864
- const alert = alerts.find(a => a.id === alertId)
865
- if (alert) {
866
- alert.resolved = true
867
- liveLog('performance', null, `โœ… Alert resolved: ${alertId}`)
868
- return true
869
- }
870
- }
871
- return false
872
- }
873
-
874
- /**
875
- * Clean up old data
876
- */
877
- private cleanupOldData(): void {
878
- const now = Date.now()
879
- const cutoff = now - this.config.historyRetention
880
-
881
- // Clean up old alerts
882
- for (const [componentId, alerts] of this.alerts) {
883
- const validAlerts = alerts.filter(alert => alert.timestamp.getTime() > cutoff)
884
- this.alerts.set(componentId, validAlerts)
885
- }
886
-
887
- // Clean up old suggestions
888
- for (const [componentId, suggestions] of this.suggestions) {
889
- const validSuggestions = suggestions.filter(suggestion => suggestion.timestamp.getTime() > cutoff)
890
- this.suggestions.set(componentId, validSuggestions)
891
- }
892
-
893
- liveLog('performance', null, '๐Ÿงน Performance monitoring data cleanup completed')
894
- }
895
-
896
- /**
897
- * Remove component from monitoring
898
- */
899
- removeComponent(componentId: string): void {
900
- this.metrics.delete(componentId)
901
- this.alerts.delete(componentId)
902
- this.suggestions.delete(componentId)
903
-
904
- liveLog('performance', componentId, `๐Ÿ“Š Performance monitoring removed for component: ${componentId}`)
905
- }
906
-
907
- /**
908
- * Shutdown performance monitor
909
- */
910
- shutdown(): void {
911
- liveLog('performance', null, '๐Ÿ“Š Shutting down Performance Monitor...')
912
-
913
- if (this.dashboardUpdateInterval) {
914
- clearInterval(this.dashboardUpdateInterval)
915
- }
916
-
917
- if (this.performanceObserver) {
918
- this.performanceObserver.disconnect()
919
- }
920
-
921
- this.metrics.clear()
922
- this.alerts.clear()
923
- this.suggestions.clear()
924
- this.alertCooldowns.clear()
925
-
926
- liveLog('performance', null, 'โœ… Performance Monitor shutdown complete')
927
- }
928
- }
929
-
930
- // Global performance monitor instance
931
- export const performanceMonitor = new LiveComponentPerformanceMonitor()