reactoradar 1.6.5 → 1.6.6

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/index.html CHANGED
@@ -90,6 +90,18 @@
90
90
 
91
91
  </div>
92
92
 
93
+ <!-- Load order: app.js (state/helpers) → panels → init.js (IPC/boot) -->
93
94
  <script src="app.js"></script>
95
+ <script src="panels/settings.js"></script>
96
+ <script src="panels/console.js"></script>
97
+ <script src="panels/network.js"></script>
98
+ <script src="panels/ga4.js"></script>
99
+ <script src="panels/redux.js"></script>
100
+ <script src="panels/storage.js"></script>
101
+ <script src="panels/performance.js"></script>
102
+ <script src="panels/native.js"></script>
103
+ <script src="panels/react.js"></script>
104
+ <script src="panels/sources.js"></script>
105
+ <script src="init.js"></script>
94
106
  </body>
95
107
  </html>
package/main.js CHANGED
@@ -375,6 +375,7 @@ function startReactDevToolsServer() {
375
375
  function startBridgeServers() {
376
376
  // Redux Bridge
377
377
  startBridge(PORTS.REDUX_BRIDGE, 'redux', reduxClients, (event) => {
378
+ // console.log('[REDUX-DEBUG] Event from SDK:', event?.type, event?.action?.type);
378
379
  _send('redux-event', event);
379
380
  });
380
381
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "reactoradar",
3
3
  "productName": "ReactoRadar",
4
- "version": "1.6.5",
4
+ "version": "1.6.6",
5
5
  "description": "macOS debugger for React Native — Console, Sources, Network, Performance, Memory, Redux, AsyncStorage, React tree. Supports RN 0.74+ with Hermes and New Architecture.",
6
6
  "main": "main.js",
7
7
  "bin": {
package/styles.css CHANGED
@@ -1396,6 +1396,33 @@ mark { background: rgba(79,172,255,.2); color: var(--accent); border-radius: 2px
1396
1396
  cursor: pointer;
1397
1397
  transition: color 0.15s, border-color 0.15s;
1398
1398
  }
1399
+ .version-dl-wrap { position: relative; }
1400
+ .version-dl-menu {
1401
+ position: absolute;
1402
+ top: 100%;
1403
+ right: 0;
1404
+ z-index: 100;
1405
+ min-width: 220px;
1406
+ background: var(--bg2);
1407
+ border: 1px solid var(--border);
1408
+ border-radius: 8px;
1409
+ box-shadow: 0 8px 24px rgba(0,0,0,.4);
1410
+ padding: 4px 0;
1411
+ margin-top: 4px;
1412
+ animation: changelogSlideIn 0.12s ease-out;
1413
+ }
1414
+ .version-dl-item {
1415
+ display: flex;
1416
+ align-items: center;
1417
+ gap: 10px;
1418
+ padding: 8px 14px;
1419
+ cursor: pointer;
1420
+ transition: background 0.12s;
1421
+ }
1422
+ .version-dl-item:hover { background: var(--bg3); }
1423
+ .version-dl-icon { font-size: 16px; flex-shrink: 0; }
1424
+ .version-dl-name { font-size: 11px; font-weight: 600; color: var(--text); }
1425
+ .version-dl-hint { font-size: 9px; color: var(--text-dim); margin-top: 1px; }
1399
1426
  .version-npm-btn {
1400
1427
  background: transparent;
1401
1428
  color: var(--accent);
@@ -1774,7 +1801,7 @@ mark { background: rgba(79,172,255,.2); color: var(--accent); border-radius: 2px
1774
1801
 
1775
1802
  /* ── Detail Panel Search ───────────────────────────────────────────────────── */
1776
1803
  .detail-search-wrap { display: flex; align-items: center; gap: 4px; margin-left: auto; padding: 0 6px; }
1777
- .detail-search-input { width: 150px; font-size: 10px; padding: 3px 6px; border: 1px solid var(--border); background: var(--bg1); color: var(--text); border-radius: 3px; outline: none; }
1804
+ .detail-search-input { width: 150px; font-size: 10px; padding: 3px 6px; border: 1px solid var(--border); background: var(--bg2); color: var(--text); border-radius: 3px; outline: none; }
1778
1805
  .detail-search-input:focus { border-color: var(--accent); }
1779
1806
  .detail-search-count { font-size: 9px; color: var(--text-dim); white-space: nowrap; min-width: 45px; }
1780
1807
  .detail-search-nav { background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-size: 9px; width: 18px; height: 18px; border-radius: 3px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
@@ -1785,13 +1812,19 @@ mark { background: rgba(79,172,255,.2); color: var(--accent); border-radius: 2px
1785
1812
  .detail-search-hl.active { background: rgba(255,213,79,.7); outline: 1px solid rgba(255,213,79,.9); }
1786
1813
 
1787
1814
  /* ── Changelog Modal ───────────────────────────────────────────────────────── */
1788
- .changelog-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 9999; display: flex; align-items: center; justify-content: center; }
1789
- .changelog-modal { background: var(--bg1); border: 1px solid var(--border); border-radius: 10px; width: 520px; max-width: 90vw; max-height: 70vh; display: flex; flex-direction: column; box-shadow: 0 8px 32px rgba(0,0,0,.4); }
1790
- .changelog-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--border); }
1815
+ .changelog-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); z-index: 9999; display: flex; align-items: center; justify-content: center; animation: changelogFadeIn 0.15s ease-out; }
1816
+ @keyframes changelogFadeIn { from { opacity: 0; } to { opacity: 1; } }
1817
+ .changelog-modal { background: var(--bg2); border: 1px solid var(--border); border-radius: 12px; width: 520px; max-width: 90vw; max-height: 70vh; display: flex; flex-direction: column; box-shadow: 0 12px 40px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.05) inset; animation: changelogSlideIn 0.2s ease-out; }
1818
+ @keyframes changelogSlideIn { from { opacity: 0; transform: translateY(12px) scale(0.97); } to { opacity: 1; transform: translateY(0) scale(1); } }
1819
+ .changelog-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--border); background: var(--bg3); border-radius: 12px 12px 0 0; }
1791
1820
  .changelog-title { font-size: 13px; font-weight: 700; color: var(--text); }
1792
- .changelog-close { background: transparent; border: none; color: var(--text-dim); font-size: 18px; cursor: pointer; padding: 0 4px; }
1793
- .changelog-close:hover { color: var(--text); }
1794
- .changelog-body { flex: 1; overflow-y: auto; padding: 16px; font-size: 11px; line-height: 1.6; color: var(--text-mid); }
1821
+ .changelog-close { background: transparent; border: none; color: var(--text-dim); font-size: 18px; cursor: pointer; padding: 2px 6px; border-radius: 4px; transition: background 0.12s, color 0.12s; }
1822
+ .changelog-close:hover { color: var(--text); background: var(--bg4); }
1823
+ .changelog-body { flex: 1; overflow-y: auto; padding: 18px; font-size: 11px; line-height: 1.7; color: var(--text-mid); }
1824
+ .changelog-body::-webkit-scrollbar { width: 4px; }
1825
+ .changelog-body::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; }
1826
+ .changelog-link { color: var(--accent); text-decoration: none; cursor: pointer; border-bottom: 1px dotted var(--accent); transition: opacity 0.12s; }
1827
+ .changelog-link:hover { opacity: 0.8; }
1795
1828
 
1796
1829
  /* ── Support Button ────────────────────────────────────────────────────────── */
1797
1830
  .support-btn { background: linear-gradient(135deg, #ff813f, #ff5e72); color: #fff; border: none; padding: 8px 20px; border-radius: 8px; font-size: 12px; font-weight: 700; cursor: pointer; transition: all 0.15s; letter-spacing: 0.3px; }
package/src/main/main.js DELETED
@@ -1,396 +0,0 @@
1
- 'use strict';
2
-
3
- const { app, BrowserWindow, ipcMain, Menu, shell, nativeTheme } = require('electron');
4
- const path = require('path');
5
- const http = require('http');
6
- const { WebSocketServer, WebSocket } = require('ws');
7
-
8
- // ─── Ports ────────────────────────────────────────────────────────────────────
9
- const PORTS = {
10
- METRO: 8081, // Metro bundler (CDP proxy lives here)
11
- REACT_DT: 8097, // react-devtools-core server port
12
- REDUX_BRIDGE: 9090, // our custom Redux WS bridge
13
- STORAGE_BRIDGE:9091, // AsyncStorage WS bridge
14
- NETWORK_BRIDGE:9092, // Network intercept WS bridge
15
- };
16
-
17
- // ─── Windows ──────────────────────────────────────────────────────────────────
18
- let mainWindow = null;
19
- let devtoolsWindow = null; // hosts the embedded CDP DevTools frontend
20
-
21
- // ─── State ────────────────────────────────────────────────────────────────────
22
- let reduxClients = new Set();
23
- let storageClients = new Set();
24
- let networkClients = new Set();
25
-
26
- // ─── App lifecycle ────────────────────────────────────────────────────────────
27
- app.whenReady().then(async () => {
28
- // Theme will be set by renderer via IPC once it reads localStorage
29
- nativeTheme.themeSource = 'dark';
30
-
31
- await createMainWindow();
32
- startBridgeServers();
33
- startReactDevToolsServer();
34
- setupMetroCDPProxy();
35
- setupIPC();
36
- buildMenu();
37
- });
38
-
39
- app.on('window-all-closed', () => {
40
- if (process.platform !== 'darwin') app.quit();
41
- });
42
-
43
- app.on('before-quit', () => {
44
- // Close all WS servers gracefully
45
- if (reactDTServer) {
46
- reactDTServer.close();
47
- reactDTClients.forEach(ws => ws.close());
48
- reactDTClients.clear();
49
- }
50
- });
51
-
52
- app.on('activate', () => {
53
- if (BrowserWindow.getAllWindows().length === 0) createMainWindow();
54
- });
55
-
56
- // ─── Main Window ──────────────────────────────────────────────────────────────
57
- async function createMainWindow() {
58
- mainWindow = new BrowserWindow({
59
- width: 1400,
60
- height: 900,
61
- minWidth: 900,
62
- minHeight: 600,
63
- titleBarStyle: 'hiddenInset',
64
- backgroundColor: '#0a0b0e',
65
- vibrancy: 'under-window',
66
- visualEffectState: 'active',
67
- webPreferences: {
68
- nodeIntegration: false,
69
- contextIsolation: true,
70
- preload: path.join(__dirname, 'preload.js'),
71
- },
72
- icon: path.join(__dirname, '../../assets/icon.png'),
73
- });
74
-
75
- mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
76
-
77
- // Open the JS Debugger panel (CDP DevTools) in a second window
78
- mainWindow.webContents.on('did-finish-load', () => {
79
- mainWindow.webContents.send('ports', PORTS);
80
- });
81
- }
82
-
83
- // ─── CDP DevTools Window (JS breakpoints, Sources, Console) ──────────────────
84
- let lastKnownTargets = [];
85
-
86
- function openCDPWindow(target) {
87
- if (devtoolsWindow && !devtoolsWindow.isDestroyed()) {
88
- devtoolsWindow.focus();
89
- return;
90
- }
91
-
92
- // Build the frontend URL from Metro's provided devtoolsFrontendUrl
93
- // Metro /json/list returns: { devtoolsFrontendUrl: "/debugger-frontend/rn_fusebox.html?ws=...", ... }
94
- let frontendUrl;
95
- if (target.devtoolsFrontendUrl) {
96
- // Metro provides the exact path — use it
97
- frontendUrl = `http://localhost:${PORTS.METRO}${target.devtoolsFrontendUrl}`;
98
- } else if (target.webSocketDebuggerUrl) {
99
- // Fallback: construct URL manually with rn_fusebox (RN 0.76+) or rn_inspector (older)
100
- const wsUrl = target.webSocketDebuggerUrl;
101
- frontendUrl = `http://localhost:${PORTS.METRO}/debugger-frontend/rn_fusebox.html?ws=${encodeURIComponent(wsUrl)}&sources.hide_add_folder=true`;
102
- } else {
103
- console.warn('[CDP] No usable target URL');
104
- return;
105
- }
106
-
107
- const titleSuffix = target.deviceName ? ` — ${target.deviceName}` : '';
108
- devtoolsWindow = new BrowserWindow({
109
- width: 1200,
110
- height: 800,
111
- titleBarStyle: 'hiddenInset',
112
- backgroundColor: '#0a0b0e',
113
- title: `JS Debugger${titleSuffix}`,
114
- webPreferences: {
115
- nodeIntegration: false,
116
- contextIsolation: false,
117
- },
118
- });
119
-
120
- console.log(`[CDP] Loading DevTools: ${frontendUrl}`);
121
- devtoolsWindow.loadURL(frontendUrl);
122
-
123
- devtoolsWindow.on('closed', () => { devtoolsWindow = null; });
124
- }
125
-
126
- // ─── Metro CDP — fetch targets on demand (no continuous polling) ──────────────
127
- // Continuous polling causes Metro's dev-middleware WebSocket to crash with
128
- // "readyState 3 (CLOSED)" when connections are opened/closed rapidly.
129
- // Instead, we fetch targets only when the user needs them.
130
- function fetchCDPTargets(callback) {
131
- http.get(`http://localhost:${PORTS.METRO}/json/list`, (res) => {
132
- let data = '';
133
- res.on('data', d => data += d);
134
- res.on('end', () => {
135
- try {
136
- const targets = JSON.parse(data);
137
- const rnTargets = targets.filter(t =>
138
- t.type === 'node' || t.devtoolsFrontendUrl
139
- );
140
- lastKnownTargets = rnTargets;
141
- mainWindow?.webContents.send('cdp-targets', rnTargets);
142
- if (callback) callback(rnTargets);
143
- } catch (_) {
144
- if (callback) callback([]);
145
- }
146
- });
147
- }).on('error', () => {
148
- lastKnownTargets = [];
149
- mainWindow?.webContents.send('cdp-targets', []);
150
- if (callback) callback([]);
151
- });
152
- }
153
-
154
- function setupMetroCDPProxy() {
155
- // Single fetch after app starts (not continuous polling)
156
- setTimeout(() => fetchCDPTargets(), 3000);
157
- }
158
-
159
- // ─── React DevTools Relay Server (Component Tree + Profiler) ─────────────────
160
- // React Native automatically connects to ws://localhost:8097 in dev mode.
161
- // We run a simple WS relay on that port. When a standalone react-devtools
162
- // window connects (via `npx react-devtools`) or when the RN app connects,
163
- // we track the connection and relay messages between frontend ↔ backend.
164
- let reactDTServer = null;
165
- let reactDTClients = new Set();
166
-
167
- function startReactDevToolsServer() {
168
- try {
169
- reactDTServer = new WebSocketServer({ port: PORTS.REACT_DT });
170
- reactDTServer.on('error', (err) => {
171
- console.warn(`[ReactDT] Server error: ${err.message}`);
172
- if (err.code === 'EADDRINUSE') {
173
- mainWindow?.webContents.send('react-dt-status', false);
174
- }
175
- });
176
- reactDTServer.on('connection', (ws) => {
177
- reactDTClients.add(ws);
178
- console.log(`[ReactDT] Client connected (total: ${reactDTClients.size})`);
179
- mainWindow?.webContents.send('react-dt-status', true);
180
-
181
- // Relay messages between all connected clients (frontend ↔ backend)
182
- ws.on('message', (data) => {
183
- reactDTClients.forEach((client) => {
184
- if (client !== ws && client.readyState === WebSocket.OPEN) {
185
- client.send(data);
186
- }
187
- });
188
- });
189
-
190
- ws.on('close', () => {
191
- reactDTClients.delete(ws);
192
- console.log(`[ReactDT] Client disconnected (total: ${reactDTClients.size})`);
193
- if (reactDTClients.size === 0) {
194
- mainWindow?.webContents.send('react-dt-status', false);
195
- }
196
- });
197
- });
198
- console.log(`[ReactDT] Relay server on :${PORTS.REACT_DT}`);
199
- } catch (e) {
200
- console.warn('[ReactDT] Failed to start relay server:', e.message);
201
- }
202
- }
203
-
204
- // ─── Bridge Servers (Redux, Storage, Network) ─────────────────────────────────
205
- function startBridgeServers() {
206
- // Redux Bridge
207
- startBridge(PORTS.REDUX_BRIDGE, 'redux', reduxClients, (event) => {
208
- mainWindow?.webContents.send('redux-event', event);
209
- });
210
-
211
- // AsyncStorage Bridge
212
- startBridge(PORTS.STORAGE_BRIDGE, 'storage', storageClients, (event) => {
213
- mainWindow?.webContents.send('storage-event', event);
214
- });
215
-
216
- // Network + Console + Perf Bridge (port 9092 carries all types from RNDebugSDK)
217
- startBridge(PORTS.NETWORK_BRIDGE, 'network', networkClients, (event) => {
218
- if (event.type === 'control') return;
219
- if (event.type === 'console') {
220
- mainWindow?.webContents.send('console-event', event);
221
- } else if (event.type === 'perf') {
222
- mainWindow?.webContents.send('perf-event', event);
223
- } else {
224
- mainWindow?.webContents.send('network-event', event);
225
- }
226
- });
227
- }
228
-
229
- function startBridge(port, name, clients, onEvent) {
230
- const wss = new WebSocketServer({ port });
231
- wss.on('connection', (ws) => {
232
- clients.add(ws);
233
- console.log(`[${name}] RN app connected`);
234
- mainWindow?.webContents.send(`${name}-connected`, true);
235
-
236
- ws.on('message', (raw) => {
237
- try {
238
- const event = JSON.parse(raw.toString());
239
- onEvent(event);
240
- } catch (_) {}
241
- });
242
-
243
- ws.on('close', () => {
244
- clients.delete(ws);
245
- if (clients.size === 0) {
246
- mainWindow?.webContents.send(`${name}-connected`, false);
247
- }
248
- });
249
- });
250
- console.log(`[${name}] Bridge on :${port}`);
251
- }
252
-
253
- // ─── IPC from Renderer ────────────────────────────────────────────────────────
254
- function setupIPC() {
255
- ipcMain.on('open-cdp-target', (_, wsUrl) => {
256
- // Always fetch fresh targets, then open
257
- fetchCDPTargets((targets) => {
258
- if (wsUrl && targets.length > 0) {
259
- const target = targets.find(t => t.webSocketDebuggerUrl === wsUrl) || targets[0];
260
- openCDPWindow(target);
261
- } else if (targets.length > 0) {
262
- const target = targets.find(t =>
263
- t.reactNative?.capabilities?.prefersFuseboxFrontend
264
- ) || targets[0];
265
- openCDPWindow(target);
266
- }
267
- });
268
- });
269
-
270
- ipcMain.on('open-react-devtools', () => {
271
- // Open standalone react-devtools window
272
- const rdtWin = new BrowserWindow({
273
- width: 1100,
274
- height: 700,
275
- titleBarStyle: 'hiddenInset',
276
- backgroundColor: '#0a0b0e',
277
- title: 'React DevTools',
278
- webPreferences: { nodeIntegration: false, contextIsolation: false },
279
- });
280
- // Metro serves the React DevTools frontend at /debugger-ui
281
- rdtWin.loadURL(`http://localhost:${PORTS.METRO}/debugger-ui`);
282
- });
283
-
284
- ipcMain.on('clear-all', () => {
285
- // Broadcast clear to all bridges
286
- // (renderer handles local state clearing; no bridge action needed)
287
- });
288
-
289
- ipcMain.on('set-network-capture', (_, enabled) => {
290
- // Broadcast to connected RN apps so they can stop/start intercepting
291
- networkClients.forEach(ws => {
292
- if (ws.readyState === WebSocket.OPEN) {
293
- ws.send(JSON.stringify({ type: 'control', action: 'set-network-capture', enabled }));
294
- }
295
- });
296
- });
297
-
298
- ipcMain.on('set-network-throttle', (_, profile) => {
299
- // Broadcast throttle config to connected RN apps
300
- networkClients.forEach(ws => {
301
- if (ws.readyState === WebSocket.OPEN) {
302
- ws.send(JSON.stringify({ type: 'control', action: 'set-throttle', profile }));
303
- }
304
- });
305
- });
306
-
307
- ipcMain.on('set-theme', (_, theme) => {
308
- nativeTheme.themeSource = theme === 'light' ? 'light' : 'dark';
309
- const bg = theme === 'light' ? '#f5f6f8' : '#0a0b0e';
310
- if (mainWindow && !mainWindow.isDestroyed()) {
311
- mainWindow.setBackgroundColor(bg);
312
- }
313
- });
314
- }
315
-
316
- // ─── macOS App Menu ───────────────────────────────────────────────────────────
317
- function buildMenu() {
318
- const template = [
319
- {
320
- label: app.name,
321
- submenu: [
322
- { role: 'about' },
323
- { type: 'separator' },
324
- { role: 'hide' }, { role: 'hideOthers' }, { role: 'unhide' },
325
- { type: 'separator' },
326
- { role: 'quit' },
327
- ],
328
- },
329
- {
330
- label: 'Debugger',
331
- submenu: [
332
- {
333
- label: 'Open JS Debugger (CDP)',
334
- accelerator: 'Cmd+D',
335
- click: () => { mainWindow?.webContents.send('trigger-open-cdp'); },
336
- },
337
- {
338
- label: 'Open React DevTools',
339
- accelerator: 'Cmd+R',
340
- click: () => { ipcMain.emit('open-react-devtools'); },
341
- },
342
- { type: 'separator' },
343
- {
344
- label: 'Clear All',
345
- accelerator: 'Cmd+K',
346
- click: () => { mainWindow?.webContents.send('clear-all-ui'); },
347
- },
348
- { type: 'separator' },
349
- {
350
- label: 'Toggle Dark/Light Mode',
351
- accelerator: 'Cmd+Shift+T',
352
- click: () => {
353
- const next = nativeTheme.themeSource === 'dark' ? 'light' : 'dark';
354
- nativeTheme.themeSource = next;
355
- const bg = next === 'light' ? '#f5f6f8' : '#0a0b0e';
356
- if (mainWindow && !mainWindow.isDestroyed()) {
357
- mainWindow.setBackgroundColor(bg);
358
- mainWindow.webContents.send('theme-changed', next);
359
- }
360
- },
361
- },
362
- ],
363
- },
364
- {
365
- label: 'Edit',
366
- submenu: [
367
- { role: 'undo' },
368
- { role: 'redo' },
369
- { type: 'separator' },
370
- { role: 'cut' },
371
- { role: 'copy' },
372
- { role: 'paste' },
373
- { role: 'selectAll' },
374
- ],
375
- },
376
- {
377
- label: 'View',
378
- submenu: [
379
- { role: 'reload' }, { role: 'forceReload' },
380
- { type: 'separator' },
381
- { role: 'resetZoom' }, { role: 'zoomIn' }, { role: 'zoomOut' },
382
- { type: 'separator' },
383
- { role: 'togglefullscreen' },
384
- ],
385
- },
386
- {
387
- label: 'Window',
388
- submenu: [
389
- { role: 'minimize' }, { role: 'zoom' },
390
- { type: 'separator' },
391
- { role: 'front' },
392
- ],
393
- },
394
- ];
395
- Menu.setApplicationMenu(Menu.buildFromTemplate(template));
396
- }
@@ -1,28 +0,0 @@
1
- 'use strict';
2
-
3
- const { contextBridge, ipcRenderer } = require('electron');
4
-
5
- const registeredChannels = new Set();
6
-
7
- contextBridge.exposeInMainWorld('electronAPI', {
8
- // Listen from main (idempotent — only one listener per channel)
9
- on: (channel, cb) => {
10
- const allowed = [
11
- 'ports', 'cdp-targets', 'redux-event', 'storage-event', 'network-event',
12
- 'console-event', 'perf-event', 'redux-connected', 'storage-connected', 'network-connected',
13
- 'react-dt-status', 'trigger-open-cdp', 'clear-all-ui', 'theme-changed',
14
- ];
15
- if (allowed.includes(channel)) {
16
- ipcRenderer.removeAllListeners(channel);
17
- registeredChannels.add(channel);
18
- ipcRenderer.on(channel, (_, ...args) => cb(...args));
19
- }
20
- },
21
- // Send to main
22
- openCDPTarget: (wsUrl) => ipcRenderer.send('open-cdp-target', wsUrl),
23
- openReactDevTools: () => ipcRenderer.send('open-react-devtools'),
24
- clearAll: () => ipcRenderer.send('clear-all'),
25
- setTheme: (theme) => ipcRenderer.send('set-theme', theme),
26
- setNetworkCapture: (enabled) => ipcRenderer.send('set-network-capture', enabled),
27
- setNetworkThrottle: (profile) => ipcRenderer.send('set-network-throttle', profile),
28
- });