@usefy/use-memory-monitor 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,612 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/mirunamu00/usefy/master/assets/logo.png" alt="usefy logo" width="120" />
3
+ </p>
4
+
5
+ <h1 align="center">@usefy/use-memory-monitor</h1>
6
+
7
+ <p align="center">
8
+ <strong>Advanced React hook for real-time browser memory monitoring</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@usefy/use-memory-monitor">
13
+ <img src="https://img.shields.io/npm/v/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="npm version" />
14
+ </a>
15
+ <a href="https://www.npmjs.com/package/@usefy/use-memory-monitor">
16
+ <img src="https://img.shields.io/npm/dm/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="npm downloads" />
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@usefy/use-memory-monitor">
19
+ <img src="https://img.shields.io/bundlephobia/minzip/@usefy/use-memory-monitor?style=flat-square&color=007acc" alt="bundle size" />
20
+ </a>
21
+ <a href="https://github.com/mirunamu00/usefy/blob/master/LICENSE">
22
+ <img src="https://img.shields.io/npm/l/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="license" />
23
+ </a>
24
+ </p>
25
+
26
+ <p align="center">
27
+ <a href="#installation">Installation</a> •
28
+ <a href="#quick-start">Quick Start</a> •
29
+ <a href="#api-reference">API Reference</a> •
30
+ <a href="#examples">Examples</a> •
31
+ <a href="#browser-support">Browser Support</a> •
32
+ <a href="#license">License</a>
33
+ </p>
34
+
35
+ <p align="center">
36
+ <a href="https://mirunamu00.github.io/usefy/?path=/docs/hooks-usememorymonitor--docs" target="_blank" rel="noopener noreferrer">
37
+ <strong>📚 View Storybook Demo</strong>
38
+ </a>
39
+ </p>
40
+
41
+ ---
42
+
43
+ ## Overview
44
+
45
+ `@usefy/use-memory-monitor` is a comprehensive React hook for monitoring browser memory usage in real-time. It provides heap metrics, memory leak detection, threshold-based alerts, history tracking, and snapshot comparison capabilities.
46
+
47
+ **Part of the [@usefy](https://www.npmjs.com/org/usefy) ecosystem** — a collection of production-ready React hooks designed for modern applications.
48
+
49
+ ### Why use-memory-monitor?
50
+
51
+ - **Real-time Monitoring** — Track heap usage, total heap, and memory limits in real-time
52
+ - **Leak Detection** — Automatic memory leak detection using linear regression analysis
53
+ - **Threshold Alerts** — Configure custom thresholds for low/medium/high/critical severity levels
54
+ - **Memory Snapshots** — Take snapshots and compare memory usage between different points in time
55
+ - **History Tracking** — Maintain a circular buffer of historical memory data with trend analysis
56
+ - **Tab Visibility Optimization** — Automatically pauses monitoring when tab is hidden
57
+ - **TypeScript First** — Full type safety with comprehensive exported interfaces
58
+ - **SSR Compatible** — Safe to use with Next.js, Remix, and other SSR frameworks
59
+ - **Browser Fallbacks** — Graceful degradation in browsers without full API support
60
+ - **Well Tested** — Comprehensive test coverage (175 tests) with Vitest
61
+
62
+ ---
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ # npm
68
+ npm install @usefy/use-memory-monitor
69
+
70
+ # yarn
71
+ yarn add @usefy/use-memory-monitor
72
+
73
+ # pnpm
74
+ pnpm add @usefy/use-memory-monitor
75
+ ```
76
+
77
+ ### Peer Dependencies
78
+
79
+ This package requires React 18 or 19:
80
+
81
+ ```json
82
+ {
83
+ "peerDependencies": {
84
+ "react": "^18.0.0 || ^19.0.0"
85
+ }
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Quick Start
92
+
93
+ ```tsx
94
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
95
+
96
+ function MemoryMonitor() {
97
+ const {
98
+ heapUsed,
99
+ heapTotal,
100
+ heapLimit,
101
+ isSupported,
102
+ severity,
103
+ formatted,
104
+ } = useMemoryMonitor({
105
+ interval: 1000,
106
+ autoStart: true,
107
+ });
108
+
109
+ if (!isSupported) {
110
+ return <div>Memory monitoring not supported in this browser</div>;
111
+ }
112
+
113
+ return (
114
+ <div>
115
+ <h2>Memory Usage</h2>
116
+ <p>Heap Used: {formatted.heapUsed}</p>
117
+ <p>Heap Total: {formatted.heapTotal}</p>
118
+ <p>Heap Limit: {formatted.heapLimit}</p>
119
+ <p>Severity: {severity}</p>
120
+ </div>
121
+ );
122
+ }
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Browser Support
128
+
129
+ ### Full Support (performance.memory API)
130
+ - ✅ **Chrome** (all versions)
131
+ - ✅ **Edge** (Chromium-based)
132
+
133
+ ### Limited Support (DOM-only metrics)
134
+ - ⚠️ **Firefox** - DOM tracking only, no heap metrics
135
+ - ⚠️ **Safari** - DOM tracking only, no heap metrics
136
+ - ⚠️ **Other browsers** - Fallback strategies available
137
+
138
+ ### Browser Detection
139
+
140
+ The hook automatically detects browser capabilities and adjusts functionality:
141
+
142
+ ```tsx
143
+ const { isSupported, getUnsupportedInfo, getBrowserSupport } = useMemoryMonitor();
144
+
145
+ if (!isSupported) {
146
+ const info = getUnsupportedInfo();
147
+ console.log("Reason:", info.reason); // 'no-api' | 'browser-restriction' | etc.
148
+ console.log("Browser:", info.browser);
149
+ console.log("Fallbacks:", info.availableFallbacks);
150
+ }
151
+
152
+ const support = getBrowserSupport();
153
+ console.log("Support level:", support.level); // 'full' | 'partial' | 'none'
154
+ console.log("Available metrics:", support.availableMetrics);
155
+ ```
156
+
157
+ ---
158
+
159
+ ## API Reference
160
+
161
+ ### `useMemoryMonitor(options?)`
162
+
163
+ A hook that monitors browser memory usage in real-time with leak detection and threshold alerts.
164
+
165
+ #### Parameters
166
+
167
+ | Parameter | Type | Default | Description |
168
+ | --------- | ----------------------------- | ------- | ---------------------------------- |
169
+ | `options` | `UseMemoryMonitorOptions` | `{}` | Configuration options (see below) |
170
+
171
+ #### Options (`UseMemoryMonitorOptions`)
172
+
173
+ | Option | Type | Default | Description |
174
+ | -------------------- | ----------------------- | -------- | ------------------------------------------------ |
175
+ | `interval` | `number` | `1000` | Polling interval in milliseconds |
176
+ | `autoStart` | `boolean` | `true` | Start monitoring automatically on mount |
177
+ | `enabled` | `boolean` | `true` | Enable/disable the hook |
178
+ | `enableHistory` | `boolean` | `true` | Track memory history |
179
+ | `historySize` | `number` | `50` | Maximum number of history entries |
180
+ | `thresholds` | `ThresholdOptions` | See below | Memory usage thresholds |
181
+ | `leakDetection` | `LeakDetectionOptions` | See below | Leak detection configuration |
182
+ | `pauseWhenHidden` | `boolean` | `true` | Pause monitoring when tab is hidden |
183
+ | `onThresholdChange` | `(severity) => void` | - | Callback when severity level changes |
184
+ | `onMemoryUpdate` | `(memory) => void` | - | Callback on each memory update |
185
+ | `onLeakDetected` | `(analysis) => void` | - | Callback when memory leak is detected |
186
+ | `onUnsupported` | `(info) => void` | - | Callback when memory API is not supported |
187
+
188
+ ##### Default Thresholds
189
+
190
+ ```typescript
191
+ {
192
+ medium: 60, // Yellow alert at 60% usage
193
+ high: 80, // Orange alert at 80% usage
194
+ critical: 90, // Red alert at 90% usage
195
+ }
196
+ ```
197
+
198
+ ##### Default Leak Detection
199
+
200
+ ```typescript
201
+ {
202
+ enabled: true,
203
+ sensitivity: "medium", // 'low' | 'medium' | 'high'
204
+ sampleSize: 10,
205
+ minDuration: 30000, // 30 seconds
206
+ }
207
+ ```
208
+
209
+ #### Returns `UseMemoryMonitorReturn`
210
+
211
+ | Property | Type | Description |
212
+ | ---------------------- | ------------------------------------ | -------------------------------------------- |
213
+ | `memory` | `MemoryInfo \| null` | Current memory information |
214
+ | `heapUsed` | `number \| null` | Used heap size in bytes |
215
+ | `heapTotal` | `number \| null` | Total heap size in bytes |
216
+ | `heapLimit` | `number \| null` | Heap size limit in bytes |
217
+ | `isSupported` | `boolean` | Whether memory monitoring is supported |
218
+ | `isMonitoring` | `boolean` | Whether currently monitoring |
219
+ | `isLeakDetected` | `boolean` | Whether memory leak is detected |
220
+ | `severity` | `Severity` | Current severity level |
221
+ | `history` | `MemoryInfo[]` | Historical memory data |
222
+ | `trend` | `Trend` | Memory usage trend |
223
+ | `formatted` | `FormattedMemory` | Human-readable formatted values |
224
+ | `start` | `() => void` | Start monitoring |
225
+ | `stop` | `() => void` | Stop monitoring |
226
+ | `takeSnapshot` | `(id: string) => MemorySnapshot \| null` | Take a memory snapshot |
227
+ | `compareSnapshots` | `(id1, id2) => MemoryDifference \| null` | Compare two snapshots |
228
+ | `clearSnapshots` | `() => void` | Clear all snapshots |
229
+ | `getAllSnapshots` | `() => MemorySnapshot[]` | Get all snapshots |
230
+ | `clearHistory` | `() => void` | Clear history buffer |
231
+ | `getLeakAnalysis` | `() => LeakAnalysis \| null` | Get current leak analysis |
232
+ | `getBrowserSupport` | `() => BrowserSupport` | Get browser support information |
233
+ | `getUnsupportedInfo` | `() => UnsupportedInfo` | Get info about why monitoring is unsupported |
234
+
235
+ ### Types
236
+
237
+ #### `Severity`
238
+ ```typescript
239
+ type Severity = "low" | "medium" | "high" | "critical";
240
+ ```
241
+
242
+ #### `Trend`
243
+ ```typescript
244
+ type Trend = "increasing" | "stable" | "decreasing";
245
+ ```
246
+
247
+ #### `MemoryInfo`
248
+ ```typescript
249
+ interface MemoryInfo {
250
+ heapUsed: number | null;
251
+ heapTotal: number | null;
252
+ heapLimit: number | null;
253
+ timestamp: number;
254
+ domNodes?: number | null;
255
+ eventListeners?: number | null;
256
+ }
257
+ ```
258
+
259
+ #### `FormattedMemory`
260
+ ```typescript
261
+ interface FormattedMemory {
262
+ heapUsed: string;
263
+ heapTotal: string;
264
+ heapLimit: string;
265
+ domNodes?: string;
266
+ eventListeners?: string;
267
+ }
268
+ ```
269
+
270
+ ---
271
+
272
+ ## Examples
273
+
274
+ ### Basic Memory Monitoring
275
+
276
+ ```tsx
277
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
278
+
279
+ function BasicMonitor() {
280
+ const { formatted, severity, isMonitoring, start, stop } = useMemoryMonitor({
281
+ interval: 1000,
282
+ autoStart: true,
283
+ });
284
+
285
+ return (
286
+ <div>
287
+ <h2>Memory Usage</h2>
288
+ <p>Used: {formatted.heapUsed}</p>
289
+ <p>Total: {formatted.heapTotal}</p>
290
+ <p>Severity: {severity}</p>
291
+
292
+ <button onClick={isMonitoring ? stop : start}>
293
+ {isMonitoring ? "Stop" : "Start"}
294
+ </button>
295
+ </div>
296
+ );
297
+ }
298
+ ```
299
+
300
+ ### Memory Leak Detection
301
+
302
+ ```tsx
303
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
304
+
305
+ function LeakDetector() {
306
+ const { isLeakDetected, getLeakAnalysis, formatted } = useMemoryMonitor({
307
+ interval: 1000,
308
+ leakDetection: {
309
+ enabled: true,
310
+ sensitivity: "high",
311
+ sampleSize: 15,
312
+ minDuration: 20000, // 20 seconds
313
+ },
314
+ onLeakDetected: (analysis) => {
315
+ console.warn("Memory leak detected!", {
316
+ probability: analysis.probability,
317
+ confidence: analysis.confidence,
318
+ slope: analysis.slope,
319
+ });
320
+ },
321
+ });
322
+
323
+ const analysis = getLeakAnalysis();
324
+
325
+ return (
326
+ <div>
327
+ <h2>Leak Detection</h2>
328
+ {isLeakDetected && (
329
+ <div className="alert">
330
+ ⚠️ Memory leak detected!
331
+ <p>Probability: {(analysis?.probability ?? 0).toFixed(2)}%</p>
332
+ <p>Confidence: {analysis?.confidence}</p>
333
+ </div>
334
+ )}
335
+ <p>Current Usage: {formatted.heapUsed}</p>
336
+ </div>
337
+ );
338
+ }
339
+ ```
340
+
341
+ ### Threshold Alerts
342
+
343
+ ```tsx
344
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
345
+
346
+ function ThresholdMonitor() {
347
+ const { severity, heapUsed, heapLimit, formatted } = useMemoryMonitor({
348
+ interval: 1000,
349
+ thresholds: {
350
+ medium: 50,
351
+ high: 75,
352
+ critical: 90,
353
+ },
354
+ onThresholdChange: (newSeverity) => {
355
+ if (newSeverity === "critical") {
356
+ alert("Critical memory usage!");
357
+ }
358
+ },
359
+ });
360
+
361
+ const usagePercent = heapUsed && heapLimit
362
+ ? (heapUsed / heapLimit) * 100
363
+ : 0;
364
+
365
+ return (
366
+ <div>
367
+ <h2>Memory Usage: {usagePercent.toFixed(1)}%</h2>
368
+ <div className={`alert alert-${severity}`}>
369
+ Severity: {severity}
370
+ </div>
371
+ <p>{formatted.heapUsed} / {formatted.heapLimit}</p>
372
+ </div>
373
+ );
374
+ }
375
+ ```
376
+
377
+ ### Memory Snapshots
378
+
379
+ ```tsx
380
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
381
+ import { useState } from "react";
382
+
383
+ function SnapshotComparison() {
384
+ const {
385
+ takeSnapshot,
386
+ compareSnapshots,
387
+ getAllSnapshots,
388
+ clearSnapshots,
389
+ formatted,
390
+ } = useMemoryMonitor({ interval: 1000 });
391
+
392
+ const [snapshots, setSnapshots] = useState<string[]>([]);
393
+
394
+ const handleSnapshot = () => {
395
+ const snapshot = takeSnapshot(`snapshot-${Date.now()}`);
396
+ if (snapshot) {
397
+ setSnapshots([...snapshots, snapshot.id]);
398
+ }
399
+ };
400
+
401
+ const handleCompare = () => {
402
+ if (snapshots.length >= 2) {
403
+ const diff = compareSnapshots(snapshots[0], snapshots[snapshots.length - 1]);
404
+ if (diff) {
405
+ console.log("Memory difference:", {
406
+ heapUsed: (diff.heapUsed / 1024 / 1024).toFixed(2) + " MB",
407
+ heapTotal: (diff.heapTotal / 1024 / 1024).toFixed(2) + " MB",
408
+ duration: (diff.duration / 1000).toFixed(1) + " seconds",
409
+ });
410
+ }
411
+ }
412
+ };
413
+
414
+ return (
415
+ <div>
416
+ <h2>Snapshots ({snapshots.length})</h2>
417
+ <p>Current: {formatted.heapUsed}</p>
418
+
419
+ <button onClick={handleSnapshot}>Take Snapshot</button>
420
+ <button onClick={handleCompare} disabled={snapshots.length < 2}>
421
+ Compare First & Last
422
+ </button>
423
+ <button onClick={clearSnapshots}>Clear All</button>
424
+
425
+ <ul>
426
+ {getAllSnapshots().map((snapshot) => (
427
+ <li key={snapshot.id}>
428
+ {snapshot.id}: {(snapshot.data.heapUsed || 0) / 1024 / 1024} MB
429
+ </li>
430
+ ))}
431
+ </ul>
432
+ </div>
433
+ );
434
+ }
435
+ ```
436
+
437
+ ### History & Trend Analysis
438
+
439
+ ```tsx
440
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
441
+
442
+ function HistoryTracker() {
443
+ const { history, trend, formatted, clearHistory } = useMemoryMonitor({
444
+ interval: 500,
445
+ enableHistory: true,
446
+ historySize: 30,
447
+ });
448
+
449
+ const maxHeapUsed = Math.max(...history.map((h) => h.heapUsed || 0), 1);
450
+
451
+ return (
452
+ <div>
453
+ <h2>Memory History</h2>
454
+ <p>Current: {formatted.heapUsed}</p>
455
+ <p>
456
+ Trend: {trend === "increasing" ? "↗" : trend === "decreasing" ? "↘" : "→"} {trend}
457
+ </p>
458
+ <p>History Points: {history.length}</p>
459
+
460
+ <button onClick={clearHistory}>Clear History</button>
461
+
462
+ {/* Simple bar chart */}
463
+ <div style={{ display: "flex", alignItems: "flex-end", height: 100 }}>
464
+ {history.map((point, i) => {
465
+ const heightPercent = ((point.heapUsed || 0) / maxHeapUsed) * 100;
466
+ return (
467
+ <div
468
+ key={i}
469
+ style={{
470
+ flex: 1,
471
+ height: `${heightPercent}%`,
472
+ backgroundColor: "blue",
473
+ margin: "0 1px",
474
+ }}
475
+ title={`${((point.heapUsed || 0) / 1024 / 1024).toFixed(2)} MB`}
476
+ />
477
+ );
478
+ })}
479
+ </div>
480
+ </div>
481
+ );
482
+ }
483
+ ```
484
+
485
+ ### Browser Support Detection
486
+
487
+ ```tsx
488
+ import { useMemoryMonitor } from "@usefy/use-memory-monitor";
489
+
490
+ function SupportDetection() {
491
+ const { isSupported, getUnsupportedInfo, getBrowserSupport } = useMemoryMonitor();
492
+
493
+ if (!isSupported) {
494
+ const info = getUnsupportedInfo();
495
+ return (
496
+ <div>
497
+ <h2>Limited Support</h2>
498
+ <p>Reason: {info.reason}</p>
499
+ <p>Browser: {info.browser || "Unknown"}</p>
500
+ <p>Available fallbacks: {info.availableFallbacks.join(", ")}</p>
501
+ </div>
502
+ );
503
+ }
504
+
505
+ const support = getBrowserSupport();
506
+
507
+ return (
508
+ <div>
509
+ <h2>Browser Support</h2>
510
+ <p>Level: {support.level}</p>
511
+ <p>Available metrics: {support.availableMetrics.join(", ")}</p>
512
+ <p>Secure context: {support.isSecureContext ? "Yes" : "No"}</p>
513
+ <p>Cross-origin isolated: {support.isCrossOriginIsolated ? "Yes" : "No"}</p>
514
+ {support.limitations.length > 0 && (
515
+ <ul>
516
+ {support.limitations.map((limitation, i) => (
517
+ <li key={i}>{limitation}</li>
518
+ ))}
519
+ </ul>
520
+ )}
521
+ </div>
522
+ );
523
+ }
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Performance
529
+
530
+ ### Optimizations
531
+
532
+ 1. **Tab Visibility**: Automatically pauses monitoring when tab is hidden (configurable with `pauseWhenHidden`)
533
+ 2. **Circular Buffer**: Uses efficient circular buffer for history storage (O(1) operations)
534
+ 3. **Stable References**: All callback functions are memoized with `useCallback`
535
+ 4. **useSyncExternalStore**: React 18+ concurrent mode safe state management
536
+ 5. **Minimal Re-renders**: Only triggers re-renders when actual memory data changes
537
+
538
+ ### Bundle Size
539
+
540
+ The hook is lightweight and tree-shakeable:
541
+ - Main hook: ~8KB minified
542
+ - With all utilities: ~15KB minified
543
+ - Gzipped: ~5KB
544
+
545
+ ---
546
+
547
+ ## TypeScript
548
+
549
+ This hook is written in TypeScript and exports comprehensive type definitions:
550
+
551
+ ```tsx
552
+ import {
553
+ useMemoryMonitor,
554
+ type UseMemoryMonitorOptions,
555
+ type UseMemoryMonitorReturn,
556
+ type MemoryInfo,
557
+ type MemorySnapshot,
558
+ type LeakAnalysis,
559
+ type BrowserSupport,
560
+ type Severity,
561
+ type Trend,
562
+ } from "@usefy/use-memory-monitor";
563
+
564
+ // Full type safety
565
+ const options: UseMemoryMonitorOptions = {
566
+ interval: 1000,
567
+ autoStart: true,
568
+ };
569
+
570
+ const monitor: UseMemoryMonitorReturn = useMemoryMonitor(options);
571
+ ```
572
+
573
+ ---
574
+
575
+ ## Testing
576
+
577
+ This package maintains comprehensive test coverage to ensure reliability and stability.
578
+
579
+ ### Test Coverage
580
+
581
+ 📊 **175 tests passed** covering:
582
+ - Memory monitoring functionality
583
+ - Leak detection algorithms
584
+ - Snapshot management
585
+ - Browser support detection
586
+ - Circular buffer operations
587
+ - Formatting utilities
588
+ - SSR compatibility
589
+
590
+ ### Test Categories
591
+
592
+ - **Initialization & Lifecycle**: Mount, unmount, start/stop behavior
593
+ - **Memory Tracking**: Polling, history, trend analysis
594
+ - **Leak Detection**: Linear regression, sensitivity levels, analysis
595
+ - **Thresholds**: Severity calculation, callbacks
596
+ - **Snapshots**: Create, compare, clear operations
597
+ - **Browser Detection**: API availability, fallback strategies
598
+ - **Edge Cases**: SSR, unsupported browsers, invalid inputs
599
+
600
+ ---
601
+
602
+ ## License
603
+
604
+ MIT © [mirunamu](https://github.com/mirunamu00)
605
+
606
+ This package is part of the [usefy](https://github.com/mirunamu00/usefy) monorepo.
607
+
608
+ ---
609
+
610
+ <p align="center">
611
+ <sub>Built with care by the usefy team</sub>
612
+ </p>