matterbridge-plugin-lightwaverf 1.0.0 → 1.0.2

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 (137) hide show
  1. package/.matterbridge/history.html +741 -0
  2. package/.matterbridge/matterbridge-plugin-lightwaverf/.endpointNumbers/d5f2123da1d74aca3d92becc86a19e3801b42e9c02634c7d4b37dbb2c5a8e9aa +1 -1
  3. package/.matterbridge/matterbridge-plugin-lightwaverf/0d0a2ac6163e36f3f2349c77671004edfe3d5e1abbef93cbb583acec8d01481b +1 -1
  4. package/.matterbridge/matterbridge-plugin-lightwaverf.config.json +2 -2
  5. package/.matterbridge/matterbridge-xiaomi-roborock/.endpointNumbers/d5f2123da1d74aca3d92becc86a19e3801b42e9c02634c7d4b37dbb2c5a8e9aa +1 -0
  6. package/.matterbridge/matterbridge-xiaomi-roborock/.selectDevice/3385b8752965077f9e52e27c413425a5f84ed89078acebbc1964f21d80c74bc9 +1 -0
  7. package/.matterbridge/matterbridge-xiaomi-roborock/.selectEntity/969dcec331a5f15e8672c8833573cff0aad3831a586ec33e8290d84c80a2dc2d +1 -0
  8. package/.matterbridge/matterbridge-xiaomi-roborock/0d0a2ac6163e36f3f2349c77671004edfe3d5e1abbef93cbb583acec8d01481b +1 -0
  9. package/.matterbridge/matterbridge-xiaomi-roborock.config.json +15 -0
  10. package/.matterbridge/matterstorage/Matterbridge/events.lastEventNumber +1 -1
  11. package/.matterbridge/matterstorage/Matterbridge/fabrics.fabrics +1 -1
  12. package/.matterbridge/matterstorage/Matterbridge/fabrics.nextFabricIndex +1 -1
  13. package/.matterbridge/matterstorage/Matterbridge/persist.serialNumber +1 -1
  14. package/.matterbridge/matterstorage/Matterbridge/persist.uniqueId +1 -1
  15. package/.matterbridge/matterstorage/Matterbridge/root.__nextNumber__ +1 -1
  16. package/.matterbridge/matterstorage/Matterbridge/root.accessControl.acl +1 -1
  17. package/.matterbridge/matterstorage/Matterbridge/root.generalDiagnostics.rebootCount +1 -1
  18. package/.matterbridge/matterstorage/Matterbridge/root.generalDiagnostics.totalOperationalHoursCounter +1 -1
  19. package/.matterbridge/matterstorage/Matterbridge/root.operationalCredentials.commissionedFabrics +1 -1
  20. package/.matterbridge/matterstorage/Matterbridge/root.operationalCredentials.fabrics +1 -1
  21. package/.matterbridge/matterstorage/Matterbridge/root.operationalCredentials.nocs +1 -1
  22. package/.matterbridge/matterstorage/Matterbridge/root.operationalCredentials.trustedRootCertificates +1 -1
  23. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.1-1.__number__ +1 -1
  24. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.1-2.__number__ +1 -1
  25. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.1-4.__number__ +1 -1
  26. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.10-1.__number__ +1 -1
  27. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.11-1.__number__ +1 -1
  28. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.2-2.__number__ +1 -1
  29. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.2-3.__number__ +1 -1
  30. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-1.__number__ +1 -1
  31. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-1.onOff.onOff +1 -1
  32. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-2.__number__ +1 -1
  33. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-3.__number__ +1 -1
  34. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-4.__number__ +1 -1
  35. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.4-1.__number__ +1 -1
  36. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.4-2.__number__ +1 -1
  37. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.5-1.__number__ +1 -1
  38. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.6-1.__number__ +1 -1
  39. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.7-1.__number__ +1 -1
  40. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-1.__number__ +1 -1
  41. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-2.__number__ +1 -1
  42. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-3.__number__ +1 -1
  43. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.9-1.__number__ +1 -1
  44. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.RestartMatterbridge%3Aoutlet.bridgedDeviceBasicInformation.uniqueId +1 -1
  45. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.UpdateMatterbridge%3Aoutlet.bridgedDeviceBasicInformation.uniqueId +1 -1
  46. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.part2.__number__ +1 -0
  47. package/.matterbridge/matterstorage/Matterbridge/root.subscription.subscriptions +1 -1
  48. package/.matterbridge/matterstorage/Matterbridge/sessions.resumptionRecords +1 -1
  49. package/.matterbridge/matterstorage/Roborock/events.lastEventNumber +1 -0
  50. package/.matterbridge/matterstorage/Roborock/fabrics.fabrics +1 -0
  51. package/.matterbridge/matterstorage/Roborock/fabrics.nextFabricIndex +1 -0
  52. package/.matterbridge/matterstorage/Roborock/persist.deviceName +1 -0
  53. package/.matterbridge/matterstorage/Roborock/persist.deviceType +1 -0
  54. package/.matterbridge/matterstorage/Roborock/persist.hardwareVersion +1 -0
  55. package/.matterbridge/matterstorage/Roborock/persist.hardwareVersionString +1 -0
  56. package/.matterbridge/matterstorage/Roborock/persist.nodeLabel +1 -0
  57. package/.matterbridge/matterstorage/Roborock/persist.productId +1 -0
  58. package/.matterbridge/matterstorage/Roborock/persist.productLabel +1 -0
  59. package/.matterbridge/matterstorage/Roborock/persist.productName +1 -0
  60. package/.matterbridge/matterstorage/Roborock/persist.serialNumber +1 -0
  61. package/.matterbridge/matterstorage/Roborock/persist.softwareVersion +1 -0
  62. package/.matterbridge/matterstorage/Roborock/persist.softwareVersionString +1 -0
  63. package/.matterbridge/matterstorage/Roborock/persist.storeId +1 -0
  64. package/.matterbridge/matterstorage/Roborock/persist.uniqueId +1 -0
  65. package/.matterbridge/matterstorage/Roborock/persist.vendorId +1 -0
  66. package/.matterbridge/matterstorage/Roborock/persist.vendorName +1 -0
  67. package/.matterbridge/matterstorage/Roborock/root.__nextNumber__ +1 -0
  68. package/.matterbridge/matterstorage/Roborock/root.__number__ +1 -0
  69. package/.matterbridge/matterstorage/Roborock/root.accessControl.__features__ +1 -0
  70. package/.matterbridge/matterstorage/Roborock/root.accessControl.acl +1 -0
  71. package/.matterbridge/matterstorage/Roborock/root.basicInformation.location +1 -0
  72. package/.matterbridge/matterstorage/Roborock/root.generalCommissioning.__features__ +1 -0
  73. package/.matterbridge/matterstorage/Roborock/root.generalCommissioning.breadcrumb +1 -0
  74. package/.matterbridge/matterstorage/Roborock/root.generalDiagnostics.__features__ +1 -0
  75. package/.matterbridge/matterstorage/Roborock/root.generalDiagnostics.rebootCount +1 -0
  76. package/.matterbridge/matterstorage/Roborock/root.generalDiagnostics.totalOperationalHoursCounter +1 -0
  77. package/.matterbridge/matterstorage/Roborock/root.network.operationalPort +1 -0
  78. package/.matterbridge/matterstorage/Roborock/root.operationalCredentials.commissionedFabrics +1 -0
  79. package/.matterbridge/matterstorage/Roborock/root.operationalCredentials.fabrics +1 -0
  80. package/.matterbridge/matterstorage/Roborock/root.operationalCredentials.nocs +1 -0
  81. package/.matterbridge/matterstorage/Roborock/root.operationalCredentials.trustedRootCertificates +1 -0
  82. package/.matterbridge/matterstorage/Roborock/root.parts.Roborock-R0514S03600279.__number__ +1 -0
  83. package/.matterbridge/matterstorage/Roborock/root.parts.Roborock-R0514S03600279.identify.identifyTime +1 -0
  84. package/.matterbridge/matterstorage/Roborock/root.parts.Roborock-R0514S03600279.rvcRunMode.__features__ +1 -0
  85. package/.matterbridge/matterstorage/Roborock/root.parts.Roborock-R0514S03600279.rvcRunMode.currentMode +1 -0
  86. package/.matterbridge/matterstorage/Roborock/root.productDescription.productId +1 -0
  87. package/.matterbridge/matterstorage/Roborock/root.productDescription.vendorId +1 -0
  88. package/.matterbridge/matterstorage/Roborock/root.subscription.subscriptions +1 -0
  89. package/.matterbridge/matterstorage/Roborock/sessions.resumptionRecords +1 -0
  90. package/.matterbridge/storage/.matterbridge/92cd10e6b8b068a931196d1d73a032543d5ca1a5bf445e27a1af74258254517c +1 -1
  91. package/.matterbridge/storage/.matterbridge/e3e931e87ead058805e8517be81328fbf7b0e04c5d78abdd4ca713df24d773fb +1 -1
  92. package/.matterbridge/storage/.matterbridge/e8f5b65c0535f90fae75a1c5e080593fdc2a490e22d5e21ea67a88cea7c1d794 +1 -1
  93. package/.matterbridge/storage/.matterbridge-plugin-lightwaverf/5ca4f3850ccc331aaf8a257d6086e526a3b42a63e18cb11d020847985b31d188 +1 -1
  94. package/.matterbridge/storage/.matterbridge-xiaomi-roborock/1303c06b0b014d0ce7b988ab173a13f31227d417058ff4bbe6f8c222b4ad913c +1 -0
  95. package/.matterbridge/storage/.matterbridge-xiaomi-roborock/5ca4f3850ccc331aaf8a257d6086e526a3b42a63e18cb11d020847985b31d188 +1 -0
  96. package/.matterbridge/storage/.matterbridge-xiaomi-roborock/636485868971eac5aca33c4a0e1800a8a11d980bcf0e3776b31002e2c5db91b2 +1 -0
  97. package/.matterbridge/storage/.matterbridge-xiaomi-roborock/82a3537ff0dbce7eec35d69edc3a189ee6f17d82f353a553f9aa96cb0be3ce89 +1 -0
  98. package/.matterbridge/storage/.matterbridge-xiaomi-roborock/a0af9f865bf637e6736817f4ce552e4cdf7b8c36ea75bc254c1d1f0af744b5bf +1 -0
  99. package/.matterbridge/storage/.matterbridge-xiaomi-roborock/c9046f7a37ad0ea7cee73355984fa5428982f8b37c8f7bcec91f7ac71a7cd104 +1 -0
  100. package/.matterbridge/storage/0d0a2ac6163e36f3f2349c77671004edfe3d5e1abbef93cbb583acec8d01481b +1 -1
  101. package/README.md +192 -56
  102. package/dist/module.d.ts.map +1 -0
  103. package/dist/module.js +70 -17
  104. package/dist/module.js.map +1 -0
  105. package/matterbridge-plugin-lightwaverf.schema.json +36 -0
  106. package/package.json +6 -6
  107. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.2-2.onOff.__features__ +0 -1
  108. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-2.levelControl.__features__ +0 -1
  109. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-2.levelControl.currentLevel +0 -1
  110. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-2.onOff.__features__ +0 -1
  111. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-3.levelControl.__features__ +0 -1
  112. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-3.levelControl.currentLevel +0 -1
  113. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-3.onOff.__features__ +0 -1
  114. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-4.onOff.__features__ +0 -1
  115. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.3-4.onOff.onOff +0 -1
  116. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.4-2.onOff.__features__ +0 -1
  117. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.4-2.onOff.onOff +0 -1
  118. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-1.onOff.__features__ +0 -1
  119. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-1.onOff.onOff +0 -1
  120. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-2.onOff.__features__ +0 -1
  121. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.8-2.onOff.onOff +0 -1
  122. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.9-1.onOff.__features__ +0 -1
  123. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.9-1.onOff.onOff +0 -1
  124. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.UpdateMatterbridge%3Aoutlet.onOff.__features__ +0 -1
  125. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.UpdateMatterbridge%3Aoutlet.onOff.onOff +0 -1
  126. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.dimmer1.__number__ +0 -1
  127. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.dimmer1.levelControl.__features__ +0 -1
  128. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.dimmer1.levelControl.currentLevel +0 -1
  129. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.dimmer1.onOff.__features__ +0 -1
  130. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.dimmer1.onOff.onOff +0 -1
  131. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.outlet1.__number__ +0 -1
  132. package/.matterbridge/matterstorage/Matterbridge/root.parts.Matterbridge.parts.registerButton1.__number__ +0 -1
  133. /package/.matterbridge/matterstorage/Matterbridge/{root.parts.Matterbridge.parts.11-1.onOff.__features__ → root.parts.Matterbridge.parts.2-3.onOff.__features__} +0 -0
  134. /package/.matterbridge/matterstorage/Matterbridge/{root.parts.Matterbridge.parts.11-1.onOff.onOff → root.parts.Matterbridge.parts.2-3.onOff.onOff} +0 -0
  135. /package/.matterbridge/matterstorage/{Matterbridge/root.parts.Matterbridge.parts.3-3.onOff.onOff → Roborock/root.commissioning.commissioned} +0 -0
  136. /package/.matterbridge/matterstorage/{Matterbridge/root.parts.Matterbridge.parts.2-2.onOff.onOff → Roborock/root.network.ble} +0 -0
  137. /package/.matterbridge/matterstorage/{Matterbridge/root.parts.Matterbridge.parts.3-2.onOff.onOff → Roborock/root.parts.Roborock-R0514S03600279.identify.isIdentifying} +0 -0
@@ -0,0 +1,741 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" translate="no">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="google" content="notranslate" />
7
+ <meta http-equiv="Content-Language" content="en" />
8
+ <title>Matterbridge Cpu &amp; Memory History</title>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
12
+ <style>
13
+ :root {
14
+ color-scheme: dark light;
15
+ --bg: #0f172a;
16
+ --bg-card: rgba(15, 23, 42, 0.72);
17
+ --fg: #e2e8f0;
18
+ --accent: #38bdf8;
19
+ --muted: #94a3b8;
20
+ --border: rgba(148, 163, 184, 0.2);
21
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
22
+ }
23
+ body {
24
+ margin: 0;
25
+ padding: 20px;
26
+ background: linear-gradient(145deg, #020617, #0f172a);
27
+ color: var(--fg);
28
+ min-width: 320px;
29
+ min-height: 100vh;
30
+ }
31
+ h1 {
32
+ margin-top: 0;
33
+ font-size: clamp(1.4rem, 1.8vw, 2.0rem);
34
+ font-weight: 700;
35
+ color: var(--accent);
36
+ }
37
+ .container {
38
+ min-width: 320px;
39
+ max-width: 1240px;
40
+ margin: 0 auto;
41
+ padding: 0;
42
+ display: grid;
43
+ gap: 20px;
44
+ }
45
+ .card {
46
+ background: var(--bg-card);
47
+ border: 1px solid var(--border);
48
+ border-radius: 16px;
49
+ padding: 20px;
50
+ box-shadow: 0 20px 60px rgba(15, 23, 42, 0.35);
51
+ backdrop-filter: blur(12px);
52
+ margin: 0;
53
+ width: calc(100% - 40px);
54
+ max-width: 1200px;
55
+ position: relative;
56
+ overflow: hidden;
57
+ }
58
+ .summary-grid {
59
+ display: grid;
60
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
61
+ gap: 16px;
62
+ }
63
+ .summary-item {
64
+ border: 1px solid var(--border);
65
+ border-radius: 12px;
66
+ padding: 16px;
67
+ background: rgba(30, 41, 59, 0.85);
68
+ }
69
+ .summary-item h2 {
70
+ margin: 0 0 8px;
71
+ font-size: 0.95rem;
72
+ text-transform: uppercase;
73
+ letter-spacing: 0.08em;
74
+ color: var(--muted);
75
+ }
76
+ .summary-item p {
77
+ margin: 0;
78
+ font-size: 1.25rem;
79
+ font-weight: 600;
80
+ }
81
+ canvas {
82
+ width: min(100%, 1200px);
83
+ height: 320px;
84
+ display: block;
85
+ margin: 0 auto;
86
+ }
87
+ .chart-legend {
88
+ display: flex;
89
+ flex-wrap: wrap;
90
+ gap: 12px;
91
+ margin-top: 16px;
92
+ font-size: 0.85rem;
93
+ color: var(--muted);
94
+ }
95
+ .chart-legend span {
96
+ display: inline-flex;
97
+ align-items: center;
98
+ gap: 8px;
99
+ }
100
+ .chart-legend span::before {
101
+ content: '';
102
+ width: 12px;
103
+ height: 12px;
104
+ border-radius: 999px;
105
+ background: currentColor;
106
+ opacity: 0.85;
107
+ border: 1px solid rgba(255, 255, 255, 0.4);
108
+ }
109
+ table {
110
+ width: 100%;
111
+ border-collapse: collapse;
112
+ font-size: 0.95rem;
113
+ }
114
+ th, td {
115
+ padding: 8px;
116
+ border-bottom: 1px solid var(--border);
117
+ text-align: left;
118
+ white-space: nowrap;
119
+ }
120
+ th {
121
+ text-transform: uppercase;
122
+ font-size: 0.75rem;
123
+ letter-spacing: 0.08em;
124
+ color: var(--muted);
125
+ }
126
+ td {
127
+ font-size: 0.75rem;
128
+ }
129
+ tr:hover {
130
+ background: rgba(148, 163, 184, 0.08);
131
+ }
132
+ .table-wrapper {
133
+ overflow: auto;
134
+ max-height: 400px;
135
+ scrollbar-color: rgba(148, 163, 184, 0.35) var(--bg-card);
136
+ scrollbar-width: thin;
137
+ }
138
+ .table-wrapper::-webkit-scrollbar {
139
+ width: 10px;
140
+ }
141
+ .table-wrapper::-webkit-scrollbar-track {
142
+ background: var(--bg-card);
143
+ }
144
+ .table-wrapper::-webkit-scrollbar-thumb {
145
+ background-color: rgba(148, 163, 184, 0.45);
146
+ border-radius: 999px;
147
+ border: 2px solid var(--bg-card);
148
+ }
149
+ @media (max-width: 720px) {
150
+ body {
151
+ padding: 16px;
152
+ }
153
+ .card {
154
+ padding: 18px;
155
+ }
156
+ }
157
+ </style>
158
+ </head>
159
+ <body>
160
+ <div class="container">
161
+ <header>
162
+ <h1>Matterbridge Cpu &amp; Memory History</h1>
163
+ <p>Hostname: Stanislaws-MacBook-Pro.local</p>
164
+ <p>Generated: 11/9/2025, 7:48:39 PM</p>
165
+ </header>
166
+
167
+ <section class="card">
168
+ <div class="summary-grid" id="summary"></div>
169
+ </section>
170
+
171
+ <section class="card">
172
+ <h2>Host CPU Usage (%)</h2>
173
+ <canvas id="cpuChart"></canvas>
174
+ </section>
175
+
176
+ <section class="card">
177
+ <h2>Process CPU Usage (%)</h2>
178
+ <canvas id="processCpuChart"></canvas>
179
+ </section>
180
+
181
+ <section class="card">
182
+ <h2>Memory Usage (MB)</h2>
183
+ <canvas id="memoryChart"></canvas>
184
+ </section>
185
+
186
+ <section class="card">
187
+ <h2>External and Array Buffers (MB)</h2>
188
+ <canvas id="extArrayChart"></canvas>
189
+ </section>
190
+
191
+ <section class="card">
192
+ <h2>Samples</h2>
193
+ <div class="table-wrapper">
194
+ <table>
195
+ <thead>
196
+ <tr>
197
+ <th>Timestamp</th>
198
+ <th>Host CPU %</th>
199
+ <th title="Host CPU Peak">Peak %</th>
200
+ <th>Process CPU %</th>
201
+ <th title="Process CPU Peak">Peak %</th>
202
+ <th>RSS (MB)</th>
203
+ <th title="RSS Peak">Peak MB</th>
204
+ <th>Heap Used (MB)</th>
205
+ <th title="Heap Used Peak">Peak MB</th>
206
+ <th>Heap Total (MB)</th>
207
+ <th title="Heap Total Peak">Peak MB</th>
208
+ </tr>
209
+ </thead>
210
+ <tbody id="historyTable"></tbody>
211
+ </table>
212
+ </div>
213
+ </section>
214
+ </div>
215
+
216
+ <script type="module">
217
+ const HISTORY_DATA = [{"timestamp":1762717516145,"freeMemory":38163939328,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":40.47,"peakOsCpu":40.47,"processCpu":1.74,"peakProcessCpu":1.74,"rss":212828160,"peakRss":212828160,"heapUsed":99421136,"peakHeapUsed":99421136,"heapTotal":126484480,"peakHeapTotal":126484480,"external":3924208,"peakExternal":3924208,"arrayBuffers":207181,"peakArrayBuffers":207181},{"timestamp":1762717526147,"freeMemory":37908840448,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":31.75,"peakOsCpu":40.47,"processCpu":0.07,"peakProcessCpu":1.74,"rss":214908928,"peakRss":214908928,"heapUsed":92811880,"peakHeapUsed":99421136,"heapTotal":96337920,"peakHeapTotal":126484480,"external":3822892,"peakExternal":3924208,"arrayBuffers":105865,"peakArrayBuffers":207181},{"timestamp":1762717536149,"freeMemory":37452791808,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":34.81,"peakOsCpu":40.47,"processCpu":0.37,"peakProcessCpu":1.74,"rss":170131456,"peakRss":214908928,"heapUsed":78840864,"peakHeapUsed":99421136,"heapTotal":83230720,"peakHeapTotal":126484480,"external":3818927,"peakExternal":3924208,"arrayBuffers":87424,"peakArrayBuffers":207181},{"timestamp":1762717546150,"freeMemory":36964368384,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":32.16,"peakOsCpu":40.47,"processCpu":0.31,"peakProcessCpu":1.74,"rss":185384960,"peakRss":214908928,"heapUsed":83153368,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3815167,"peakExternal":3924208,"arrayBuffers":98220,"peakArrayBuffers":207181},{"timestamp":1762717556151,"freeMemory":36863361024,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":26.66,"peakOsCpu":40.47,"processCpu":0.02,"peakProcessCpu":1.74,"rss":185384960,"peakRss":214908928,"heapUsed":82746936,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3812488,"peakExternal":3924208,"arrayBuffers":95541,"peakArrayBuffers":207181},{"timestamp":1762717566152,"freeMemory":36649730048,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":29.34,"peakOsCpu":40.47,"processCpu":0.05,"peakProcessCpu":1.74,"rss":185384960,"peakRss":214908928,"heapUsed":82737024,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3810638,"peakExternal":3924208,"arrayBuffers":93691,"peakArrayBuffers":207181},{"timestamp":1762717576153,"freeMemory":36630003712,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":28.17,"peakOsCpu":40.47,"processCpu":0.05,"peakProcessCpu":1.74,"rss":185384960,"peakRss":214908928,"heapUsed":83227800,"peakHeapUsed":99421136,"heapTotal":90832896,"peakHeapTotal":126484480,"external":3824490,"peakExternal":3924208,"arrayBuffers":107543,"peakArrayBuffers":207181},{"timestamp":1762717586153,"freeMemory":36500733952,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":33.84,"peakOsCpu":40.47,"processCpu":0.05,"peakProcessCpu":1.74,"rss":185384960,"peakRss":214908928,"heapUsed":82645248,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3829166,"peakExternal":3924208,"arrayBuffers":99221,"peakArrayBuffers":207181},{"timestamp":1762717596154,"freeMemory":36164354048,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":43.97,"peakOsCpu":43.97,"processCpu":0.01,"peakProcessCpu":1.74,"rss":185417728,"peakRss":214908928,"heapUsed":83387304,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3828938,"peakExternal":3924208,"arrayBuffers":111991,"peakArrayBuffers":207181},{"timestamp":1762717606155,"freeMemory":36463820800,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":36.97,"peakOsCpu":43.97,"processCpu":0.01,"peakProcessCpu":1.74,"rss":185434112,"peakRss":214908928,"heapUsed":83302512,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3829306,"peakExternal":3924208,"arrayBuffers":112359,"peakArrayBuffers":207181},{"timestamp":1762717616156,"freeMemory":35951788032,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":25.3,"peakOsCpu":43.97,"processCpu":0.02,"peakProcessCpu":1.74,"rss":185434112,"peakRss":214908928,"heapUsed":82663024,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3833282,"peakExternal":3924208,"arrayBuffers":99221,"peakArrayBuffers":207181},{"timestamp":1762717626156,"freeMemory":35742203904,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":26.61,"peakOsCpu":43.97,"processCpu":0.05,"peakProcessCpu":1.74,"rss":185450496,"peakRss":214908928,"heapUsed":82700032,"peakHeapUsed":99421136,"heapTotal":89784320,"peakHeapTotal":126484480,"external":3830114,"peakExternal":3924208,"arrayBuffers":99221,"peakArrayBuffers":207181},{"timestamp":1762717636157,"freeMemory":35591749632,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":42.5,"peakOsCpu":43.97,"processCpu":0.03,"peakProcessCpu":1.74,"rss":185466880,"peakRss":214908928,"heapUsed":83551824,"peakHeapUsed":99421136,"heapTotal":90832896,"peakHeapTotal":126484480,"external":3829326,"peakExternal":3924208,"arrayBuffers":112379,"peakArrayBuffers":207181},{"timestamp":1762717646157,"freeMemory":34653339648,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":33.08,"peakOsCpu":43.97,"processCpu":0.33,"peakProcessCpu":1.74,"rss":201867264,"peakRss":214908928,"heapUsed":89353448,"peakHeapUsed":99421136,"heapTotal":113311744,"peakHeapTotal":126484480,"external":5174193,"peakExternal":5174193,"arrayBuffers":1459636,"peakArrayBuffers":1459636},{"timestamp":1762717656159,"freeMemory":34647752704,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":24.61,"peakOsCpu":43.97,"processCpu":0.31,"peakProcessCpu":1.74,"rss":179879936,"peakRss":214908928,"heapUsed":80826824,"peakHeapUsed":99421136,"heapTotal":85786624,"peakHeapTotal":126484480,"external":3806050,"peakExternal":5174193,"arrayBuffers":94601,"peakArrayBuffers":1459636},{"timestamp":1762717666161,"freeMemory":34669461504,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":23.01,"peakOsCpu":43.97,"processCpu":0.09,"peakProcessCpu":1.74,"rss":181518336,"peakRss":214908928,"heapUsed":81092248,"peakHeapUsed":99421136,"heapTotal":85786624,"peakHeapTotal":126484480,"external":3809974,"peakExternal":5174193,"arrayBuffers":98525,"peakArrayBuffers":1459636},{"timestamp":1762717676161,"freeMemory":34626207744,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":26,"peakOsCpu":43.97,"processCpu":0.05,"peakProcessCpu":1.74,"rss":181534720,"peakRss":214908928,"heapUsed":81139696,"peakHeapUsed":99421136,"heapTotal":85786624,"peakHeapTotal":126484480,"external":3809300,"peakExternal":5174193,"arrayBuffers":97851,"peakArrayBuffers":1459636},{"timestamp":1762717686165,"freeMemory":34651619328,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":24.37,"peakOsCpu":43.97,"processCpu":0.04,"peakProcessCpu":1.74,"rss":181551104,"peakRss":214908928,"heapUsed":80750304,"peakHeapUsed":99421136,"heapTotal":85786624,"peakHeapTotal":126484480,"external":3804178,"peakExternal":5174193,"arrayBuffers":92729,"peakArrayBuffers":1459636},{"timestamp":1762717696167,"freeMemory":34586427392,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":24.36,"peakOsCpu":43.97,"processCpu":0.15,"peakProcessCpu":1.74,"rss":183697408,"peakRss":214908928,"heapUsed":82019552,"peakHeapUsed":99421136,"heapTotal":87359488,"peakHeapTotal":126484480,"external":3821932,"peakExternal":5174193,"arrayBuffers":110483,"peakArrayBuffers":1459636},{"timestamp":1762717706168,"freeMemory":34500837376,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":24.21,"peakOsCpu":43.97,"processCpu":0.04,"peakProcessCpu":1.74,"rss":183697408,"peakRss":214908928,"heapUsed":81596224,"peakHeapUsed":99421136,"heapTotal":86310912,"peakHeapTotal":126484480,"external":3818886,"peakExternal":5174193,"arrayBuffers":107437,"peakArrayBuffers":1459636},{"timestamp":1762717716169,"freeMemory":34636136448,"peakFreeMemory":38163939328,"totalMemory":68719476736,"peakTotalMemory":68719476736,"osCpu":22.78,"peakOsCpu":43.97,"processCpu":0.1,"peakProcessCpu":1.74,"rss":184532992,"peakRss":214908928,"heapUsed":82551912,"peakHeapUsed":99421136,"heapTotal":86835200,"peakHeapTotal":126484480,"external":3847348,"peakExternal":5174193,"arrayBuffers":135819,"peakArrayBuffers":1459636}];
218
+ const SUMMARY_DATA = {"entries":21,"timeRange":"11/9/2025, 7:45:16 PM → 11/9/2025, 7:48:36 PM","peakOsCpu":43.97,"peakProcessCpu":1.74,"peakRss":214908928,"peakHeapUsed":99421136,"peakHeapTotal":126484480,"peakExternal":5174193,"peakArrayBuffers":1459636};
219
+ let cleanup = () => {};
220
+
221
+ const summaryContainer = document.getElementById('summary');
222
+ const summaryEntries = [
223
+ { label: 'Samples', value: SUMMARY_DATA.entries.toLocaleString() },
224
+ { label: 'Time Range', value: SUMMARY_DATA.timeRange },
225
+ { label: 'Host CPU Peak', value: SUMMARY_DATA.peakOsCpu.toFixed(2) + ' %' },
226
+ { label: 'Process CPU Peak', value: SUMMARY_DATA.peakProcessCpu.toFixed(2) + ' %' },
227
+ { label: 'RSS Peak', value: formatBytes(SUMMARY_DATA.peakRss) },
228
+ { label: 'Heap Used Peak', value: formatBytes(SUMMARY_DATA.peakHeapUsed) },
229
+ { label: 'Heap Total Peak', value: formatBytes(SUMMARY_DATA.peakHeapTotal) },
230
+ { label: 'External Peak', value: formatBytes(SUMMARY_DATA.peakExternal) },
231
+ { label: 'Array Buffers Peak', value: formatBytes(SUMMARY_DATA.peakArrayBuffers) }
232
+ ];
233
+
234
+ summaryEntries.forEach(function (itemData) {
235
+ const item = document.createElement('div');
236
+ item.className = 'summary-item';
237
+ item.innerHTML = '<h2>' + itemData.label + '</h2><p>' + itemData.value + '</p>';
238
+ summaryContainer.appendChild(item);
239
+ });
240
+
241
+ const tableBody = document.getElementById('historyTable');
242
+ HISTORY_DATA.forEach(function (entry) {
243
+ const row = document.createElement('tr');
244
+ const cells = [
245
+ new Date(entry.timestamp).toLocaleString(),
246
+ entry.osCpu.toFixed(2),
247
+ entry.peakOsCpu.toFixed(2),
248
+ (Number.isFinite(entry.processCpu) ? entry.processCpu : 0).toFixed(2),
249
+ (
250
+ Number.isFinite(entry.peakProcessCpu)
251
+ ? entry.peakProcessCpu
252
+ : Number.isFinite(entry.processCpu)
253
+ ? entry.processCpu
254
+ : 0
255
+ ).toFixed(2),
256
+ bytesToMb(entry.rss).toFixed(2),
257
+ bytesToMb(entry.peakRss).toFixed(2),
258
+ bytesToMb(entry.heapUsed).toFixed(2),
259
+ bytesToMb(entry.peakHeapUsed).toFixed(2),
260
+ bytesToMb(entry.heapTotal).toFixed(2),
261
+ bytesToMb(entry.peakHeapTotal).toFixed(2)
262
+ ];
263
+ row.innerHTML = '<td>' + cells.join('</td><td>') + '</td>';
264
+ tableBody.appendChild(row);
265
+ });
266
+
267
+ const labels = HISTORY_DATA.map(function (entry) {
268
+ return formatTimestamp(entry.timestamp);
269
+ });
270
+
271
+ const cpuPeakValue = HISTORY_DATA.reduce(function (acc, entry) {
272
+ return Math.max(acc, Number.isFinite(entry.peakOsCpu) ? entry.peakOsCpu : 0, Number.isFinite(entry.osCpu) ? entry.osCpu : 0);
273
+ }, 0);
274
+ const cpuMaxYAxis = cpuPeakValue > 0 ? cpuPeakValue * 1.05 : undefined;
275
+
276
+ const processCpuPeakValue = HISTORY_DATA.reduce(function (acc, entry) {
277
+ return Math.max(acc, Number.isFinite(entry.peakProcessCpu) ? entry.peakProcessCpu : 0, Number.isFinite(entry.processCpu) ? entry.processCpu : 0);
278
+ }, 0);
279
+ const processCpuMaxYAxis = processCpuPeakValue > 0 ? processCpuPeakValue * 1.05 : undefined;
280
+ const useProcessCpuDecimals = (processCpuMaxYAxis ?? 0) <= 3;
281
+
282
+ // Compute memory chart dynamic minimum Y as (min observed MB) - 10%
283
+ const memoryMinMb = HISTORY_DATA.reduce(function (acc, entry) {
284
+ const values = [entry.rss, entry.heapTotal, entry.heapUsed].map(bytesToMb);
285
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
286
+ const minEntry = finiteValues.length ? Math.min.apply(Math, finiteValues) : acc;
287
+ return Math.min(acc, minEntry);
288
+ }, Number.POSITIVE_INFINITY);
289
+ const memoryMinYAxis = Number.isFinite(memoryMinMb) && memoryMinMb > 0 ? Math.max(0, memoryMinMb - memoryMinMb * 0.1) : 0;
290
+
291
+ // Compute memory chart dynamic maximum Y as (max observed MB including peaks) + 5%
292
+ const memoryMaxMb = HISTORY_DATA.reduce(function (acc, entry) {
293
+ const values = [
294
+ entry.rss,
295
+ entry.heapTotal,
296
+ entry.heapUsed,
297
+ entry.peakRss,
298
+ entry.peakHeapTotal,
299
+ entry.peakHeapUsed
300
+ ].map(bytesToMb);
301
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
302
+ const maxEntry = finiteValues.length ? Math.max.apply(Math, finiteValues) : acc;
303
+ return Math.max(acc, maxEntry);
304
+ }, 0);
305
+ const memoryMaxYAxis = Number.isFinite(memoryMaxMb) && memoryMaxMb > 0 ? memoryMaxMb * 1.05 : undefined;
306
+
307
+ // Compute External/ArrayBuffers chart dynamic min/max
308
+ const extArrayMinMb = HISTORY_DATA.reduce(function (acc, entry) {
309
+ const values = [entry.external, entry.arrayBuffers].map(bytesToMb);
310
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
311
+ const minEntry = finiteValues.length ? Math.min.apply(Math, finiteValues) : acc;
312
+ return Math.min(acc, minEntry);
313
+ }, Number.POSITIVE_INFINITY);
314
+
315
+ const extArrayMinYAxis = Number.isFinite(extArrayMinMb) && extArrayMinMb > 0
316
+ ? Math.max(0, extArrayMinMb - extArrayMinMb * 0.1)
317
+ : 0;
318
+
319
+ const extArrayMaxMb = HISTORY_DATA.reduce(function (acc, entry) {
320
+ const values = [
321
+ entry.external,
322
+ entry.arrayBuffers,
323
+ entry.peakExternal,
324
+ entry.peakArrayBuffers,
325
+ ].map(bytesToMb);
326
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
327
+ const maxEntry = finiteValues.length ? Math.max.apply(Math, finiteValues) : acc;
328
+ return Math.max(acc, maxEntry);
329
+ }, 0);
330
+ const extArrayMaxYAxis = Number.isFinite(extArrayMaxMb) && extArrayMaxMb > 0 ? extArrayMaxMb * 1.05 : undefined;
331
+
332
+ renderCharts();
333
+
334
+ function renderCharts() {
335
+ cleanup();
336
+
337
+ function draw() {
338
+ renderLineChart('cpuChart', {
339
+ labels: labels,
340
+ datasets: [
341
+ {
342
+ label: 'Host CPU %',
343
+ values: HISTORY_DATA.map(function (entry) {
344
+ return Number.isFinite(entry.osCpu) ? Number(entry.osCpu.toFixed(2)) : 0;
345
+ }),
346
+ color: '#38bdf8',
347
+ fill: 'rgba(56, 189, 248, 0.18)',
348
+ markPeaks: true,
349
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
350
+ if (Number.isFinite(entry.peakOsCpu)) return entry.peakOsCpu;
351
+ if (Number.isFinite(entry.osCpu)) return entry.osCpu;
352
+ return Number.NEGATIVE_INFINITY;
353
+ }),
354
+ markerRadius: 2.5
355
+ },
356
+ {
357
+ label: 'Host Peak CPU %',
358
+ values: HISTORY_DATA.map(function (entry) {
359
+ return Number.isFinite(entry.peakOsCpu) ? Number(entry.peakOsCpu.toFixed(2)) : 0;
360
+ }),
361
+ color: '#facc15',
362
+ dashed: [6, 4]
363
+ }
364
+ ],
365
+ minY: 0,
366
+ maxY: cpuMaxYAxis,
367
+ yFormatter: function (value) {
368
+ return value.toFixed(0) + ' %';
369
+ }
370
+ });
371
+
372
+ renderLineChart('processCpuChart', {
373
+ labels: labels,
374
+ datasets: [
375
+ {
376
+ label: 'Process CPU %',
377
+ values: HISTORY_DATA.map(function (entry) {
378
+ return Number.isFinite(entry.processCpu) ? Number(entry.processCpu.toFixed(2)) : 0;
379
+ }),
380
+ color: '#a855f7',
381
+ fill: 'rgba(168, 85, 247, 0.18)',
382
+ markPeaks: true,
383
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
384
+ if (Number.isFinite(entry.peakProcessCpu)) return entry.peakProcessCpu;
385
+ if (Number.isFinite(entry.processCpu)) return entry.processCpu;
386
+ return Number.NEGATIVE_INFINITY;
387
+ }),
388
+ markerRadius: 2.5
389
+ },
390
+ {
391
+ label: 'Process Peak CPU %',
392
+ values: HISTORY_DATA.map(function (entry) {
393
+ if (Number.isFinite(entry.peakProcessCpu)) {
394
+ return Number(entry.peakProcessCpu.toFixed(2));
395
+ }
396
+ if (Number.isFinite(entry.processCpu)) {
397
+ return Number(entry.processCpu.toFixed(2));
398
+ }
399
+ return 0;
400
+ }),
401
+ color: '#f97316',
402
+ dashed: [6, 4]
403
+ }
404
+ ],
405
+ minY: 0,
406
+ maxY: processCpuMaxYAxis,
407
+ yFormatter: function (value) {
408
+ return value.toFixed(useProcessCpuDecimals ? 1 : 0) + ' %';
409
+ }
410
+ });
411
+
412
+ renderLineChart('memoryChart', {
413
+ labels: labels,
414
+ datasets: [
415
+ {
416
+ label: 'RSS (MB)',
417
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.rss); }),
418
+ color: '#34d399',
419
+ fill: 'rgba(52, 211, 153, 0.18)',
420
+ markPeaks: true,
421
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
422
+ if (Number.isFinite(entry.peakRss)) return entry.peakRss;
423
+ if (Number.isFinite(entry.rss)) return entry.rss;
424
+ return Number.NEGATIVE_INFINITY;
425
+ }),
426
+ markerRadius: 2.5
427
+ },
428
+ {
429
+ label: 'Heap Total (MB)',
430
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.heapTotal); }),
431
+ color: '#fb923c',
432
+ markPeaks: true,
433
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
434
+ if (Number.isFinite(entry.peakHeapTotal)) return entry.peakHeapTotal;
435
+ if (Number.isFinite(entry.heapTotal)) return entry.heapTotal;
436
+ return Number.NEGATIVE_INFINITY;
437
+ }),
438
+ markerRadius: 2.5
439
+ },
440
+ {
441
+ label: 'Heap Used (MB)',
442
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.heapUsed); }),
443
+ color: '#f472b6',
444
+ markPeaks: true,
445
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
446
+ if (Number.isFinite(entry.peakHeapUsed)) return entry.peakHeapUsed;
447
+ if (Number.isFinite(entry.heapUsed)) return entry.heapUsed;
448
+ return Number.NEGATIVE_INFINITY;
449
+ }),
450
+ markerRadius: 2.5
451
+ }
452
+ ],
453
+ minY: memoryMinYAxis,
454
+ maxY: memoryMaxYAxis,
455
+ yFormatter: function (value) {
456
+ return value.toFixed(0) + ' MB';
457
+ }
458
+ });
459
+
460
+ // External and Array Buffers chart
461
+ renderLineChart('extArrayChart', {
462
+ labels: labels,
463
+ datasets: [
464
+ {
465
+ label: 'External (MB)',
466
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.external); }),
467
+ color: '#60a5fa',
468
+ fill: 'rgba(96, 165, 250, 0.18)',
469
+ markPeaks: true,
470
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
471
+ if (Number.isFinite(entry.peakExternal)) return entry.peakExternal;
472
+ if (Number.isFinite(entry.external)) return entry.external;
473
+ return Number.NEGATIVE_INFINITY;
474
+ }),
475
+ markerRadius: 2.5
476
+ },
477
+ {
478
+ label: 'Array Buffers (MB)',
479
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.arrayBuffers); }),
480
+ color: '#22d3ee',
481
+ markPeaks: true,
482
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
483
+ if (Number.isFinite(entry.peakArrayBuffers)) return entry.peakArrayBuffers;
484
+ if (Number.isFinite(entry.arrayBuffers)) return entry.arrayBuffers;
485
+ return Number.NEGATIVE_INFINITY;
486
+ }),
487
+ markerRadius: 2.5
488
+ }
489
+ ],
490
+ minY: extArrayMinYAxis,
491
+ maxY: extArrayMaxYAxis,
492
+ yFormatter: function (value) {
493
+ return value.toFixed(0) + ' MB';
494
+ }
495
+ });
496
+ }
497
+
498
+ draw();
499
+
500
+ const debouncedRender = debounce(draw, 150);
501
+ window.addEventListener('resize', debouncedRender);
502
+
503
+ cleanup = function () {
504
+ window.removeEventListener('resize', debouncedRender);
505
+ };
506
+ }
507
+
508
+ function renderLineChart(canvasId, config) {
509
+ const canvas = document.getElementById(canvasId);
510
+ if (!canvas) {
511
+ return;
512
+ }
513
+
514
+ const parent = canvas.parentElement;
515
+ if (parent) {
516
+ const existingLegend = parent.querySelector('.chart-legend');
517
+ if (existingLegend) {
518
+ existingLegend.remove();
519
+ }
520
+ }
521
+
522
+ const parentWidth = parent && parent.clientWidth ? parent.clientWidth : canvas.clientWidth || 720;
523
+ const cssHeight = canvas.dataset.height ? Number(canvas.dataset.height) : 320;
524
+ const dpr = window.devicePixelRatio || 1;
525
+
526
+ canvas.width = parentWidth * dpr;
527
+ canvas.height = cssHeight * dpr;
528
+ canvas.style.width = '100%';
529
+ canvas.style.height = cssHeight + 'px';
530
+
531
+ const ctx = canvas.getContext('2d');
532
+ if (!ctx) {
533
+ return;
534
+ }
535
+
536
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
537
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
538
+ ctx.scale(dpr, dpr);
539
+
540
+ const margin = { top: 20, right: 24, bottom: 48, left: 72 };
541
+ const innerWidth = Math.max(10, parentWidth - margin.left - margin.right);
542
+ const innerHeight = Math.max(10, cssHeight - margin.top - margin.bottom);
543
+
544
+ ctx.translate(margin.left, margin.top);
545
+
546
+ const allValues = [];
547
+ config.datasets.forEach(function (dataset) {
548
+ dataset.values.forEach(function (value) {
549
+ if (Number.isFinite(value)) {
550
+ allValues.push(value);
551
+ }
552
+ });
553
+ });
554
+
555
+ let minY = typeof config.minY === 'number' ? config.minY : Math.min.apply(Math, allValues);
556
+ let maxY = typeof config.maxY === 'number' ? config.maxY : Math.max.apply(Math, allValues);
557
+
558
+ if (!Number.isFinite(minY) || !Number.isFinite(maxY)) {
559
+ minY = 0;
560
+ maxY = 1;
561
+ }
562
+
563
+ if (minY === maxY) {
564
+ const padding = Math.abs(minY) * 0.05 || 1;
565
+ minY -= padding;
566
+ maxY += padding;
567
+ }
568
+
569
+ const valueRange = maxY - minY;
570
+ const gridLines = config.yTicks || 4;
571
+
572
+ ctx.lineWidth = 1;
573
+ ctx.font = '12px Inter, sans-serif';
574
+ ctx.textAlign = 'right';
575
+ ctx.textBaseline = 'middle';
576
+ ctx.fillStyle = '#94a3b8';
577
+
578
+ for (let i = 0; i <= gridLines; i += 1) {
579
+ const ratio = i / gridLines;
580
+ const y = innerHeight - ratio * innerHeight;
581
+ ctx.strokeStyle = 'rgba(148, 163, 184, 0.12)';
582
+ ctx.beginPath();
583
+ ctx.moveTo(0, y);
584
+ ctx.lineTo(innerWidth, y);
585
+ ctx.stroke();
586
+
587
+ const value = minY + ratio * valueRange;
588
+ const label = config.yFormatter ? config.yFormatter(value) : value.toFixed(1);
589
+ ctx.fillText(label, -12, y);
590
+ }
591
+
592
+ const xCount = config.labels.length;
593
+ const xTicks = config.xTickCount || Math.min(6, xCount);
594
+ const xStep = xCount > 1 ? Math.max(1, Math.floor(xCount / xTicks)) : 1;
595
+
596
+ ctx.textAlign = 'center';
597
+ ctx.textBaseline = 'top';
598
+
599
+ for (let i = 0; i < xCount; i += xStep) {
600
+ const x = xCount === 1 ? innerWidth / 2 : (i / (xCount - 1)) * innerWidth;
601
+ ctx.strokeStyle = 'rgba(148, 163, 184, 0.08)';
602
+ ctx.beginPath();
603
+ ctx.moveTo(x, 0);
604
+ ctx.lineTo(x, innerHeight);
605
+ ctx.stroke();
606
+
607
+ ctx.save();
608
+ ctx.translate(x, innerHeight + 14);
609
+ ctx.rotate(-Math.PI / 8);
610
+ ctx.fillStyle = '#94a3b8';
611
+ ctx.fillText(config.labels[i], 0, 0);
612
+ ctx.restore();
613
+ }
614
+
615
+ ctx.strokeStyle = 'rgba(148, 163, 184, 0.35)';
616
+ ctx.lineWidth = 1.2;
617
+ ctx.beginPath();
618
+ ctx.moveTo(0, 0);
619
+ ctx.lineTo(0, innerHeight);
620
+ ctx.lineTo(innerWidth, innerHeight);
621
+ ctx.stroke();
622
+
623
+ config.datasets.forEach(function (dataset) {
624
+ const points = dataset.values.map(function (value, index) {
625
+ const safeValue = Number.isFinite(value) ? value : minY;
626
+ const x = xCount === 1 ? innerWidth / 2 : (index / (xCount - 1)) * innerWidth;
627
+ const ratio = (safeValue - minY) / valueRange;
628
+ const y = innerHeight - ratio * innerHeight;
629
+ return { x: x, y: y };
630
+ });
631
+
632
+ if (dataset.fill && points.length > 1) {
633
+ ctx.fillStyle = dataset.fill;
634
+ ctx.beginPath();
635
+ points.forEach(function (point, pointIndex) {
636
+ if (pointIndex === 0) {
637
+ ctx.moveTo(point.x, point.y);
638
+ } else {
639
+ ctx.lineTo(point.x, point.y);
640
+ }
641
+ });
642
+ const last = points[points.length - 1];
643
+ const first = points[0];
644
+ ctx.lineTo(last.x, innerHeight);
645
+ ctx.lineTo(first.x, innerHeight);
646
+ ctx.closePath();
647
+ ctx.fill();
648
+ }
649
+
650
+ if (dataset.dashed) {
651
+ ctx.setLineDash(dataset.dashed);
652
+ } else {
653
+ ctx.setLineDash([]);
654
+ }
655
+ ctx.strokeStyle = dataset.color;
656
+ ctx.lineWidth = dataset.width || 2;
657
+ ctx.beginPath();
658
+ points.forEach(function (point, pointIndex) {
659
+ if (pointIndex === 0) {
660
+ ctx.moveTo(point.x, point.y);
661
+ } else {
662
+ ctx.lineTo(point.x, point.y);
663
+ }
664
+ });
665
+ ctx.stroke();
666
+ ctx.setLineDash([]);
667
+
668
+ // Draw new-peak markers if enabled
669
+ if (dataset.markPeaks) {
670
+ let runningMax = -Infinity;
671
+ const radius = Number.isFinite(dataset.markerRadius) ? dataset.markerRadius : 2.5;
672
+ ctx.save();
673
+ ctx.fillStyle = dataset.markerColor || dataset.color;
674
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.85)';
675
+ ctx.lineWidth = 1;
676
+ const peakSeries = Array.isArray(dataset.markerPeakValues) ? dataset.markerPeakValues : dataset.values;
677
+ peakSeries.forEach(function (value, idx) {
678
+ if (!Number.isFinite(value)) return;
679
+ if (value > runningMax) {
680
+ runningMax = value;
681
+ const p = points[idx];
682
+ ctx.beginPath();
683
+ ctx.arc(p.x, p.y, radius, 0, Math.PI * 2);
684
+ ctx.fill();
685
+ ctx.stroke();
686
+ }
687
+ });
688
+ ctx.restore();
689
+ }
690
+ });
691
+
692
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
693
+
694
+ if (parent) {
695
+ const legend = document.createElement('div');
696
+ legend.className = 'chart-legend';
697
+ config.datasets.forEach(function (dataset) {
698
+ const legendItem = document.createElement('span');
699
+ legendItem.style.color = dataset.color;
700
+ legendItem.textContent = dataset.label;
701
+ legend.appendChild(legendItem);
702
+ });
703
+ parent.appendChild(legend);
704
+ }
705
+ }
706
+
707
+ function formatTimestamp(timestamp) {
708
+ const date = new Date(timestamp);
709
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
710
+ }
711
+
712
+ function debounce(fn, delay) {
713
+ let timeout;
714
+ return function () {
715
+ const context = this;
716
+ const args = arguments;
717
+ clearTimeout(timeout);
718
+ timeout = setTimeout(function () {
719
+ fn.apply(context, args);
720
+ }, delay);
721
+ };
722
+ }
723
+
724
+ function bytesToMb(bytes) {
725
+ return bytes / (1024 * 1024);
726
+ }
727
+
728
+ function formatBytes(bytes) {
729
+ if (!Number.isFinite(bytes)) return '0 B';
730
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
731
+ let value = bytes;
732
+ let unitIndex = 0;
733
+ while (value >= 1024 && unitIndex < units.length - 1) {
734
+ value /= 1024;
735
+ unitIndex += 1;
736
+ }
737
+ return value.toFixed(2) + ' ' + units[unitIndex];
738
+ }
739
+ </script>
740
+ </body>
741
+ </html>