reactoradar 1.6.5 → 1.6.7

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 (40) hide show
  1. package/AGENTS.md +341 -0
  2. package/app.js +22 -4448
  3. package/index.html +12 -0
  4. package/init.js +187 -0
  5. package/main.js +1 -0
  6. package/package.json +4 -2
  7. package/panels/console.js +788 -0
  8. package/panels/ga4.js +328 -0
  9. package/panels/native.js +256 -0
  10. package/panels/network.js +968 -0
  11. package/{src/renderer/panels → panels}/performance.js +51 -14
  12. package/panels/react.js +21 -0
  13. package/panels/redux.js +438 -0
  14. package/panels/settings.js +832 -0
  15. package/panels/sources.js +282 -0
  16. package/{src/renderer/panels → panels}/storage.js +77 -26
  17. package/styles.css +40 -7
  18. package/src/main/main.js +0 -396
  19. package/src/main/preload.js +0 -28
  20. package/src/renderer/app.js +0 -221
  21. package/src/renderer/components/object-tree.js +0 -245
  22. package/src/renderer/index.html +0 -111
  23. package/src/renderer/panels/console.js +0 -248
  24. package/src/renderer/panels/memory.js +0 -60
  25. package/src/renderer/panels/network.js +0 -559
  26. package/src/renderer/panels/react.js +0 -31
  27. package/src/renderer/panels/redux.js +0 -159
  28. package/src/renderer/panels/settings.js +0 -93
  29. package/src/renderer/panels/sources.js +0 -189
  30. package/src/renderer/state.js +0 -132
  31. package/src/renderer/styles/components.css +0 -145
  32. package/src/renderer/styles/console.css +0 -73
  33. package/src/renderer/styles/main.css +0 -229
  34. package/src/renderer/styles/network.css +0 -242
  35. package/src/renderer/styles/performance.css +0 -45
  36. package/src/renderer/styles/redux.css +0 -77
  37. package/src/renderer/styles/settings.css +0 -63
  38. package/src/renderer/styles/sources.css +0 -48
  39. package/src/renderer/styles/storage.css +0 -28
  40. package/src/renderer/styles/theme-light.css +0 -57
package/AGENTS.md ADDED
@@ -0,0 +1,341 @@
1
+ # ReactoRadar — Architecture & Coding Rules
2
+
3
+ > **Read this file before making ANY code changes.**
4
+ > This document defines the architecture, panel ownership, state contracts, and rules
5
+ > that must be followed to avoid breaking existing functionality.
6
+
7
+ ---
8
+
9
+ ## File Structure
10
+
11
+ ### Main Process
12
+ | File | Role |
13
+ |------|------|
14
+ | `main.js` | Electron main process — windows, IPC, bridges, native logs, menus |
15
+ | `preload.js` | Context bridge — IPC allowlist, renderer API surface |
16
+
17
+ ### Renderer (loaded in this order via `<script>` tags in index.html)
18
+ | File | Role |
19
+ |------|------|
20
+ | `app.js` | **Shared state**, helpers (`$`, `esc`, `ts`), navigation, `clearAll`, `freeMemory`, `clearActiveTab`, `updateDeviceBanner`, `takeScreenshot` |
21
+ | `panels/settings.js` | Settings panel + **shared utilities** used by other panels: `TAB_CONFIG`, `isTabEnabled`, `applyTheme`, `getTabVisibility`, `applyTabVisibility`, hidden URLs, localStorage helpers, `_applyUpdateBanner`, `_showChangelog`, `_loadVersionHistory` |
22
+ | `panels/console.js` | Console panel + **shared renderers**: `collectEntries`, `objPreview`, `createTreeNode`, `showContextMenu`, `showToast`, `addConsoleLog` |
23
+ | `panels/network.js` | Network panel — `handleNetworkEvent`, `renderNetwork`, HAR export, detail view |
24
+ | `panels/ga4.js` | GA4 Events panel — `ga4State`, `handleGA4Event`, `renderGA4List`, `renderGA4Summary` |
25
+ | `panels/redux.js` | Redux panel — `handleReduxEvent`, `renderRedux`, `_createHighlightedTree`, state diff |
26
+ | `panels/storage.js` | AsyncStorage panel — `handleStorageEvent`, `renderStorage`, `formatSize` |
27
+ | `panels/performance.js` | Performance + Memory panels — `perfState`, `handlePerfEvent`, `handleMemoryEvent`, `initMemoryPanel` |
28
+ | `panels/native.js` | Native Logs panel — `_nativeState`, `initNativeLogsPanel`, `_appendNativeLog` |
29
+ | `panels/react.js` | React Tree panel — just a connect button |
30
+ | `panels/sources.js` | Sources panel — Metro source file browser |
31
+ | `init.js` | **Boot script** (loaded LAST) — IPC wiring, button handlers, memory monitor, settings apply, panel init calls |
32
+
33
+ ### Other
34
+ | File | Role |
35
+ |------|------|
36
+ | `styles.css` | All CSS — themes, panel styles, components |
37
+ | `index.html` | Shell HTML — nav sidebar, panel containers, script load order |
38
+ | `sdk/RNDebugSDK.js` | Client SDK injected into React Native apps |
39
+ | `bin/setup.js` | CLI setup script — copies SDK, patches RN project |
40
+
41
+ ### Script Load Order (critical)
42
+ ```
43
+ 1. app.js — state, $, esc, ts, clearAll, freeMemory (no panel dependencies)
44
+ 2. panels/settings.js — TAB_CONFIG, isTabEnabled, localStorage helpers (used by all panels)
45
+ 3. panels/console.js — createTreeNode, showContextMenu, addConsoleLog (used by other panels)
46
+ 4. panels/network.js — depends on: console.js (showToast, showContextMenu, createTreeNode)
47
+ 5. panels/ga4.js — depends on: console.js (showContextMenu, createTreeNode)
48
+ 6. panels/redux.js — depends on: console.js (addConsoleLog, createTreeNode, showContextMenu)
49
+ 7. panels/storage.js — depends on: console.js (createTreeNode, showContextMenu)
50
+ 8. panels/performance.js — depends on: settings.js (isTabEnabled)
51
+ 9. panels/native.js — depends on: settings.js (isTabEnabled)
52
+ 10. panels/react.js — no dependencies
53
+ 11. panels/sources.js — no panel dependencies
54
+ 12. init.js — depends on ALL of the above (calls init functions, registers IPC)
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Critical Rule: Do NOT Break Other Panels
60
+
61
+ **Every panel is currently in a single `app.js` file.** Changes to one panel can silently
62
+ break another. Before making any change, check:
63
+
64
+ 1. **Shared state** — Is the variable you're touching read/written by other panels?
65
+ 2. **Shared functions** — Is the function you're modifying called from other panels?
66
+ 3. **IPC listeners** — The preload `on()` method calls `removeAllListeners(channel)`.
67
+ Registering the same channel twice **kills the first listener**.
68
+ 4. **Array sync** — `state.redux.actions` and `state.redux.states` MUST have the same length.
69
+ Never empty one without emptying the other.
70
+
71
+ ---
72
+
73
+ ## Panels — Ownership & State
74
+
75
+ ### Console Panel
76
+ - **Init:** `initConsolePanel()` (app.js)
77
+ - **State owned:**
78
+ - `state.console.logs` — array of log entries
79
+ - `state.console.levelFilters` — `{log, info, warn, error, debug}` booleans
80
+ - `state.console.searchFilter` — string
81
+ - `state.console.showRedux` — boolean (show redux actions in console)
82
+ - `_consolePending` — batch queue for rAF rendering
83
+ - `_consoleRAF` — pending requestAnimationFrame ID
84
+ - `_lastLogMsg`, `_lastLogRow`, `_lastLogCount` — log grouping state
85
+ - **IPC channels:** `console-event` (line 921)
86
+ - **Key functions:** `addConsoleLog()`, `flushConsoleBatch()`, `renderConsole()`, `buildLogRow()`, `buildLogBody()`
87
+ - **Cross-panel dependency:** Called by Redux (`handleReduxEvent` → `addConsoleLog`)
88
+ - **Constants:** `MAX_CONSOLE_LOGS = 5000`
89
+
90
+ ### Network Panel
91
+ - **Init:** `initNetworkPanel()` (app.js)
92
+ - **State owned:**
93
+ - `state.network.requests` — `{id: requestObj}` map
94
+ - `state.network.order` — array of request IDs
95
+ - `state.network.selectedId`, `statusFilter`, `typeFilter`, `searchFilter`, `throttle`, `enabled`, `sortCol`, `sortDir`
96
+ - `_netRAF` — pending requestAnimationFrame ID
97
+ - **IPC channels:** `network-event` (line 357)
98
+ - **Key functions:** `handleNetworkEvent()`, `renderNetwork()`, `buildNetRow()`, `selectNetRequest()`, `closeNetDetail()`
99
+ - **Cross-panel dependency:** Calls `addConsoleLog()` for error toasts; calls `showToast()`
100
+ - **Constants:** `NET_COLS` (column definitions)
101
+
102
+ ### Redux Panel
103
+ - **Init:** `initReduxPanel()` (app.js)
104
+ - **State owned:**
105
+ - `state.redux.actions` — array of action entries
106
+ - `state.redux.states` — array of full state snapshots (**MUST be same length as actions**)
107
+ - `state.redux.selected` — selected action index (-1 = none)
108
+ - `state.redux.searchFilter`, `sortDir`
109
+ - `_reduxCatColors`, `_reduxColorIdx` — action category color cache
110
+ - **IPC channels:** `redux-event` (line 356)
111
+ - **Key functions:** `handleReduxEvent()`, `renderRedux()`, `_createHighlightedTree()`, `_deepEqual()`, `_findLeafChanges()`
112
+ - **Cross-panel dependency:** Calls `addConsoleLog()` to mirror actions in console
113
+ - **CRITICAL:** `actions` and `states` arrays must always be the same length. Never clear one without the other.
114
+ - **Constants:** `MAX_REDUX_HISTORY = 500`
115
+
116
+ ### GA4 Events Panel
117
+ - **Init:** `initGA4Panel()` (app.js)
118
+ - **State owned:**
119
+ - `ga4State` — standalone object: `{events, selected, searchFilter, sortDir, _raf}`
120
+ - `_ga4EventColors`, `_ga4ColorIdx` — event color cache
121
+ - **IPC channels:** `ga4-event` (line 360)
122
+ - **Key functions:** `handleGA4Event()`, `renderGA4List()`, `renderGA4Detail()`, `renderGA4Summary()`
123
+
124
+ ### Storage Panel
125
+ - **Init:** `initStoragePanel()` (app.js)
126
+ - **State owned:**
127
+ - `state.storage.entries` — `{key: value}` map
128
+ - `state.storage.keys` — ordered key array
129
+ - `state.storage.selected`, `searchFilter`
130
+ - `_storageRAF` — pending requestAnimationFrame ID
131
+ - **IPC channels:** `storage-event` (line 358)
132
+ - **Key functions:** `handleStorageEvent()`, `renderStorage()`, `renderStorageValue()`
133
+
134
+ ### Performance Panel
135
+ - **Init:** `initPerformancePanel()` (app.js)
136
+ - **State owned:**
137
+ - `perfState` — standalone object: `{fps, jsThread, uiThread, recording, data}`
138
+ - **IPC channels:** `perf-event` (line 362, shared with Memory)
139
+ - **Key functions:** `handlePerfEvent()`, `drawPerfGraph()`, `clearPerfCanvas()`
140
+
141
+ ### Memory Panel
142
+ - **Init:** `initMemoryPanel()` (app.js)
143
+ - **State owned:** None (displays live values from perf events)
144
+ - **IPC channels:** `perf-event` (line 362, shared with Performance)
145
+ - **Key functions:** `handleMemoryEvent()`
146
+
147
+ ### Native Logs Panel
148
+ - **Init:** `initNativeLogsPanel()` (app.js)
149
+ - **State owned:**
150
+ - `_nativeState` — standalone object: `{logs, connected, platform, levelFilter, searchFilter}`
151
+ - **IPC channels:** `native-log`, `native-status` (registered inside init, lines 3429, 3440)
152
+ - **Key functions:** `_clearNativeLogs()`, `_appendNativeLog()`, `_renderNativeLogs()`, `_autoDetectNative()`
153
+ - **Constants:** `MAX_NATIVE_LOGS`
154
+
155
+ ### Settings Panel
156
+ - **Init:** `initSettingsPanel()` (app.js)
157
+ - **State owned:** All localStorage accessors (theme, font, app name, metro port, tab visibility, tab order, hidden URLs)
158
+ - **Key functions:** `applyTheme()`, `applyFontSize()`, `applyFontFamily()`, `applyAppName()`, `applyTabVisibility()`, `_buildTabVisGrid()`, `_loadVersionHistory()`
159
+ - **Constants:** `TAB_CONFIG`, `FONT_FAMILIES`
160
+
161
+ ### Sources Panel
162
+ - **Init:** `initSourcesPanel()` (app.js)
163
+ - **Key functions:** `fetchSourceFileList()`, `renderSourceFileList()`, `buildSourceTreeNode()`, `loadSourceFile()`
164
+
165
+ ### React Tree Panel
166
+ - **Init:** `initReactPanel()` (app.js)
167
+ - **Minimal** — just a connect button for React DevTools
168
+
169
+ ---
170
+
171
+ ## Shared Utilities — DO NOT MODIFY without checking all callers
172
+
173
+ | Function | Used By |
174
+ |----------|---------|
175
+ | `$(id)` | Every panel |
176
+ | `esc(s)` | Every panel |
177
+ | `ts(ms)` | Console, Network, Redux, GA4, Native |
178
+ | `collectEntries(val)` | `objPreview()`, `createTreeNode()` |
179
+ | `objPreview(val)` | `createTreeNode()` |
180
+ | `createTreeNode(key, val, collapsed)` | Console, Network, Redux, Storage, GA4 |
181
+ | `createPrimitiveSpan(val)` | `createTreeNode()`, `renderConsoleArg()` |
182
+ | `showContextMenu(e, items)` | Console, Network, Redux, Storage, GA4, Native |
183
+ | `clearAll()` | IPC `clear-all-ui`, memory warning |
184
+ | `freeMemory()` | IPC `device-all-disconnected` (debounced) |
185
+ | `clearActiveTab()` | Keyboard shortcut Cmd+K |
186
+ | `isTabEnabled(tabId)` | Redux, GA4, Storage, Native, Performance |
187
+ | `formatSize(bytes)` | Storage, Network, Memory |
188
+ | `switchPanel(panel)` | Navigation, tab visibility, toasts |
189
+ | `updateDeviceBanner(service, on)` | IPC connection handlers |
190
+ | `showToast(msg, type, panel)` | Network |
191
+
192
+ ---
193
+
194
+ ## IPC Channel Registry
195
+
196
+ ### Renderer listens (app.js → via preload allowlist)
197
+
198
+ | Channel | Handler | Panel |
199
+ |---------|---------|-------|
200
+ | `ports` | Sets `state.ports` | Global |
201
+ | `cdp-targets` | Updates CDP button | Global |
202
+ | `redux-event` | `handleReduxEvent` | Redux |
203
+ | `network-event` | `handleNetworkEvent` | Network |
204
+ | `storage-event` | `handleStorageEvent` | Storage |
205
+ | `console-event` | `addConsoleLog` | Console |
206
+ | `ga4-event` | `handleGA4Event` | GA4 |
207
+ | `perf-event` | `handlePerfEvent` + `handleMemoryEvent` | Perf + Memory |
208
+ | `redux-connected` | `updateDeviceBanner` + cancel disconnect timer | Global |
209
+ | `network-connected` | `updateDeviceBanner` + cancel disconnect timer | Global |
210
+ | `storage-connected` | `updateDeviceBanner` + cancel disconnect timer | Global |
211
+ | `react-dt-status` | `updateDeviceBanner` | Global |
212
+ | `clear-all-ui` | `clearAll()` | Global |
213
+ | `device-all-disconnected` | debounced `freeMemory()` | Global |
214
+ | `app-version` | Sets `state._appVersion`, `state._isPackaged` | Settings |
215
+ | `update-available` | `_applyUpdateBanner()` | Settings |
216
+ | `update-downloaded` | `_applyUpdateBanner()` | Settings |
217
+ | `trigger-open-cdp` | Opens CDP | Global |
218
+ | `theme-changed` | Applies theme | Settings |
219
+ | `focus-search` | Focuses active panel search | Global |
220
+ | `native-log` | Appends native log | Native (registered inside init) |
221
+ | `native-status` | Updates native connection status | Native (registered inside init) |
222
+
223
+ ### Preload allowlist (preload.js)
224
+
225
+ **Every new IPC channel MUST be added to the `allowed` array in `preload.js` line 10-14.**
226
+ If a channel is not in this array, the listener is silently dropped — no error, no warning.
227
+
228
+ ### Main process sends (main.js)
229
+
230
+ | Channel | Sent from |
231
+ |---------|-----------|
232
+ | `redux-event` | `startBridge` callback for Redux bridge (port 9090) |
233
+ | `network-event` | `startBridge` callback for Network bridge (port 9092) |
234
+ | `storage-event` | `startBridge` callback for Storage bridge (port 9091) |
235
+ | `console-event` | `startBridge` callback for Network bridge (type=console) |
236
+ | `perf-event` | `startBridge` callback for Network bridge (type=perf) |
237
+ | `ga4-event` | `startBridge` callback for Network bridge (type=ga4) |
238
+ | `*-connected` | `startBridge` on WS connect/disconnect |
239
+ | `device-all-disconnected` | `startBridge` when all 3 bridges have 0 clients |
240
+ | `clear-all-ui` | Menu Cmd+K handler |
241
+ | `app-version` | `createMainWindow` on `did-finish-load` |
242
+ | `native-log` | Native log process stdout parser |
243
+ | `native-status` | Native log start/stop/error |
244
+
245
+ ---
246
+
247
+ ## Main Process (main.js) — Structure
248
+
249
+ ### WebSocket Bridges
250
+
251
+ | Port | Name | Client Set | Events Carried |
252
+ |------|------|------------|----------------|
253
+ | 9090 | Redux | `reduxClients` | `type: 'redux'` — action + nextState |
254
+ | 9091 | Storage | `storageClients` | `type: 'storage'` — key/value snapshots |
255
+ | 9092 | Network | `networkClients` | `type: 'console'`, `'network'`, `'perf'`, `'ga4'`, `'control'` |
256
+ | 8097 | React DT | `reactDTClients` | React DevTools relay (pass-through) |
257
+
258
+ ### before-quit cleanup order
259
+ 1. Send `device-all-disconnected` to renderer
260
+ 2. Destroy `devtoolsWindow`
261
+ 3. Close `reactDTServer` + clients
262
+ 4. Close all bridge servers + clients
263
+ 5. Kill `_nativeLogProcess` (second `before-quit` handler inside `setupIPC`)
264
+
265
+ ---
266
+
267
+ ## Rules for Making Changes
268
+
269
+ ### 1. Adding a new panel
270
+ - Add init function: `initXxxPanel()`
271
+ - Add to `TAB_CONFIG` array
272
+ - Add to init sequence at bottom of app.js
273
+ - Add state to `clearAll()` and `freeMemory()` if the panel stores data
274
+ - Add case to `clearActiveTab()` if the panel has clearable data
275
+
276
+ ### 2. Adding a new IPC channel
277
+ - Add `ipcMain.on/handle` in `main.js` `setupIPC()`
278
+ - Add channel name to `preload.js` allowed array (line 10-14)
279
+ - Add `window.electronAPI.on()` in app.js or expose send method in preload
280
+ - **Test:** Verify the listener fires by adding a `console.log` in the handler
281
+
282
+ ### 3. Modifying shared state
283
+ - Check all panels that read/write the field (see tables above)
284
+ - **Redux arrays:** `actions` and `states` must stay in sync
285
+ - **rAF IDs:** Cancel with `cancelAnimationFrame()` before clearing data
286
+ - **freeMemory():** Only trim, never wipe arrays that other panels index into
287
+
288
+ ### 4. Modifying clearAll() or freeMemory()
289
+ - `clearAll()` wipes everything + re-renders — used for explicit user action (Cmd+K)
290
+ - `freeMemory()` trims heavy data without clearing UI — used on disconnect/quit
291
+ - After modifying either, verify ALL panels still render correctly
292
+ - Test: Cmd+K clears all panels, device disconnect doesn't break subsequent events
293
+
294
+ ### 5. Modifying the object tree renderer
295
+ - `collectEntries()`, `objPreview()`, `createTreeNode()` are used by Console, Network, Redux, Storage, GA4
296
+ - **Any change to these functions affects ALL panels** that render object trees
297
+ - `_createHighlightedTree()` in Redux is a SEPARATE tree renderer — changes to `createTreeNode` do NOT automatically apply to Redux diff trees
298
+
299
+ ### 6. CSS variable naming
300
+ - Themes define: `--bg`, `--bg2`, `--bg3`, `--bg4` (NOT `--bg1`)
301
+ - `--text`, `--text-mid`, `--text-dim`, `--text-bright`
302
+ - `--accent`, `--accent2`, `--border`, `--border2`
303
+ - `--green`, `--yellow`, `--red`
304
+ - **Never use undefined variables** — the value resolves to transparent/empty
305
+
306
+ ---
307
+
308
+ ## SDK Integration (in user's React Native app)
309
+
310
+ The SDK (`RNDebugSDK.js`) has two parts:
311
+ 1. **Auto-connect** — WebSocket connections to ports 9090/9091/9092 open on import
312
+ 2. **Manual wiring** — Redux requires adding `reduxMiddleware` or `reduxEnhancer` to the store
313
+
314
+ `npx reactoradar setup` handles:
315
+ - Copying SDK to `src/debug/RNDebugSDK.js`
316
+ - Patching entry file (`index.js`) to import SDK
317
+ - Auto-patching RTK `configureStore` with middleware
318
+ - **Legacy `createStore`**: Only prints manual instructions (does NOT auto-patch)
319
+
320
+ If Redux is not working:
321
+ 1. Check if `reduxMiddleware` or `reduxEnhancer` is wired into the store
322
+ 2. Connection to port 9090 ("RN app connected") does NOT mean events are flowing
323
+ 3. Events only flow when `store.dispatch()` goes through the middleware/enhancer
324
+
325
+ ---
326
+
327
+ ## Testing Checklist (after any change)
328
+
329
+ - [ ] Console: logs appear, level filters work, search works, Cmd+K clears
330
+ - [ ] Network: requests appear, detail panel opens, HAR export works
331
+ - [ ] Redux: actions appear, state diff shows, Cmd+K clears
332
+ - [ ] GA4: events appear, summary works, color toggle works
333
+ - [ ] Storage: keys appear, values render, search works
334
+ - [ ] Performance: FPS/JS/UI graphs render when recording
335
+ - [ ] Memory: heap values appear
336
+ - [ ] Native Logs: connect to adb/xcrun, logs stream, Cmd+K clears
337
+ - [ ] Settings: theme switch, font size, tab visibility, version history loads
338
+ - [ ] Device disconnect: `freeMemory()` fires after 3s, panels still work after reconnect
339
+ - [ ] Device reconnect: cancel disconnect timer, new events flow immediately
340
+ - [ ] Cmd+K: clears active tab (all tabs including native)
341
+ - [ ] App quit: `devtoolsWindow` closed, bridges closed, no crash