@uistate/perf
v1.0.0
Published
Non-invasive performance monitoring for @uistate/core stores: method wrapping, path heatmaps, timeline recording, browser overlay, downloadable JSON reports
Downloads
99
Maintainers
Readme
@uistate/perf
Non-invasive performance monitoring for @uistate/core stores.
Wraps store methods via the Prepend Dot-Path Pattern: zero core changes. Captures timing, path frequency, subscriber lifecycle, batch stats, and a full event timeline. Download the report as JSON for later analysis.
Install
npm install @uistate/perfQuick Start
import { createEventState } from '@uistate/core';
import { createPerfMonitor, mountOverlay } from '@uistate/perf';
const store = createEventState({ count: 0 });
// 1. Wrap the store (non-invasive)
const perf = createPerfMonitor(store);
// 2. Inject browser overlay (optional)
const unmount = mountOverlay(perf, document.body);
// 3. Use the store normally (all calls are instrumented)
store.set('count', 1);
store.subscribe('count', (v) => console.log(v));
// 4. Download JSON report
perf.download(); // triggers browser download
// 5. Cleanup
perf.destroy(); // unwraps store methods
unmount(); // removes overlayAPI
createPerfMonitor(store, options?)
Returns a monitor instance. Wraps set, get (opt-in), subscribe, batch, setMany.
Options:
| Option | Default | Description |
|--------|---------|-------------|
| maxEvents | 10000 | Ring buffer size for timeline events |
| trackValues | false | Store values in timeline (increases memory) |
| trackGets | false | Record get() calls (can be noisy) |
Monitor methods:
| Method | Description |
|--------|-------------|
| report() | Returns the full report object |
| download(filename?) | Triggers browser JSON download |
| reset() | Clears all recorded data |
| destroy() | Unwraps store methods (restores originals) |
Monitor properties:
| Property | Description |
|----------|-------------|
| timeline | Raw timeline array (read-only) |
| pathStats | Map<path, stats> of per-path metrics |
| sessionId | Unique session identifier |
mountOverlay(monitor, container)
Injects a floating overlay panel into the DOM. Returns an unmount() function.
Features:
- Real-time summary (sets/sec, unique paths, active subs)
- Hot paths table sorted by set count with frequency bars
- Hot listeners table sorted by fire count
- Recent events timeline
- Draggable, collapsible
- Download JSON button
- Reset button
Report Structure
{
"sessionId": "a1b2c3d4",
"elapsedMs": 12345.67,
"totalEvents": 1024,
"dropped": 0,
"summary": {
"totalSets": 500,
"totalGets": 0,
"totalFires": 1200,
"uniquePaths": 15,
"totalSubscribes": 8,
"totalUnsubscribes": 2,
"activeSubscribers": 6,
"setsPerSec": 40.5
},
"batches": {
"count": 10,
"totalPaths": 45,
"totalCoalesced": 12
},
"hotPaths": [
{ "path": "count", "sets": 100, "fires": 200, "avgSetMs": 0.012, "peakSetMs": 0.15 }
],
"hotListeners": [
{ "path": "count", "fires": 200, "firesPerSec": 16.2 }
],
"activeSubs": [
{ "id": "x1y2z3", "path": "count", "ts": 123.45 }
],
"timeline": [
{ "type": "set", "path": "count", "dur": 0.012, "ts": 100.5, "_seq": 0 }
]
}Architecture
Your App
│
▼
store.set('x', 1) ──► perfSet() ──► originalSet()
│ │
▼ ▼
record event write + notify
update stats- Prepend pattern: wraps methods, delegates to originals
- Ring buffer: bounded memory, drops oldest events
- No core changes: works with any
@uistate/core≥ 5.0.0 - Overlay at ~2 fps: minimal render overhead
Use Cases
- Hot path detection: Find which paths are set most frequently
- Slow set() diagnosis: Identify paths with high per-set latency
- Subscriber audit: See which paths have listeners and how often they fire
- Batch efficiency: Check if batches are coalescing writes effectively
- Post-hoc analysis: Download JSON for post-hoc analysis
License
MIT — Copyright (c) 2026 Ajdin Imsirovic
