react-native-debug-toolkit 3.0.0 → 3.1.3

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 (83) hide show
  1. package/README.md +115 -97
  2. package/README.zh-CN.md +113 -95
  3. package/lib/commonjs/core/initialize.js +5 -0
  4. package/lib/commonjs/core/initialize.js.map +1 -1
  5. package/lib/commonjs/index.js +23 -26
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/ui/panel/StreamingSettingsModal.js +24 -58
  8. package/lib/commonjs/ui/panel/StreamingSettingsModal.js.map +1 -1
  9. package/lib/commonjs/utils/DaemonClient.js +721 -0
  10. package/lib/commonjs/utils/DaemonClient.js.map +1 -0
  11. package/lib/commonjs/utils/{sessionReport.js → deviceReport.js} +3 -3
  12. package/lib/commonjs/utils/deviceReport.js.map +1 -0
  13. package/lib/module/core/initialize.js +6 -0
  14. package/lib/module/core/initialize.js.map +1 -1
  15. package/lib/module/index.js +3 -5
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/ui/panel/StreamingSettingsModal.js +21 -55
  18. package/lib/module/ui/panel/StreamingSettingsModal.js.map +1 -1
  19. package/lib/module/utils/DaemonClient.js +703 -0
  20. package/lib/module/utils/DaemonClient.js.map +1 -0
  21. package/lib/module/utils/{sessionReport.js → deviceReport.js} +2 -2
  22. package/lib/module/utils/deviceReport.js.map +1 -0
  23. package/lib/typescript/src/core/initialize.d.ts.map +1 -1
  24. package/lib/typescript/src/index.d.ts +5 -10
  25. package/lib/typescript/src/index.d.ts.map +1 -1
  26. package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts.map +1 -1
  27. package/lib/typescript/src/utils/DaemonClient.d.ts +141 -0
  28. package/lib/typescript/src/utils/DaemonClient.d.ts.map +1 -0
  29. package/lib/typescript/src/utils/{sessionReport.d.ts → deviceReport.d.ts} +4 -4
  30. package/lib/typescript/src/utils/deviceReport.d.ts.map +1 -0
  31. package/node/daemon/src/cli.js +9 -2
  32. package/node/daemon/src/console/console.html +1052 -249
  33. package/node/daemon/src/constants.js +6 -0
  34. package/node/daemon/src/server.js +205 -123
  35. package/node/daemon/src/store.js +122 -45
  36. package/node/mcp/src/daemonClient.js +6 -6
  37. package/node/mcp/src/index.js +2 -2
  38. package/node/mcp/src/logs.js +5 -4
  39. package/node/mcp/src/tools.js +16 -16
  40. package/package.json +2 -2
  41. package/src/core/initialize.ts +8 -0
  42. package/src/index.ts +18 -10
  43. package/src/ui/panel/StreamingSettingsModal.tsx +25 -63
  44. package/src/utils/DaemonClient.ts +887 -0
  45. package/src/utils/{sessionReport.ts → deviceReport.ts} +6 -6
  46. package/lib/commonjs/utils/autoDetectDaemon.js +0 -141
  47. package/lib/commonjs/utils/autoDetectDaemon.js.map +0 -1
  48. package/lib/commonjs/utils/daemonConnection.js +0 -81
  49. package/lib/commonjs/utils/daemonConnection.js.map +0 -1
  50. package/lib/commonjs/utils/daemonSettings.js +0 -110
  51. package/lib/commonjs/utils/daemonSettings.js.map +0 -1
  52. package/lib/commonjs/utils/reportToDaemon.js +0 -112
  53. package/lib/commonjs/utils/reportToDaemon.js.map +0 -1
  54. package/lib/commonjs/utils/sessionReport.js.map +0 -1
  55. package/lib/commonjs/utils/streamToDaemon.js +0 -334
  56. package/lib/commonjs/utils/streamToDaemon.js.map +0 -1
  57. package/lib/module/utils/autoDetectDaemon.js +0 -136
  58. package/lib/module/utils/autoDetectDaemon.js.map +0 -1
  59. package/lib/module/utils/daemonConnection.js +0 -77
  60. package/lib/module/utils/daemonConnection.js.map +0 -1
  61. package/lib/module/utils/daemonSettings.js +0 -102
  62. package/lib/module/utils/daemonSettings.js.map +0 -1
  63. package/lib/module/utils/reportToDaemon.js +0 -105
  64. package/lib/module/utils/reportToDaemon.js.map +0 -1
  65. package/lib/module/utils/sessionReport.js.map +0 -1
  66. package/lib/module/utils/streamToDaemon.js +0 -328
  67. package/lib/module/utils/streamToDaemon.js.map +0 -1
  68. package/lib/typescript/src/utils/autoDetectDaemon.d.ts +0 -15
  69. package/lib/typescript/src/utils/autoDetectDaemon.d.ts.map +0 -1
  70. package/lib/typescript/src/utils/daemonConnection.d.ts +0 -18
  71. package/lib/typescript/src/utils/daemonConnection.d.ts.map +0 -1
  72. package/lib/typescript/src/utils/daemonSettings.d.ts +0 -19
  73. package/lib/typescript/src/utils/daemonSettings.d.ts.map +0 -1
  74. package/lib/typescript/src/utils/reportToDaemon.d.ts +0 -34
  75. package/lib/typescript/src/utils/reportToDaemon.d.ts.map +0 -1
  76. package/lib/typescript/src/utils/sessionReport.d.ts.map +0 -1
  77. package/lib/typescript/src/utils/streamToDaemon.d.ts +0 -23
  78. package/lib/typescript/src/utils/streamToDaemon.d.ts.map +0 -1
  79. package/src/utils/autoDetectDaemon.ts +0 -175
  80. package/src/utils/daemonConnection.ts +0 -133
  81. package/src/utils/daemonSettings.ts +0 -134
  82. package/src/utils/reportToDaemon.ts +0 -172
  83. package/src/utils/streamToDaemon.ts +0 -419
@@ -2,14 +2,14 @@
2
2
 
3
3
  const { ensureDaemon } = require('./daemonClient');
4
4
  const { handleMessage, startStdioServer } = require('./server');
5
- const { callTool, getAppLogsTool, listAppSessionsTool, tools } = require('./tools');
5
+ const { callTool, getAppLogsTool, listAppDevicesTool, tools } = require('./tools');
6
6
 
7
7
  module.exports = {
8
8
  callTool,
9
9
  ensureDaemon,
10
10
  getAppLogsTool,
11
11
  handleMessage,
12
- listAppSessionsTool,
12
+ listAppDevicesTool,
13
13
  startStdioServer,
14
14
  tools,
15
15
  };
@@ -70,14 +70,15 @@ function selectLogs(report, options = {}) {
70
70
  }));
71
71
  }
72
72
 
73
- function createToolPayload(session, options = {}) {
74
- const report = session.report || { version: 2, logs: {} };
73
+ function createToolPayload(device, options = {}) {
74
+ const report = device.report || { version: 2, logs: {} };
75
75
  const logs = selectLogs(report, options);
76
76
 
77
77
  return {
78
78
  ok: true,
79
- sessionId: session.sessionId,
80
- receivedAt: session.receivedAt,
79
+ deviceId: device.deviceId,
80
+ receivedAt: device.receivedAt,
81
+ lastSeenAt: device.lastSeenAt,
81
82
  logType: options.logType || 'all',
82
83
  failedOnly: options.failedOnly === true,
83
84
  includeBodies: options.includeBodies !== false,
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
- const { getDaemonOrigin, readSession, readSessions } = require('./daemonClient');
3
+ const { getDaemonOrigin, readDevice, readDevices } = require('./daemonClient');
4
4
  const { KNOWN_LOG_TYPES, createToolPayload } = require('./logs');
5
5
 
6
6
  const getAppLogsTool = {
7
7
  name: 'get_app_logs',
8
- description: 'Read React Native Debug Toolkit logs from the local daemon. Tip: if you have shell access, curl http://127.0.0.1:3799/sessions/latest is more efficient.',
8
+ description: 'Read React Native Debug Toolkit logs from the local daemon. Tip: if you have shell access, curl http://127.0.0.1:3799/devices/latest is more efficient.',
9
9
  inputSchema: {
10
10
  type: 'object',
11
11
  properties: {
12
- sessionId: { type: 'string' },
12
+ deviceId: { type: 'string' },
13
13
  logType: {
14
14
  type: 'string',
15
15
  enum: KNOWN_LOG_TYPES,
@@ -21,16 +21,16 @@ const getAppLogsTool = {
21
21
  },
22
22
  };
23
23
 
24
- const listAppSessionsTool = {
25
- name: 'list_app_sessions',
26
- description: 'List React Native Debug Toolkit sessions available in the local daemon. Tip: if you have shell access, curl http://127.0.0.1:3799/sessions is more efficient.',
24
+ const listAppDevicesTool = {
25
+ name: 'list_app_devices',
26
+ description: 'List React Native Debug Toolkit devices available in the local daemon. Tip: if you have shell access, curl http://127.0.0.1:3799/devices is more efficient.',
27
27
  inputSchema: {
28
28
  type: 'object',
29
29
  properties: {},
30
30
  },
31
31
  };
32
32
 
33
- const tools = [getAppLogsTool, listAppSessionsTool];
33
+ const tools = [getAppLogsTool, listAppDevicesTool];
34
34
 
35
35
  async function callTool(name, args = {}, context = {}) {
36
36
  const ensureDaemon = context.ensureDaemon || (async () => ({ ok: true, origin: getDaemonOrigin() }));
@@ -44,15 +44,15 @@ async function callTool(name, args = {}, context = {}) {
44
44
  }
45
45
 
46
46
  try {
47
- if (name === listAppSessionsTool.name) {
48
- const readSessionsImpl = context.readSessions || readSessions;
49
- const result = await readSessionsImpl(daemon.origin);
50
- const sessions = Array.isArray(result.sessions) ? result.sessions : [];
47
+ if (name === listAppDevicesTool.name) {
48
+ const readDevicesImpl = context.readDevices || readDevices;
49
+ const result = await readDevicesImpl(daemon.origin);
50
+ const devices = Array.isArray(result.devices) ? result.devices : [];
51
51
  return {
52
52
  ok: true,
53
53
  origin: daemon.origin,
54
- sessions,
55
- count: sessions.length,
54
+ devices,
55
+ count: devices.length,
56
56
  };
57
57
  }
58
58
 
@@ -60,8 +60,8 @@ async function callTool(name, args = {}, context = {}) {
60
60
  throw new Error(`Unknown tool: ${name}`);
61
61
  }
62
62
 
63
- const session = await readSession(daemon.origin, args.sessionId);
64
- return createToolPayload(session, {
63
+ const device = await readDevice(daemon.origin, args.deviceId);
64
+ return createToolPayload(device, {
65
65
  logType: args.logType,
66
66
  limit: args.limit,
67
67
  failedOnly: args.failedOnly,
@@ -79,6 +79,6 @@ async function callTool(name, args = {}, context = {}) {
79
79
  module.exports = {
80
80
  callTool,
81
81
  getAppLogsTool,
82
- listAppSessionsTool,
82
+ listAppDevicesTool,
83
83
  tools,
84
84
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-debug-toolkit",
3
- "version": "3.0.0",
4
- "description": "A dev-only floating debug panel for React Native with network, console, Zustand, navigation, and event logs",
3
+ "version": "3.1.3",
4
+ "description": "A local-first React Native debugging bridge with in-app logs, desktop daemon, Web Console, HTTP API, and MCP support",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
7
7
  "types": "lib/typescript/src/index.d.ts",
@@ -11,10 +11,16 @@ import { createTrackFeature } from '../features/track';
11
11
  import type { TrackFeatureConfig } from '../features/track';
12
12
  import { createEnvironmentFeature } from '../features/environment';
13
13
  import { createClipboardFeature } from '../features/clipboard';
14
+ import { daemonClient, restoreDaemonStreaming } from '../utils/DaemonClient';
15
+ import { _addDaemonEndpointToNetworkBlacklist } from '../features/network';
14
16
  import type { AnyDebugFeature, BuiltInFeatureName } from '../types';
15
17
 
16
18
  const isDebugMode = __DEV__;
17
19
 
20
+ daemonClient.setEndpointDetector((url) => {
21
+ _addDaemonEndpointToNetworkBlacklist(url);
22
+ });
23
+
18
24
  /** Feature-specific configuration map */
19
25
  export interface FeatureConfigs {
20
26
  network?: boolean | NetworkFeatureConfig;
@@ -114,6 +120,8 @@ export function initializeDebugToolkit(
114
120
  DebugToolkit.hideLauncher();
115
121
  }
116
122
 
123
+ restoreDaemonStreaming().catch(() => {});
124
+
117
125
  return DebugToolkit;
118
126
  } catch (error) {
119
127
  console.error('[DebugToolkit] Initialization failed:', error);
package/src/index.ts CHANGED
@@ -28,20 +28,28 @@ export { useNavigationLogger } from './features/navigation/useNavigationLogger';
28
28
  export { safeStringify } from './utils/safeStringify';
29
29
  export { copyToComputer, logToComputer, fmt } from './utils/copyToComputer';
30
30
  export type { CopyResult, CopyOptions, CopyMethod } from './utils/copyToComputer';
31
- export { createDebugSessionReport } from './utils/sessionReport';
32
- export type { DebugSessionReport, DebugSessionReportOptions } from './utils/sessionReport';
33
- export { getDefaultDaemonEndpoint, reportDebugSessionToDaemon } from './utils/reportToDaemon';
34
- export type { ReportResult, ReportToDaemonOptions } from './utils/reportToDaemon';
35
- export { checkDaemonConnection } from './utils/daemonConnection';
31
+ export { createDebugDeviceReport } from './utils/deviceReport';
32
+ export type { DebugDeviceReport, DebugDeviceReportOptions } from './utils/deviceReport';
33
+ export { DaemonClient, daemonClient } from './utils/DaemonClient';
36
34
  export type {
35
+ DaemonSettings,
36
+ DaemonConnectionMode,
37
37
  DaemonConnectionFailureReason,
38
38
  DaemonConnectionOptions,
39
39
  DaemonConnectionResult,
40
- } from './utils/daemonConnection';
41
- export { startStreaming, stopStreaming, isStreaming } from './utils/streamToDaemon';
42
- export type { StreamStatus, StreamToDaemonOptions } from './utils/streamToDaemon';
43
- export { autoDetectDaemonIp, getMetroHost } from './utils/autoDetectDaemon';
44
- export type { AutoDetectOptions, AutoDetectResult } from './utils/autoDetectDaemon';
40
+ StreamStatus,
41
+ StreamToDaemonOptions,
42
+ ReportResult,
43
+ ReportToDaemonOptions,
44
+ } from './utils/DaemonClient';
45
+ export {
46
+ getDefaultDaemonEndpoint,
47
+ reportDebugDeviceToDaemon,
48
+ checkDaemonConnection,
49
+ startStreaming,
50
+ stopStreaming,
51
+ isStreaming,
52
+ } from './utils/DaemonClient';
45
53
 
46
54
  // Types
47
55
  export type {
@@ -13,17 +13,13 @@ import {
13
13
  } from 'react-native';
14
14
  import { Colors } from '../theme/colors';
15
15
  import {
16
- buildDeviceDaemonEndpoint,
16
+ daemonClient,
17
17
  type DaemonConnectionMode,
18
18
  type DaemonSettings,
19
- loadDaemonSettings,
19
+ buildDeviceDaemonEndpoint,
20
20
  normalizeDaemonSettings,
21
- saveDaemonSettings,
22
- } from '../../utils/daemonSettings';
23
- import { checkDaemonConnection } from '../../utils/daemonConnection';
24
- import { getDefaultDaemonEndpoint, reportDebugSessionToDaemon } from '../../utils/reportToDaemon';
25
- import { autoDetectDaemonIp, getMetroHost } from '../../utils/autoDetectDaemon';
26
- import { startStreaming, stopStreaming, isStreaming } from '../../utils/streamToDaemon';
21
+ getDefaultDaemonEndpoint,
22
+ } from '../../utils/DaemonClient';
27
23
 
28
24
  interface StreamingSettingsModalProps {
29
25
  visible: boolean;
@@ -42,11 +38,10 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
42
38
  const inputRef = useRef<TextInput>(null);
43
39
  const [mode, setMode] = useState<DaemonConnectionMode>('simulator');
44
40
  const [deviceHost, setDeviceHost] = useState('');
45
- const [streaming, setStreaming] = useState(isStreaming());
46
- const [syncState, setSyncState] = useState<SyncUiState>(isStreaming() ? 'running' : 'idle');
41
+ const [streaming, setStreaming] = useState(daemonClient.isConnected());
42
+ const [syncState, setSyncState] = useState<SyncUiState>(daemonClient.isConnected() ? 'running' : 'idle');
47
43
  const [message, setMessage] = useState<string | null>(null);
48
44
  const [sending, setSending] = useState(false);
49
- const [detecting, setDetecting] = useState(false);
50
45
 
51
46
  const handleDeviceHostChange = useCallback((value: string) => {
52
47
  setDeviceHost(value);
@@ -57,44 +52,19 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
57
52
  }, [syncState]);
58
53
 
59
54
  const detectDeviceHost = useCallback(async () => {
60
- setDetecting(true);
61
- setMessage('Detecting desktop...');
62
- const result = await autoDetectDaemonIp({
63
- timeoutMs: 800,
64
- scanSubnets: false,
65
- });
66
- setDetecting(false);
67
-
68
- if (result.ip) {
69
- setDeviceHost((current) => current.trim() ? current : result.ip || current);
70
- setMessage(`Detected desktop at ${buildDeviceDaemonEndpoint(result.ip)}.`);
71
- return;
72
- }
73
-
74
55
  setMessage('Enter your Mac IP, or open /health on the phone browser to verify reachability.');
75
56
  }, []);
76
57
 
77
58
  useEffect(() => {
78
59
  if (visible) {
79
- loadDaemonSettings().then((settings) => {
80
- setMode(settings.mode);
81
- const savedHost = settings.deviceHost;
82
- if (settings.mode === 'device' && !savedHost) {
83
- const metroHost = getMetroHost();
84
- if (metroHost) {
85
- setDeviceHost(metroHost);
86
- } else {
87
- detectDeviceHost();
88
- }
89
- } else {
90
- setDeviceHost(savedHost);
91
- }
92
- });
60
+ const settings = daemonClient.getSettings();
61
+ setMode(settings.mode);
62
+ setDeviceHost(settings.deviceHost);
93
63
  }
94
- }, [detectDeviceHost, visible]);
64
+ }, [visible]);
95
65
 
96
66
  useEffect(() => {
97
- const active = isStreaming();
67
+ const active = daemonClient.isConnected();
98
68
  setStreaming(active);
99
69
  setSyncState(active ? 'running' : 'idle');
100
70
  }, [visible]);
@@ -116,19 +86,12 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
116
86
 
117
87
  const handleModeChange = useCallback((nextMode: DaemonConnectionMode) => {
118
88
  setMode(nextMode);
119
- if (nextMode === 'device' && !deviceHost) {
120
- const metroHost = getMetroHost();
121
- if (metroHost) {
122
- setDeviceHost(metroHost);
123
- } else {
124
- detectDeviceHost();
125
- }
126
- }
127
- }, [detectDeviceHost, deviceHost]);
89
+ }, []);
128
90
 
129
91
  const toggleLiveSync = useCallback(async () => {
130
92
  if (streaming) {
131
- stopStreaming();
93
+ daemonClient.disconnect();
94
+ daemonClient.setStreamingEnabled(false);
132
95
  setStreaming(false);
133
96
  setSyncState('idle');
134
97
  setMessage(null);
@@ -143,9 +106,9 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
143
106
  const daemonOptions = normalizeDaemonSettings(settings);
144
107
  setMessage('Checking desktop connection...');
145
108
  setSyncState('connecting');
146
- await saveDaemonSettings(settings);
109
+ daemonClient.configure(settings);
147
110
 
148
- const connection = await checkDaemonConnection({
111
+ const connection = await daemonClient.checkConnection({
149
112
  ...daemonOptions,
150
113
  timeoutMs: CONNECTION_TIMEOUT_MS,
151
114
  });
@@ -156,7 +119,8 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
156
119
  return;
157
120
  }
158
121
 
159
- startStreaming({
122
+ daemonClient.setStreamingEnabled(true);
123
+ daemonClient.connect({
160
124
  ...daemonOptions,
161
125
  timeoutMs: 3000,
162
126
  onStatus: (status) => {
@@ -191,10 +155,10 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
191
155
  const daemonOptions = normalizeDaemonSettings(settings);
192
156
  setSending(true);
193
157
  setMessage('Checking desktop connection...');
194
- await saveDaemonSettings(settings);
158
+ daemonClient.configure(settings);
195
159
 
196
160
  try {
197
- const connection = await checkDaemonConnection({
161
+ const connection = await daemonClient.checkConnection({
198
162
  ...daemonOptions,
199
163
  timeoutMs: CONNECTION_TIMEOUT_MS,
200
164
  });
@@ -204,7 +168,7 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
204
168
  }
205
169
 
206
170
  setMessage('Sending logs...');
207
- const result = await reportDebugSessionToDaemon({
171
+ const result = await daemonClient.reportOnce({
208
172
  ...daemonOptions,
209
173
  timeoutMs: 2000,
210
174
  });
@@ -225,12 +189,10 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
225
189
  : getDefaultDaemonEndpoint();
226
190
  const canConnect = mode === 'simulator' || Boolean(deviceHost.trim());
227
191
  const connecting = !streaming && syncState === 'connecting';
228
- const busy = detecting || sending || connecting;
229
- const statusTitle = detecting
192
+ const busy = sending || connecting;
193
+ const statusTitle = sending
230
194
  ? 'Checking'
231
- : sending
232
- ? 'Checking'
233
- : connecting
195
+ : connecting
234
196
  ? 'Checking'
235
197
  : streaming && syncState === 'connected'
236
198
  ? 'Live sync connected'
@@ -324,7 +286,7 @@ export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsMo
324
286
  disabled={streaming || busy}
325
287
  activeOpacity={0.7}
326
288
  >
327
- <Text style={styles.detectButtonText}>{detecting ? '...' : 'Detect'}</Text>
289
+ <Text style={styles.detectButtonText}>?</Text>
328
290
  </TouchableOpacity>
329
291
  </View>
330
292
  </View>