state-surgeon 1.0.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.
- package/LICENSE +21 -0
- package/README.md +296 -0
- package/dist/dashboard/index.js +1192 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/index.mjs +1181 -0
- package/dist/dashboard/index.mjs.map +1 -0
- package/dist/index.js +1828 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1798 -0
- package/dist/index.mjs.map +1 -0
- package/dist/instrument/index.js +828 -0
- package/dist/instrument/index.js.map +1 -0
- package/dist/instrument/index.mjs +819 -0
- package/dist/instrument/index.mjs.map +1 -0
- package/dist/recorder/index.js +882 -0
- package/dist/recorder/index.js.map +1 -0
- package/dist/recorder/index.mjs +873 -0
- package/dist/recorder/index.mjs.map +1 -0
- package/package.json +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# ๐ฌ State Surgeon
|
|
2
|
+
|
|
3
|
+
**Time-travel debugging platform for JavaScript applications**
|
|
4
|
+
|
|
5
|
+
State Surgeon records every state mutation across your React, Redux, and Zustand applications, providing interactive forensic tools to investigate bugs.
|
|
6
|
+
|
|
7
|
+
> "Deterministic state timeline reconstruction with surgical debugging capabilities"
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/state-surgeon)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- ๐ฏ **Automatic State Capture** - Instruments React hooks, Redux stores, and Zustand without code changes
|
|
15
|
+
- ๐ฐ๏ธ **Time Travel** - Scrub through your state history with a visual timeline
|
|
16
|
+
- ๐ **State Diff Viewer** - Side-by-side comparison of before/after states
|
|
17
|
+
- ๐ **Mutation Inspector** - Detailed view of each state change with call stacks
|
|
18
|
+
- ๐ **Causal Chain Analysis** - Find the root cause of state corruption
|
|
19
|
+
- ๐งช **Test Case Generation** - Generate test cases from bug timelines (coming soon)
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### 1. Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install state-surgeon
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Start the Recorder Server
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import { createRecorderServer } from 'state-surgeon/recorder';
|
|
33
|
+
|
|
34
|
+
const server = createRecorderServer({
|
|
35
|
+
port: 8080,
|
|
36
|
+
wsPort: 8081,
|
|
37
|
+
debug: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await server.start();
|
|
41
|
+
console.log('State Surgeon Recorder running on http://localhost:8080');
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Instrument Your App
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
import React from 'react';
|
|
48
|
+
import { StateSurgeonClient, instrumentReact } from 'state-surgeon/instrument';
|
|
49
|
+
|
|
50
|
+
// Create client (connects to recorder)
|
|
51
|
+
const client = new StateSurgeonClient({
|
|
52
|
+
serverUrl: 'ws://localhost:8081',
|
|
53
|
+
appId: 'my-app',
|
|
54
|
+
debug: true,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Instrument React hooks
|
|
58
|
+
instrumentReact(React);
|
|
59
|
+
|
|
60
|
+
// Now all useState and useReducer calls are automatically tracked!
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 4. View the Dashboard
|
|
64
|
+
|
|
65
|
+
Open `http://localhost:8080/_surgeon` to see your state mutations in real-time.
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
### React Instrumentation
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import React from 'react';
|
|
73
|
+
import { instrumentReact } from 'state-surgeon/instrument';
|
|
74
|
+
|
|
75
|
+
// Instrument React (call once at app startup)
|
|
76
|
+
const cleanup = instrumentReact(React);
|
|
77
|
+
|
|
78
|
+
// Your components work normally
|
|
79
|
+
function Counter() {
|
|
80
|
+
const [count, setCount] = React.useState(0); // โ
Automatically tracked!
|
|
81
|
+
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// To stop instrumentation
|
|
85
|
+
cleanup();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Redux Instrumentation
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
import { createStore, applyMiddleware } from 'redux';
|
|
92
|
+
import { createReduxMiddleware } from 'state-surgeon/instrument';
|
|
93
|
+
|
|
94
|
+
const stateSurgeonMiddleware = createReduxMiddleware({
|
|
95
|
+
storeName: 'main',
|
|
96
|
+
ignoreActions: ['@@INIT'], // Optional: ignore certain actions
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const store = createStore(
|
|
100
|
+
rootReducer,
|
|
101
|
+
applyMiddleware(stateSurgeonMiddleware)
|
|
102
|
+
);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Zustand Instrumentation
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
import { create } from 'zustand';
|
|
109
|
+
import { instrumentZustand } from 'state-surgeon/instrument';
|
|
110
|
+
|
|
111
|
+
const useStore = create(
|
|
112
|
+
instrumentZustand(
|
|
113
|
+
(set) => ({
|
|
114
|
+
count: 0,
|
|
115
|
+
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
116
|
+
}),
|
|
117
|
+
{ storeName: 'counter' }
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### API Call Tracking
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
import { instrumentFetch, instrumentXHR } from 'state-surgeon/instrument';
|
|
126
|
+
|
|
127
|
+
// Track all fetch calls
|
|
128
|
+
const cleanupFetch = instrumentFetch({
|
|
129
|
+
captureResponseBody: true,
|
|
130
|
+
ignoreUrls: ['/health', '/metrics'],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Track XMLHttpRequest
|
|
134
|
+
const cleanupXHR = instrumentXHR();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## API Reference
|
|
138
|
+
|
|
139
|
+
### Instrument Module
|
|
140
|
+
|
|
141
|
+
#### `StateSurgeonClient`
|
|
142
|
+
|
|
143
|
+
Main client for connecting to the recorder server.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const client = new StateSurgeonClient({
|
|
147
|
+
serverUrl?: string; // WebSocket URL (default: 'ws://localhost:8081')
|
|
148
|
+
appId?: string; // Application identifier
|
|
149
|
+
sessionId?: string; // Session ID (auto-generated if not provided)
|
|
150
|
+
autoConnect?: boolean; // Connect on creation (default: true)
|
|
151
|
+
batchSize?: number; // Mutations to batch before sending (default: 50)
|
|
152
|
+
flushInterval?: number;// Flush interval in ms (default: 100)
|
|
153
|
+
debug?: boolean; // Enable console logging
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### `instrumentReact(React, options?)`
|
|
158
|
+
|
|
159
|
+
Patches React's `useState` and `useReducer` to capture mutations.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const cleanup = instrumentReact(React, {
|
|
163
|
+
client?: StateSurgeonClient; // Custom client instance
|
|
164
|
+
captureComponentName?: boolean; // Detect component from stack trace
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### `createReduxMiddleware(options?)`
|
|
169
|
+
|
|
170
|
+
Creates Redux middleware for capturing dispatched actions.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const middleware = createReduxMiddleware({
|
|
174
|
+
client?: StateSurgeonClient;
|
|
175
|
+
storeName?: string;
|
|
176
|
+
ignoreActions?: string[]; // Action types to skip
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Recorder Module
|
|
181
|
+
|
|
182
|
+
#### `createRecorderServer(options?)`
|
|
183
|
+
|
|
184
|
+
Creates the mutation recording server.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
const server = createRecorderServer({
|
|
188
|
+
port?: number; // HTTP port (default: 8080)
|
|
189
|
+
wsPort?: number; // WebSocket port (default: 8081)
|
|
190
|
+
cors?: boolean; // Enable CORS (default: true)
|
|
191
|
+
debug?: boolean; // Enable logging
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
await server.start();
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Dashboard Module
|
|
198
|
+
|
|
199
|
+
#### `StateSurgeonDashboard`
|
|
200
|
+
|
|
201
|
+
React component for the forensic debugging UI.
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import { StateSurgeonDashboard } from 'state-surgeon/dashboard';
|
|
205
|
+
|
|
206
|
+
function App() {
|
|
207
|
+
return <StateSurgeonDashboard serverUrl="http://localhost:8080" />;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Advanced Usage
|
|
212
|
+
|
|
213
|
+
### Finding State Corruption
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
import { TimelineReconstructor } from 'state-surgeon/recorder';
|
|
217
|
+
|
|
218
|
+
const reconstructor = new TimelineReconstructor(store);
|
|
219
|
+
|
|
220
|
+
// Find exactly when a value became invalid
|
|
221
|
+
const corruptedMutation = await reconstructor.findStateCorruption(
|
|
222
|
+
sessionId,
|
|
223
|
+
(state) => !isNaN(state.cart?.total) // Validation function
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
console.log('State became corrupted at:', corruptedMutation);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Comparing Sessions
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
const { divergencePoint, session1Only, session2Only } =
|
|
233
|
+
await reconstructor.compareSessions(workingSessionId, brokenSessionId);
|
|
234
|
+
|
|
235
|
+
console.log('Sessions diverged at mutation index:', divergencePoint);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Finding Mutations for a Path
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const mutations = await reconstructor.findMutationsForPath(
|
|
242
|
+
sessionId,
|
|
243
|
+
'cart.total' // State path
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
console.log('These mutations affected cart.total:', mutations);
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Architecture
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
253
|
+
โ Your Application โ
|
|
254
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
255
|
+
โ instrumentReact() โ createReduxMiddleware() โ etc. โ
|
|
256
|
+
โ โ โ โ
|
|
257
|
+
โ StateSurgeonClient โ
|
|
258
|
+
โ โ โ
|
|
259
|
+
โ WebSocket Transport โ
|
|
260
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
261
|
+
โ
|
|
262
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
263
|
+
โ Recorder Server โ
|
|
264
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
265
|
+
โ WebSocket Handler โ MutationStore โ API Routes โ
|
|
266
|
+
โ โ โ โ
|
|
267
|
+
โ โ โ โ
|
|
268
|
+
โ TimelineReconstructor โ
|
|
269
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
270
|
+
โ
|
|
271
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
272
|
+
โ Dashboard UI โ
|
|
273
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
274
|
+
โ TimelineScrubber โ StateDiffViewer โ MutationInspector โ
|
|
275
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Development
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Install dependencies
|
|
282
|
+
npm install
|
|
283
|
+
|
|
284
|
+
# Build
|
|
285
|
+
npm run build
|
|
286
|
+
|
|
287
|
+
# Run tests
|
|
288
|
+
npm test
|
|
289
|
+
|
|
290
|
+
# Run demo
|
|
291
|
+
npm run demo
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## License
|
|
295
|
+
|
|
296
|
+
MIT ยฉ 2024
|