react-native-debug-toolkit 3.2.1 → 3.2.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 (66) hide show
  1. package/README.md +13 -2
  2. package/README.zh-CN.md +13 -2
  3. package/android/build.gradle +34 -0
  4. package/android/src/main/AndroidManifest.xml +1 -0
  5. package/android/src/main/java/com/reactnativedebugtoolkit/DebugToolkitDevConnectModule.java +154 -0
  6. package/android/src/main/java/com/reactnativedebugtoolkit/ReactNativeDebugToolkitPackage.java +25 -0
  7. package/ios/DebugToolkitDevConnect.mm +81 -0
  8. package/lib/commonjs/features/devConnect/DevConnectQrScanner.js +115 -70
  9. package/lib/commonjs/features/devConnect/DevConnectQrScanner.js.map +1 -1
  10. package/lib/commonjs/features/devConnect/DevConnectTab.js +232 -161
  11. package/lib/commonjs/features/devConnect/DevConnectTab.js.map +1 -1
  12. package/lib/commonjs/features/devConnect/devConnectPreferences.js +35 -5
  13. package/lib/commonjs/features/devConnect/devConnectPreferences.js.map +1 -1
  14. package/lib/commonjs/features/devConnect/devConnectUtils.js +99 -15
  15. package/lib/commonjs/features/devConnect/devConnectUtils.js.map +1 -1
  16. package/lib/commonjs/features/devConnect/index.js +39 -2
  17. package/lib/commonjs/features/devConnect/index.js.map +1 -1
  18. package/lib/commonjs/features/devConnect/nativeDevConnect.js +108 -0
  19. package/lib/commonjs/features/devConnect/nativeDevConnect.js.map +1 -0
  20. package/lib/commonjs/features/devConnect/platformDetect.js +7 -11
  21. package/lib/commonjs/features/devConnect/platformDetect.js.map +1 -1
  22. package/lib/commonjs/utils/debugPreferences.js +43 -6
  23. package/lib/commonjs/utils/debugPreferences.js.map +1 -1
  24. package/lib/module/features/devConnect/DevConnectQrScanner.js +116 -71
  25. package/lib/module/features/devConnect/DevConnectQrScanner.js.map +1 -1
  26. package/lib/module/features/devConnect/DevConnectTab.js +235 -164
  27. package/lib/module/features/devConnect/DevConnectTab.js.map +1 -1
  28. package/lib/module/features/devConnect/devConnectPreferences.js +33 -6
  29. package/lib/module/features/devConnect/devConnectPreferences.js.map +1 -1
  30. package/lib/module/features/devConnect/devConnectUtils.js +94 -15
  31. package/lib/module/features/devConnect/devConnectUtils.js.map +1 -1
  32. package/lib/module/features/devConnect/index.js +11 -3
  33. package/lib/module/features/devConnect/index.js.map +1 -1
  34. package/lib/module/features/devConnect/nativeDevConnect.js +102 -0
  35. package/lib/module/features/devConnect/nativeDevConnect.js.map +1 -0
  36. package/lib/module/features/devConnect/platformDetect.js +8 -12
  37. package/lib/module/features/devConnect/platformDetect.js.map +1 -1
  38. package/lib/module/utils/debugPreferences.js +43 -6
  39. package/lib/module/utils/debugPreferences.js.map +1 -1
  40. package/lib/typescript/src/features/devConnect/DevConnectQrScanner.d.ts +3 -2
  41. package/lib/typescript/src/features/devConnect/DevConnectQrScanner.d.ts.map +1 -1
  42. package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts.map +1 -1
  43. package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts +6 -0
  44. package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts.map +1 -1
  45. package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts +18 -1
  46. package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts.map +1 -1
  47. package/lib/typescript/src/features/devConnect/index.d.ts +2 -2
  48. package/lib/typescript/src/features/devConnect/index.d.ts.map +1 -1
  49. package/lib/typescript/src/features/devConnect/nativeDevConnect.d.ts +17 -0
  50. package/lib/typescript/src/features/devConnect/nativeDevConnect.d.ts.map +1 -0
  51. package/lib/typescript/src/features/devConnect/platformDetect.d.ts.map +1 -1
  52. package/lib/typescript/src/features/devConnect/types.d.ts +3 -0
  53. package/lib/typescript/src/features/devConnect/types.d.ts.map +1 -1
  54. package/lib/typescript/src/utils/debugPreferences.d.ts +2 -0
  55. package/lib/typescript/src/utils/debugPreferences.d.ts.map +1 -1
  56. package/package.json +4 -1
  57. package/react-native-debug-toolkit.podspec +18 -0
  58. package/src/features/devConnect/DevConnectQrScanner.tsx +101 -60
  59. package/src/features/devConnect/DevConnectTab.tsx +227 -105
  60. package/src/features/devConnect/devConnectPreferences.ts +50 -5
  61. package/src/features/devConnect/devConnectUtils.ts +122 -15
  62. package/src/features/devConnect/index.ts +13 -0
  63. package/src/features/devConnect/nativeDevConnect.ts +126 -0
  64. package/src/features/devConnect/platformDetect.ts +8 -13
  65. package/src/features/devConnect/types.ts +3 -0
  66. package/src/utils/debugPreferences.ts +49 -4
@@ -0,0 +1,17 @@
1
+ type MetroBundleFailureReason = 'invalid_target' | 'native_unavailable' | 'fetch_unavailable' | 'metro_unreachable' | 'native_error';
2
+ export type MetroBundleResult = {
3
+ ok: true;
4
+ hostPort: string;
5
+ } | {
6
+ ok: false;
7
+ reason: MetroBundleFailureReason;
8
+ error?: string;
9
+ statusUrl?: string;
10
+ };
11
+ export declare function isNativeDevConnectAvailable(): boolean;
12
+ export declare function applyMetroBundle(host: string, port: string): Promise<MetroBundleResult>;
13
+ export declare function resetMetroBundle(): Promise<MetroBundleResult | {
14
+ ok: true;
15
+ }>;
16
+ export {};
17
+ //# sourceMappingURL=nativeDevConnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeDevConnect.d.ts","sourceRoot":"","sources":["../../../../../src/features/devConnect/nativeDevConnect.ts"],"names":[],"mappings":"AAUA,KAAK,wBAAwB,GACzB,gBAAgB,GAChB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,CAAC;AAEnB,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,wBAAwB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAsBxF,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAmCD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6B7F;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAgBlF"}
@@ -1 +1 @@
1
- {"version":3,"file":"platformDetect.d.ts","sourceRoot":"","sources":["../../../../../src/features/devConnect/platformDetect.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,IAAI,OAAO,CAuBrC"}
1
+ {"version":3,"file":"platformDetect.d.ts","sourceRoot":"","sources":["../../../../../src/features/devConnect/platformDetect.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,IAAI,OAAO,CAkBrC"}
@@ -1,7 +1,10 @@
1
1
  export interface DevConnectState {
2
2
  isSimulator: boolean;
3
3
  computerHost: string;
4
+ metroPort: string;
5
+ daemonPort: string;
4
6
  qrAvailable: boolean;
7
+ nativeMetroAvailable: boolean;
5
8
  streaming: boolean;
6
9
  }
7
10
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/features/devConnect/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/features/devConnect/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;CACpB"}
@@ -7,5 +7,7 @@ export declare const KEYS: {
7
7
  readonly networkLogs: "@react_native_debug_toolkit/network_logs";
8
8
  readonly trackLogs: "@react_native_debug_toolkit/track_logs";
9
9
  readonly computerHost: "@react_native_debug_toolkit/computer_host";
10
+ readonly metroPort: "@react_native_debug_toolkit/metro_port";
11
+ readonly daemonPort: "@react_native_debug_toolkit/daemon_port";
10
12
  };
11
13
  //# sourceMappingURL=debugPreferences.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"debugPreferences.d.ts","sourceRoot":"","sources":["../../../../src/utils/debugPreferences.ts"],"names":[],"mappings":"AAgBA,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU7E;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWvE;AAED,eAAO,MAAM,IAAI;;;;;;;CAOP,CAAC"}
1
+ {"version":3,"file":"debugPreferences.d.ts","sourceRoot":"","sources":["../../../../src/utils/debugPreferences.ts"],"names":[],"mappings":"AAkCA,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB7E;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BvE;AAED,eAAO,MAAM,IAAI;;;;;;;;;CASP,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-debug-toolkit",
3
- "version": "3.2.1",
3
+ "version": "3.2.3",
4
4
  "description": "A local-first React Native debug toolkit with Web Console, HTTP API, and MCP support for AI-readable app logs",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -10,6 +10,9 @@
10
10
  "lib",
11
11
  "bin",
12
12
  "node",
13
+ "ios",
14
+ "android",
15
+ "react-native-debug-toolkit.podspec",
13
16
  "README.md",
14
17
  "LICENSE",
15
18
  "!**/__tests__",
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'react-native-debug-toolkit'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.homepage = package['homepage']
11
+ s.license = package['license']
12
+ s.author = package['author']
13
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
14
+
15
+ s.platforms = { :ios => '12.0' }
16
+ s.source_files = 'ios/**/*.{h,m,mm}'
17
+ s.dependency 'React-Core'
18
+ end
@@ -1,7 +1,6 @@
1
1
  import React, { Component, useCallback, useEffect, useRef, useState } from 'react';
2
2
  import {
3
3
  Modal,
4
- Pressable,
5
4
  StyleSheet,
6
5
  Text,
7
6
  TouchableOpacity,
@@ -14,7 +13,7 @@ import {
14
13
  type CameraKitReadCodeEvent,
15
14
  type ExpoCameraScanResult,
16
15
  } from './cameraKit';
17
- import { parseMetroQrPayload } from './devConnectUtils';
16
+ import { parseMetroQrPayload, type ParsedComputerTarget } from './devConnectUtils';
18
17
 
19
18
  // ─── Camera Error Boundary ─────────────────────────────────
20
19
 
@@ -40,7 +39,9 @@ class CameraErrorBoundary extends Component<CameraBoundaryProps, CameraBoundaryS
40
39
  }
41
40
 
42
41
  render() {
43
- if (this.state.hasError) return null;
42
+ if (this.state.hasError) {
43
+ return null;
44
+ }
44
45
  return this.props.children;
45
46
  }
46
47
  }
@@ -50,10 +51,10 @@ class CameraErrorBoundary extends Component<CameraBoundaryProps, CameraBoundaryS
50
51
  interface DevConnectQrScannerProps {
51
52
  visible: boolean;
52
53
  onClose: () => void;
53
- onScanHost: (host: string) => void;
54
+ onScanTarget: (target: ParsedComputerTarget) => void;
54
55
  }
55
56
 
56
- export function DevConnectQrScanner({ visible, onClose, onScanHost }: DevConnectQrScannerProps) {
57
+ export function DevConnectQrScanner({ visible, onClose, onScanTarget }: DevConnectQrScannerProps) {
57
58
  const scannedRef = useRef(false);
58
59
  const [error, setError] = useState<string | null>(null);
59
60
  const [cameraFailed, setCameraFailed] = useState(false);
@@ -68,8 +69,12 @@ export function DevConnectQrScanner({ visible, onClose, onScanHost }: DevConnect
68
69
  }, [visible]);
69
70
 
70
71
  const handleScanned = useCallback((rawValue: string) => {
71
- if (scannedRef.current) return;
72
- if (typeof rawValue !== 'string') return;
72
+ if (scannedRef.current) {
73
+ return;
74
+ }
75
+ if (typeof rawValue !== 'string') {
76
+ return;
77
+ }
73
78
 
74
79
  const parsed = parseMetroQrPayload(rawValue);
75
80
  if (!parsed) {
@@ -79,9 +84,12 @@ export function DevConnectQrScanner({ visible, onClose, onScanHost }: DevConnect
79
84
 
80
85
  scannedRef.current = true;
81
86
  setError(null);
82
- onScanHost(parsed.computerHost);
87
+ onScanTarget({
88
+ computerHost: parsed.computerHost,
89
+ metroPort: parsed.metroPort,
90
+ });
83
91
  onClose();
84
- }, [onClose, onScanHost]);
92
+ }, [onClose, onScanTarget]);
85
93
 
86
94
  const handleCameraKitRead = useCallback((event: CameraKitReadCodeEvent) => {
87
95
  handleScanned(event.nativeEvent?.codeStringValue ?? '');
@@ -95,49 +103,59 @@ export function DevConnectQrScanner({ visible, onClose, onScanHost }: DevConnect
95
103
  setCameraFailed(true);
96
104
  }, []);
97
105
 
98
- if (!visible || !scanner) return null;
106
+ if (!visible || !scanner) {
107
+ return null;
108
+ }
99
109
 
100
110
  return (
101
- <Modal visible={visible} animationType="slide" onRequestClose={onClose}>
111
+ <Modal visible={visible} animationType="slide" presentationStyle="fullScreen" onRequestClose={onClose}>
102
112
  <View style={styles.container}>
103
- {!cameraFailed && (
104
- <CameraErrorBoundary onCameraError={handleCameraError}>
105
- {scanner.kind === 'camera-kit' && scanner.CameraKit ? (
106
- <scanner.CameraKit.Camera
107
- style={styles.camera}
108
- cameraType={scanner.CameraKit.CameraType?.Back}
109
- scanBarcode
110
- onReadCode={handleCameraKitRead}
111
- showFrame
112
- laserColor={Colors.primary}
113
- frameColor={Colors.primary}
114
- allowedBarcodeTypes={['qr']}
115
- />
116
- ) : scanner.kind === 'expo-camera' && scanner.ExpoCamera ? (
117
- <scanner.ExpoCamera.Camera
118
- style={styles.camera}
119
- onBarCodeScanned={handleExpoScanned}
120
- barCodeScannerSettings={{ barCodeTypes: ['qr'] }}
121
- />
122
- ) : null}
123
- </CameraErrorBoundary>
124
- )}
125
- {cameraFailed && (
126
- <View style={styles.cameraFallback}>
127
- <Text style={styles.cameraFallbackText}>Camera unavailable.</Text>
128
- <Text style={styles.cameraFallbackHint}>Please enter computer IP manually.</Text>
113
+ <View style={styles.previewLayer}>
114
+ {!cameraFailed && (
115
+ <CameraErrorBoundary onCameraError={handleCameraError}>
116
+ {scanner.kind === 'camera-kit' && scanner.CameraKit ? (
117
+ <scanner.CameraKit.Camera
118
+ style={styles.camera}
119
+ cameraType={scanner.CameraKit.CameraType?.Back}
120
+ scanBarcode
121
+ onReadCode={handleCameraKitRead}
122
+ showFrame
123
+ laserColor={Colors.primary}
124
+ frameColor={Colors.primary}
125
+ allowedBarcodeTypes={['qr']}
126
+ />
127
+ ) : scanner.kind === 'expo-camera' && scanner.ExpoCamera ? (
128
+ <scanner.ExpoCamera.Camera
129
+ style={styles.camera}
130
+ onBarCodeScanned={handleExpoScanned}
131
+ barCodeScannerSettings={{ barCodeTypes: ['qr'] }}
132
+ />
133
+ ) : null}
134
+ </CameraErrorBoundary>
135
+ )}
136
+ {cameraFailed && (
137
+ <View style={styles.cameraFallback}>
138
+ <Text style={styles.cameraFallbackText}>Camera unavailable.</Text>
139
+ <Text style={styles.cameraFallbackHint}>Please enter computer IP manually.</Text>
140
+ </View>
141
+ )}
142
+ </View>
143
+
144
+ <View style={styles.topBar}>
145
+ <View style={styles.titleGroup}>
146
+ <Text style={styles.title}>Scan Metro QR</Text>
147
+ <Text style={styles.subtitle}>Expo or Metro URL</Text>
129
148
  </View>
130
- )}
131
- <View style={styles.footer}>
132
- {!cameraFailed && !error && <Text style={styles.hint}>Scan a Metro QR code.</Text>}
133
- {error && <Text style={styles.error}>{error}</Text>}
134
- <TouchableOpacity style={styles.closeButton} onPress={onClose} activeOpacity={0.7}>
149
+ <TouchableOpacity style={styles.closeButton} onPress={onClose} activeOpacity={0.75}>
135
150
  <Text style={styles.closeButtonText}>Close</Text>
136
151
  </TouchableOpacity>
137
152
  </View>
138
- <Pressable style={styles.topClose} onPress={onClose}>
139
- <Text style={styles.topCloseText}>Close</Text>
140
- </Pressable>
153
+
154
+ <View style={[styles.statusPill, error && styles.statusPillError]}>
155
+ <Text style={[styles.statusText, error && styles.statusTextError]}>
156
+ {error ?? 'Point the camera at exp:// or http:// Metro URL.'}
157
+ </Text>
158
+ </View>
141
159
  </View>
142
160
  </Modal>
143
161
  );
@@ -145,29 +163,52 @@ export function DevConnectQrScanner({ visible, onClose, onScanHost }: DevConnect
145
163
 
146
164
  const styles = StyleSheet.create({
147
165
  container: { flex: 1, backgroundColor: '#000' },
148
- camera: { flex: 1 },
149
- cameraFallback: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24 },
166
+ previewLayer: { ...StyleSheet.absoluteFillObject },
167
+ camera: { ...StyleSheet.absoluteFillObject },
168
+ cameraFallback: { ...StyleSheet.absoluteFillObject, justifyContent: 'center', alignItems: 'center', padding: 24 },
150
169
  cameraFallbackText: { fontSize: 16, color: '#fff', fontWeight: '600', marginBottom: 8 },
151
170
  cameraFallbackHint: { fontSize: 13, color: 'rgba(255,255,255,0.6)', textAlign: 'center' },
152
- footer: { padding: 16, backgroundColor: Colors.surface },
153
- hint: { fontSize: 13, color: Colors.textSecondary, marginBottom: 12 },
154
- error: { fontSize: 13, color: Colors.error, marginBottom: 12 },
171
+ topBar: {
172
+ position: 'absolute',
173
+ top: 44,
174
+ left: 16,
175
+ right: 16,
176
+ flexDirection: 'row',
177
+ alignItems: 'center',
178
+ justifyContent: 'space-between',
179
+ paddingLeft: 14,
180
+ paddingRight: 8,
181
+ paddingVertical: 8,
182
+ borderRadius: 12,
183
+ backgroundColor: 'rgba(0,0,0,0.62)',
184
+ },
185
+ titleGroup: { flex: 1, paddingRight: 10 },
186
+ title: { color: '#fff', fontSize: 15, fontWeight: '700' },
187
+ subtitle: { color: 'rgba(255,255,255,0.68)', fontSize: 11, marginTop: 2 },
155
188
  closeButton: {
156
189
  alignItems: 'center',
157
190
  justifyContent: 'center',
158
- paddingVertical: 11,
159
- borderRadius: 10,
160
- backgroundColor: Colors.primary,
191
+ paddingHorizontal: 12,
192
+ paddingVertical: 8,
193
+ borderRadius: 8,
194
+ backgroundColor: 'rgba(255,255,255,0.14)',
161
195
  },
162
196
  closeButtonText: { color: '#fff', fontSize: 14, fontWeight: '600' },
163
- topClose: {
197
+ statusPill: {
164
198
  position: 'absolute',
165
- top: 48,
199
+ left: 16,
166
200
  right: 16,
167
- paddingHorizontal: 12,
168
- paddingVertical: 8,
169
- borderRadius: 8,
170
- backgroundColor: 'rgba(0,0,0,0.55)',
201
+ bottom: 30,
202
+ paddingHorizontal: 14,
203
+ paddingVertical: 11,
204
+ borderRadius: 12,
205
+ backgroundColor: 'rgba(0,0,0,0.62)',
206
+ },
207
+ statusPillError: {
208
+ backgroundColor: `${Colors.error}22`,
209
+ borderWidth: 1,
210
+ borderColor: `${Colors.error}66`,
171
211
  },
172
- topCloseText: { color: '#fff', fontSize: 13, fontWeight: '600' },
212
+ statusText: { color: '#fff', fontSize: 13, textAlign: 'center', lineHeight: 18 },
213
+ statusTextError: { color: '#fff' },
173
214
  });