npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

state-surgeon

v2.0.1

Published

Time-travel debugging platform that records every state mutation across full-stack JavaScript applications and provides interactive forensic tools to investigate bugs

Readme

🔬 State Surgeon

Time-travel debugging platform for JavaScript applications

State Surgeon records every state mutation across your React, Redux, and Zustand applications, providing interactive forensic tools to investigate bugs.

"Deterministic state timeline reconstruction with surgical debugging capabilities"

npm version License: MIT

Features

  • 🎯 Automatic State Capture - Instruments React hooks, Redux stores, and Zustand without code changes
  • 🕰️ Time Travel - Scrub through your state history with a visual timeline
  • 🔍 State Diff Viewer - Side-by-side comparison of before/after states
  • 📊 Mutation Inspector - Detailed view of each state change with call stacks
  • 🔗 Causal Chain Analysis - Find the root cause of state corruption
  • 🧪 Test Case Generation - Generate test cases from bug timelines (coming soon)

Quick Start

1. Install

npm install state-surgeon

2. Start the Recorder Server

import { createRecorderServer } from 'state-surgeon/recorder';

const server = createRecorderServer({
  port: 8080,
  wsPort: 8081,
  debug: true,
});

await server.start();
console.log('State Surgeon Recorder running on http://localhost:8080');

3. Instrument Your App

import React from 'react';
import { StateSurgeonClient, instrumentReact } from 'state-surgeon/instrument';

// Create client (connects to recorder)
const client = new StateSurgeonClient({
  serverUrl: 'ws://localhost:8081',
  appId: 'my-app',
  debug: true,
});

// Instrument React hooks
instrumentReact(React);

// Now all useState and useReducer calls are automatically tracked!

4. View the Dashboard

Open http://localhost:8080/_surgeon to see your state mutations in real-time.

Usage

React Instrumentation

import React from 'react';
import { instrumentReact } from 'state-surgeon/instrument';

// Instrument React (call once at app startup)
const cleanup = instrumentReact(React);

// Your components work normally
function Counter() {
  const [count, setCount] = React.useState(0); // ✅ Automatically tracked!
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

// To stop instrumentation
cleanup();

Redux Instrumentation

import { createStore, applyMiddleware } from 'redux';
import { createReduxMiddleware } from 'state-surgeon/instrument';

const stateSurgeonMiddleware = createReduxMiddleware({
  storeName: 'main',
  ignoreActions: ['@@INIT'], // Optional: ignore certain actions
});

const store = createStore(
  rootReducer,
  applyMiddleware(stateSurgeonMiddleware)
);

Zustand Instrumentation

import { create } from 'zustand';
import { instrumentZustand } from 'state-surgeon/instrument';

const useStore = create(
  instrumentZustand(
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }),
    { storeName: 'counter' }
  )
);

API Call Tracking

import { instrumentFetch, instrumentXHR } from 'state-surgeon/instrument';

// Track all fetch calls
const cleanupFetch = instrumentFetch({
  captureResponseBody: true,
  ignoreUrls: ['/health', '/metrics'],
});

// Track XMLHttpRequest
const cleanupXHR = instrumentXHR();

API Reference

Instrument Module

StateSurgeonClient

Main client for connecting to the recorder server.

const client = new StateSurgeonClient({
  serverUrl?: string;    // WebSocket URL (default: 'ws://localhost:8081')
  appId?: string;        // Application identifier
  sessionId?: string;    // Session ID (auto-generated if not provided)
  autoConnect?: boolean; // Connect on creation (default: true)
  batchSize?: number;    // Mutations to batch before sending (default: 50)
  flushInterval?: number;// Flush interval in ms (default: 100)
  debug?: boolean;       // Enable console logging
});

instrumentReact(React, options?)

Patches React's useState and useReducer to capture mutations.

const cleanup = instrumentReact(React, {
  client?: StateSurgeonClient; // Custom client instance
  captureComponentName?: boolean; // Detect component from stack trace
});

createReduxMiddleware(options?)

Creates Redux middleware for capturing dispatched actions.

const middleware = createReduxMiddleware({
  client?: StateSurgeonClient;
  storeName?: string;
  ignoreActions?: string[]; // Action types to skip
});

Recorder Module

createRecorderServer(options?)

Creates the mutation recording server.

const server = createRecorderServer({
  port?: number;         // HTTP port (default: 8080)
  wsPort?: number;       // WebSocket port (default: 8081)
  cors?: boolean;        // Enable CORS (default: true)
  debug?: boolean;       // Enable logging
});

await server.start();

Dashboard Module

StateSurgeonDashboard

React component for the forensic debugging UI.

import { StateSurgeonDashboard } from 'state-surgeon/dashboard';

function App() {
  return <StateSurgeonDashboard serverUrl="http://localhost:8080" />;
}

Advanced Usage

Finding State Corruption

import { TimelineReconstructor } from 'state-surgeon/recorder';

const reconstructor = new TimelineReconstructor(store);

// Find exactly when a value became invalid
const corruptedMutation = await reconstructor.findStateCorruption(
  sessionId,
  (state) => !isNaN(state.cart?.total) // Validation function
);

console.log('State became corrupted at:', corruptedMutation);

Comparing Sessions

const { divergencePoint, session1Only, session2Only } =
  await reconstructor.compareSessions(workingSessionId, brokenSessionId);

console.log('Sessions diverged at mutation index:', divergencePoint);

Finding Mutations for a Path

const mutations = await reconstructor.findMutationsForPath(
  sessionId,
  'cart.total' // State path
);

console.log('These mutations affected cart.total:', mutations);

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Your Application                          │
├─────────────────────────────────────────────────────────────┤
│  instrumentReact()  │  createReduxMiddleware()  │  etc.     │
│           ↓                    ↓                             │
│                  StateSurgeonClient                          │
│                         ↓                                    │
│              WebSocket Transport                             │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                   Recorder Server                            │
├─────────────────────────────────────────────────────────────┤
│  WebSocket Handler  │  MutationStore  │  API Routes         │
│                     │                 │                      │
│                     ↓                 ↓                      │
│              TimelineReconstructor                           │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                     Dashboard UI                             │
├─────────────────────────────────────────────────────────────┤
│  TimelineScrubber  │  StateDiffViewer  │  MutationInspector │
└─────────────────────────────────────────────────────────────┘

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Run demo
npm run demo

License

MIT © 2024