react-native-debug-toolkit 3.1.4 → 3.2.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/README.md +88 -65
- package/README.zh-CN.md +87 -64
- package/bin/debug-toolkit.js +10 -2
- package/lib/commonjs/core/initialize.js +5 -3
- package/lib/commonjs/core/initialize.js.map +1 -1
- package/lib/commonjs/features/devConnect/DevConnectQrScanner.js +146 -0
- package/lib/commonjs/features/devConnect/DevConnectQrScanner.js.map +1 -0
- package/lib/commonjs/features/devConnect/DevConnectTab.js +426 -0
- package/lib/commonjs/features/devConnect/DevConnectTab.js.map +1 -0
- package/lib/commonjs/features/devConnect/cameraKit.js +54 -0
- package/lib/commonjs/features/devConnect/cameraKit.js.map +1 -0
- package/lib/commonjs/features/devConnect/devConnectPreferences.js +35 -0
- package/lib/commonjs/features/devConnect/devConnectPreferences.js.map +1 -0
- package/lib/commonjs/features/devConnect/devConnectUtils.js +53 -0
- package/lib/commonjs/features/devConnect/devConnectUtils.js.map +1 -0
- package/lib/commonjs/features/devConnect/index.js +92 -0
- package/lib/commonjs/features/devConnect/index.js.map +1 -0
- package/lib/commonjs/features/devConnect/platformDetect.js +30 -0
- package/lib/commonjs/features/devConnect/platformDetect.js.map +1 -0
- package/lib/commonjs/features/devConnect/types.js +2 -0
- package/lib/commonjs/features/devConnect/types.js.map +1 -0
- package/lib/commonjs/features/network/NetworkLogTab.js +7 -3
- package/lib/commonjs/features/network/NetworkLogTab.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/DebugView.js +1 -0
- package/lib/commonjs/ui/DebugView.js.map +1 -1
- package/lib/commonjs/ui/panel/DebugPanel.js +0 -25
- package/lib/commonjs/ui/panel/DebugPanel.js.map +1 -1
- package/lib/commonjs/utils/DaemonClient.js +25 -1
- package/lib/commonjs/utils/DaemonClient.js.map +1 -1
- package/lib/commonjs/utils/debugPreferences.js +2 -1
- package/lib/commonjs/utils/debugPreferences.js.map +1 -1
- package/lib/commonjs/utils/deviceReport.js +1 -0
- package/lib/commonjs/utils/deviceReport.js.map +1 -1
- package/lib/module/core/initialize.js +5 -3
- package/lib/module/core/initialize.js.map +1 -1
- package/lib/module/features/devConnect/DevConnectQrScanner.js +141 -0
- package/lib/module/features/devConnect/DevConnectQrScanner.js.map +1 -0
- package/lib/module/features/devConnect/DevConnectTab.js +421 -0
- package/lib/module/features/devConnect/DevConnectTab.js.map +1 -0
- package/lib/module/features/devConnect/cameraKit.js +49 -0
- package/lib/module/features/devConnect/cameraKit.js.map +1 -0
- package/lib/module/features/devConnect/devConnectPreferences.js +29 -0
- package/lib/module/features/devConnect/devConnectPreferences.js.map +1 -0
- package/lib/module/features/devConnect/devConnectUtils.js +47 -0
- package/lib/module/features/devConnect/devConnectUtils.js.map +1 -0
- package/lib/module/features/devConnect/index.js +52 -0
- package/lib/module/features/devConnect/index.js.map +1 -0
- package/lib/module/features/devConnect/platformDetect.js +26 -0
- package/lib/module/features/devConnect/platformDetect.js.map +1 -0
- package/lib/module/features/devConnect/types.js +2 -0
- package/lib/module/features/devConnect/types.js.map +1 -0
- package/lib/module/features/network/NetworkLogTab.js +7 -3
- package/lib/module/features/network/NetworkLogTab.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/DebugView.js +1 -0
- package/lib/module/ui/DebugView.js.map +1 -1
- package/lib/module/ui/panel/DebugPanel.js +1 -26
- package/lib/module/ui/panel/DebugPanel.js.map +1 -1
- package/lib/module/utils/DaemonClient.js +25 -1
- package/lib/module/utils/DaemonClient.js.map +1 -1
- package/lib/module/utils/debugPreferences.js +2 -1
- package/lib/module/utils/debugPreferences.js.map +1 -1
- package/lib/module/utils/deviceReport.js +1 -0
- package/lib/module/utils/deviceReport.js.map +1 -1
- package/lib/typescript/src/core/initialize.d.ts +1 -0
- package/lib/typescript/src/core/initialize.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/DevConnectQrScanner.d.ts +9 -0
- package/lib/typescript/src/features/devConnect/DevConnectQrScanner.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts +5 -0
- package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/cameraKit.d.ts +47 -0
- package/lib/typescript/src/features/devConnect/cameraKit.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts +7 -0
- package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts +12 -0
- package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/index.d.ts +7 -0
- package/lib/typescript/src/features/devConnect/index.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/platformDetect.d.ts +2 -0
- package/lib/typescript/src/features/devConnect/platformDetect.d.ts.map +1 -0
- package/lib/typescript/src/features/devConnect/types.d.ts +7 -0
- package/lib/typescript/src/features/devConnect/types.d.ts.map +1 -0
- package/lib/typescript/src/features/network/NetworkLogTab.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types/feature.d.ts +1 -1
- package/lib/typescript/src/types/feature.d.ts.map +1 -1
- package/lib/typescript/src/ui/DebugView.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/DebugPanel.d.ts.map +1 -1
- package/lib/typescript/src/utils/DaemonClient.d.ts +1 -0
- package/lib/typescript/src/utils/DaemonClient.d.ts.map +1 -1
- package/lib/typescript/src/utils/debugPreferences.d.ts +1 -0
- package/lib/typescript/src/utils/debugPreferences.d.ts.map +1 -1
- package/lib/typescript/src/utils/deviceReport.d.ts +6 -0
- package/lib/typescript/src/utils/deviceReport.d.ts.map +1 -1
- package/node/daemon/src/console/console.html +166 -27
- package/node/daemon/src/store.js +45 -6
- package/package.json +15 -3
- package/src/core/initialize.ts +7 -1
- package/src/features/devConnect/DevConnectQrScanner.tsx +122 -0
- package/src/features/devConnect/DevConnectTab.tsx +357 -0
- package/src/features/devConnect/cameraKit.ts +93 -0
- package/src/features/devConnect/devConnectPreferences.ts +33 -0
- package/src/features/devConnect/devConnectUtils.ts +59 -0
- package/src/features/devConnect/index.ts +64 -0
- package/src/features/devConnect/platformDetect.ts +26 -0
- package/src/features/devConnect/types.ts +6 -0
- package/src/features/network/NetworkLogTab.tsx +6 -3
- package/src/index.ts +2 -0
- package/src/types/feature.ts +2 -1
- package/src/ui/DebugView.tsx +1 -0
- package/src/ui/panel/DebugPanel.tsx +1 -23
- package/src/utils/DaemonClient.ts +26 -1
- package/src/utils/debugPreferences.ts +1 -0
- package/src/utils/deviceReport.ts +8 -1
- package/lib/commonjs/ui/panel/StreamingSettingsModal.js +0 -495
- package/lib/commonjs/ui/panel/StreamingSettingsModal.js.map +0 -1
- package/lib/module/ui/panel/StreamingSettingsModal.js +0 -490
- package/lib/module/ui/panel/StreamingSettingsModal.js.map +0 -1
- package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts +0 -8
- package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts.map +0 -1
- package/src/ui/panel/StreamingSettingsModal.tsx +0 -528
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
// ---- react-native-camera-kit types ----
|
|
5
|
+
|
|
6
|
+
export interface CameraKitReadCodeEvent {
|
|
7
|
+
nativeEvent?: {
|
|
8
|
+
codeStringValue?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CameraKitCameraProps {
|
|
13
|
+
style?: StyleProp<ViewStyle>;
|
|
14
|
+
cameraType?: unknown;
|
|
15
|
+
scanBarcode?: boolean;
|
|
16
|
+
onReadCode?: (event: CameraKitReadCodeEvent) => void;
|
|
17
|
+
showFrame?: boolean;
|
|
18
|
+
laserColor?: string;
|
|
19
|
+
frameColor?: string;
|
|
20
|
+
allowedBarcodeTypes?: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CameraKitModule {
|
|
24
|
+
Camera: ComponentType<CameraKitCameraProps>;
|
|
25
|
+
CameraType?: { Back?: unknown };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ---- expo-camera types ----
|
|
29
|
+
|
|
30
|
+
export interface ExpoCameraScanResult {
|
|
31
|
+
boundingBox?: unknown;
|
|
32
|
+
cornerPoints?: unknown;
|
|
33
|
+
type?: string;
|
|
34
|
+
value?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ExpoCameraModule {
|
|
38
|
+
Camera: ComponentType<{
|
|
39
|
+
style?: StyleProp<ViewStyle>;
|
|
40
|
+
onBarCodeScanned?: (result: ExpoCameraScanResult) => void;
|
|
41
|
+
barCodeScannerSettings?: { barCodeTypes: string[] };
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---- Unified scanner ----
|
|
46
|
+
|
|
47
|
+
export type ScannerKind = 'camera-kit' | 'expo-camera';
|
|
48
|
+
|
|
49
|
+
export interface ScannerModule {
|
|
50
|
+
kind: ScannerKind;
|
|
51
|
+
CameraKit?: CameraKitModule;
|
|
52
|
+
ExpoCamera?: ExpoCameraModule;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let cached: ScannerModule | null | false = false;
|
|
56
|
+
|
|
57
|
+
function tryCameraKit(): ScannerModule | null {
|
|
58
|
+
try {
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
60
|
+
const mod = require('react-native-camera-kit') as Partial<CameraKitModule>;
|
|
61
|
+
if (mod.Camera) {
|
|
62
|
+
return {
|
|
63
|
+
kind: 'camera-kit',
|
|
64
|
+
CameraKit: { Camera: mod.Camera, CameraType: mod.CameraType },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
} catch { /* not installed */ }
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function tryExpoCamera(): ScannerModule | null {
|
|
72
|
+
try {
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
74
|
+
const mod = require('expo-camera') as Partial<ExpoCameraModule>;
|
|
75
|
+
if (mod.Camera) {
|
|
76
|
+
return {
|
|
77
|
+
kind: 'expo-camera',
|
|
78
|
+
ExpoCamera: { Camera: mod.Camera },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
} catch { /* not installed */ }
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getScannerModule(): ScannerModule | null {
|
|
86
|
+
if (cached !== false) return cached;
|
|
87
|
+
cached = tryCameraKit() ?? tryExpoCamera();
|
|
88
|
+
return cached;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function isCameraKitAvailable(): boolean {
|
|
92
|
+
return getScannerModule() !== null;
|
|
93
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { daemonClient } from '../../utils/DaemonClient';
|
|
2
|
+
import { getPreference, KEYS, setPreference } from '../../utils/debugPreferences';
|
|
3
|
+
import { normalizeComputerHost } from './devConnectUtils';
|
|
4
|
+
import { isSimulator } from './platformDetect';
|
|
5
|
+
|
|
6
|
+
export interface DevConnectPreferences {
|
|
7
|
+
computerHost: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function loadDevConnectPreferences(): Promise<DevConnectPreferences> {
|
|
11
|
+
const storedHost = await getPreference(KEYS.computerHost);
|
|
12
|
+
return {
|
|
13
|
+
computerHost: storedHost ? normalizeComputerHost(storedHost) ?? '' : '',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function saveComputerHost(value: string): Promise<string | null> {
|
|
18
|
+
const normalized = normalizeComputerHost(value);
|
|
19
|
+
if (!normalized) return null;
|
|
20
|
+
await setPreference(KEYS.computerHost, normalized);
|
|
21
|
+
return normalized;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function restoreDevConnectSettingsToDaemon(): Promise<void> {
|
|
25
|
+
const preferences = await loadDevConnectPreferences();
|
|
26
|
+
const mode = isSimulator() ? 'simulator' as const : 'device' as const;
|
|
27
|
+
daemonClient.configure({
|
|
28
|
+
mode,
|
|
29
|
+
endpoint: '',
|
|
30
|
+
deviceHost: mode === 'simulator' ? '' : preferences.computerHost,
|
|
31
|
+
token: '',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const METRO_PORT = '8081';
|
|
2
|
+
|
|
3
|
+
export interface MetroUrls {
|
|
4
|
+
expUrl: string;
|
|
5
|
+
httpUrl: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ParsedMetroQrPayload {
|
|
9
|
+
computerHost: string;
|
|
10
|
+
source: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isValidIpv4(host: string): boolean {
|
|
14
|
+
const parts = host.split('.');
|
|
15
|
+
if (parts.length !== 4) return false;
|
|
16
|
+
|
|
17
|
+
return parts.every((part) => {
|
|
18
|
+
if (!/^\d{1,3}$/.test(part)) return false;
|
|
19
|
+
const value = Number(part);
|
|
20
|
+
return value >= 0 && value <= 255 && String(value) === part;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function toUrlInput(raw: string): string {
|
|
25
|
+
const trimmed = raw.trim();
|
|
26
|
+
if (/^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(trimmed)) {
|
|
27
|
+
return trimmed;
|
|
28
|
+
}
|
|
29
|
+
return `http://${trimmed}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function normalizeComputerHost(raw: string): string | null {
|
|
33
|
+
const trimmed = raw.trim();
|
|
34
|
+
if (!trimmed) return null;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const parsed = new URL(toUrlInput(trimmed));
|
|
38
|
+
const host = parsed.hostname.trim();
|
|
39
|
+
return isValidIpv4(host) ? host : null;
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function buildMetroUrls(rawHost: string): MetroUrls | null {
|
|
46
|
+
const host = normalizeComputerHost(rawHost);
|
|
47
|
+
if (!host) return null;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
expUrl: `exp://${host}:${METRO_PORT}`,
|
|
51
|
+
httpUrl: `http://${host}:${METRO_PORT}`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function parseMetroQrPayload(payload: string): ParsedMetroQrPayload | null {
|
|
56
|
+
const computerHost = normalizeComputerHost(payload);
|
|
57
|
+
if (!computerHost) return null;
|
|
58
|
+
return { computerHost, source: payload };
|
|
59
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { DevConnectTab } from './DevConnectTab';
|
|
2
|
+
import { isCameraKitAvailable } from './cameraKit';
|
|
3
|
+
import { loadDevConnectPreferences } from './devConnectPreferences';
|
|
4
|
+
import { isSimulator } from './platformDetect';
|
|
5
|
+
import { daemonClient } from '../../utils/DaemonClient';
|
|
6
|
+
import type { DebugFeature, DebugFeatureListener } from '../../types';
|
|
7
|
+
import type { DevConnectState } from './types';
|
|
8
|
+
|
|
9
|
+
export type { DevConnectState } from './types';
|
|
10
|
+
export {
|
|
11
|
+
buildMetroUrls,
|
|
12
|
+
normalizeComputerHost,
|
|
13
|
+
parseMetroQrPayload,
|
|
14
|
+
} from './devConnectUtils';
|
|
15
|
+
export {
|
|
16
|
+
loadDevConnectPreferences,
|
|
17
|
+
restoreDevConnectSettingsToDaemon,
|
|
18
|
+
saveComputerHost,
|
|
19
|
+
} from './devConnectPreferences';
|
|
20
|
+
|
|
21
|
+
export const createDevConnectFeature = (): DebugFeature<DevConnectState> => {
|
|
22
|
+
const listeners = new Set<DebugFeatureListener>();
|
|
23
|
+
let state: DevConnectState = {
|
|
24
|
+
isSimulator: isSimulator(),
|
|
25
|
+
computerHost: '',
|
|
26
|
+
qrAvailable: isCameraKitAvailable(),
|
|
27
|
+
streaming: daemonClient.isConnected(),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const notify = () => {
|
|
31
|
+
state = {
|
|
32
|
+
...state,
|
|
33
|
+
streaming: daemonClient.isConnected(),
|
|
34
|
+
};
|
|
35
|
+
listeners.forEach((listener) => listener());
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: 'devConnect',
|
|
40
|
+
label: 'DevConnect',
|
|
41
|
+
renderContent: DevConnectTab,
|
|
42
|
+
setup() {
|
|
43
|
+
loadDevConnectPreferences().then((preferences) => {
|
|
44
|
+
state = {
|
|
45
|
+
...state,
|
|
46
|
+
computerHost: preferences.computerHost,
|
|
47
|
+
};
|
|
48
|
+
notify();
|
|
49
|
+
}).catch(() => {
|
|
50
|
+
notify();
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
getSnapshot: () => state,
|
|
54
|
+
cleanup() {
|
|
55
|
+
listeners.clear();
|
|
56
|
+
},
|
|
57
|
+
subscribe(listener) {
|
|
58
|
+
listeners.add(listener);
|
|
59
|
+
return () => {
|
|
60
|
+
listeners.delete(listener);
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export function isSimulator(): boolean {
|
|
4
|
+
const { OS } = Platform;
|
|
5
|
+
|
|
6
|
+
if (OS === 'android') {
|
|
7
|
+
const constants = Platform.constants as Record<string, unknown>;
|
|
8
|
+
if (constants.isEmulator === true) return true;
|
|
9
|
+
const model = String(constants.Model ?? '').toLowerCase();
|
|
10
|
+
return model.includes('sdk') || model.includes('emulator') || model.includes('google_sdk');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (OS === 'ios') {
|
|
14
|
+
// NativeModules.KCKFCSupportManager is absent on simulator,
|
|
15
|
+
// but the most reliable check is the DeviceInfo model name.
|
|
16
|
+
const deviceInfo = NativeModules.DeviceInfo
|
|
17
|
+
?? NativeModules.PlatformConstants;
|
|
18
|
+
if (deviceInfo) {
|
|
19
|
+
const model = String(deviceInfo.model ?? '').toLowerCase();
|
|
20
|
+
if (model.includes('simulator')) return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
@@ -26,13 +26,16 @@ const formatSize = (data: unknown): string => {
|
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
// Keep in sync with console.html buildCurlCommand()
|
|
29
30
|
const buildCurl = (log: NetworkLogEntry): string => {
|
|
30
|
-
|
|
31
|
+
const q = (s: string) => s.replace(/'/g, "'\\''");
|
|
32
|
+
let c = `curl -X ${log.request.method} '${q(log.request.url)}'`;
|
|
31
33
|
if (log.request.headers) {
|
|
32
|
-
Object.entries(log.request.headers).forEach(([k, v]) => (c += ` \\\n -H '${k}: ${v}'`));
|
|
34
|
+
Object.entries(log.request.headers).forEach(([k, v]) => (c += ` \\\n -H '${q(k)}: ${q(String(v))}'`));
|
|
33
35
|
}
|
|
34
36
|
if (log.request.body) {
|
|
35
|
-
|
|
37
|
+
const bodyStr = typeof log.request.body === 'string' ? log.request.body : JSON.stringify(log.request.body);
|
|
38
|
+
c += ` \\\n -d '${q(bodyStr)}'`;
|
|
36
39
|
}
|
|
37
40
|
return c;
|
|
38
41
|
};
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,8 @@ export type { TrackFeatureConfig, TrackEventData } from './features/track';
|
|
|
20
20
|
export { createEnvironmentFeature } from './features/environment';
|
|
21
21
|
export type { EnvironmentFeatureAPI } from './features/environment';
|
|
22
22
|
export { createClipboardFeature } from './features/clipboard';
|
|
23
|
+
export { createDevConnectFeature } from './features/devConnect';
|
|
24
|
+
export type { DevConnectState } from './features/devConnect';
|
|
23
25
|
|
|
24
26
|
// Hooks
|
|
25
27
|
export { useNavigationLogger } from './features/navigation/useNavigationLogger';
|
package/src/types/feature.ts
CHANGED
package/src/ui/DebugView.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef
|
|
1
|
+
import React, { useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
useWindowDimensions,
|
|
11
11
|
} from 'react-native';
|
|
12
12
|
import { Colors } from '../theme/colors';
|
|
13
|
-
import { StreamingSettingsModal } from './StreamingSettingsModal';
|
|
14
13
|
|
|
15
14
|
interface DebugPanelProps {
|
|
16
15
|
onClose: () => void;
|
|
@@ -22,7 +21,6 @@ export function DebugPanel({ onClose, onClearAll, children }: DebugPanelProps) {
|
|
|
22
21
|
const { height: screenHeight } = useWindowDimensions();
|
|
23
22
|
const panelTranslateY = useRef(new Animated.Value(screenHeight)).current;
|
|
24
23
|
const backdropOpacity = useRef(new Animated.Value(0)).current;
|
|
25
|
-
const [settingsVisible, setSettingsVisible] = useState(false);
|
|
26
24
|
|
|
27
25
|
useEffect(() => {
|
|
28
26
|
requestAnimationFrame(() => {
|
|
@@ -103,13 +101,6 @@ export function DebugPanel({ onClose, onClearAll, children }: DebugPanelProps) {
|
|
|
103
101
|
<View style={styles.header}>
|
|
104
102
|
<Text style={styles.headerTitle}>Debug Toolkit</Text>
|
|
105
103
|
<View style={styles.headerButtons}>
|
|
106
|
-
<TouchableOpacity
|
|
107
|
-
onPress={() => setSettingsVisible(true)}
|
|
108
|
-
style={styles.settingsButton}
|
|
109
|
-
activeOpacity={0.6}
|
|
110
|
-
>
|
|
111
|
-
<Text style={styles.settingsButtonText}>⚙</Text>
|
|
112
|
-
</TouchableOpacity>
|
|
113
104
|
<TouchableOpacity
|
|
114
105
|
onPress={() => {
|
|
115
106
|
onClearAll();
|
|
@@ -128,7 +119,6 @@ export function DebugPanel({ onClose, onClearAll, children }: DebugPanelProps) {
|
|
|
128
119
|
</View>
|
|
129
120
|
<View style={styles.panelContent}>{children}</View>
|
|
130
121
|
</Animated.View>
|
|
131
|
-
<StreamingSettingsModal visible={settingsVisible} onClose={() => setSettingsVisible(false)} />
|
|
132
122
|
</View>
|
|
133
123
|
);
|
|
134
124
|
}
|
|
@@ -208,18 +198,6 @@ const styles = StyleSheet.create({
|
|
|
208
198
|
fontSize: 14,
|
|
209
199
|
fontWeight: '500',
|
|
210
200
|
},
|
|
211
|
-
settingsButton: {
|
|
212
|
-
width: 32,
|
|
213
|
-
height: 32,
|
|
214
|
-
borderRadius: 16,
|
|
215
|
-
backgroundColor: Colors.background,
|
|
216
|
-
alignItems: 'center',
|
|
217
|
-
justifyContent: 'center',
|
|
218
|
-
},
|
|
219
|
-
settingsButtonText: {
|
|
220
|
-
fontSize: 16,
|
|
221
|
-
color: Colors.textSecondary,
|
|
222
|
-
},
|
|
223
201
|
closeButton: {
|
|
224
202
|
width: 30,
|
|
225
203
|
height: 30,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
createDebugDeviceReport,
|
|
7
7
|
type DebugDeviceReport,
|
|
8
8
|
type DebugDeviceReportOptions,
|
|
9
|
+
type SessionInfo,
|
|
9
10
|
} from './deviceReport';
|
|
10
11
|
import { safeStringify } from './safeStringify';
|
|
11
12
|
|
|
@@ -147,6 +148,7 @@ interface StreamState {
|
|
|
147
148
|
debounceMs: number;
|
|
148
149
|
timeoutMs: number;
|
|
149
150
|
deviceId: string | null;
|
|
151
|
+
session: SessionInfo;
|
|
150
152
|
sending: boolean;
|
|
151
153
|
debounceTimer: ReturnType<typeof setTimeout> | null;
|
|
152
154
|
retryTimer: ReturnType<typeof setTimeout> | null;
|
|
@@ -183,6 +185,7 @@ export class DaemonClient {
|
|
|
183
185
|
private _featureProvider: FeatureDataProvider;
|
|
184
186
|
private _onEndpointDetected: ((url: string) => void) | undefined;
|
|
185
187
|
private _restorePromise: Promise<void> | null = null;
|
|
188
|
+
private _sessionId: SessionInfo | null = null;
|
|
186
189
|
|
|
187
190
|
constructor(options: DaemonClientOptions) {
|
|
188
191
|
this._fetch = options.fetch;
|
|
@@ -264,6 +267,10 @@ export class DaemonClient {
|
|
|
264
267
|
connect(options: StreamToDaemonOptions = {}): void {
|
|
265
268
|
if (this._stream) return;
|
|
266
269
|
|
|
270
|
+
if (!this._sessionId) {
|
|
271
|
+
this._sessionId = { id: generateSessionId(), startedAt: Date.now() };
|
|
272
|
+
}
|
|
273
|
+
|
|
267
274
|
const endpoint = options.endpoint || this.resolveEndpoint();
|
|
268
275
|
const reportUrl = buildDaemonUrl(endpoint, '/report');
|
|
269
276
|
const ingestUrl = buildDaemonUrl(endpoint, '/ingest');
|
|
@@ -280,6 +287,7 @@ export class DaemonClient {
|
|
|
280
287
|
debounceMs: options.debounceMs || DEFAULT_DEBOUNCE_MS,
|
|
281
288
|
timeoutMs: Math.max(0, options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
282
289
|
deviceId: null,
|
|
290
|
+
session: this._sessionId,
|
|
283
291
|
sending: false,
|
|
284
292
|
debounceTimer: null,
|
|
285
293
|
retryTimer: null,
|
|
@@ -315,6 +323,7 @@ export class DaemonClient {
|
|
|
315
323
|
if (!this._stream) return;
|
|
316
324
|
const state = this._stream;
|
|
317
325
|
this._stream = null;
|
|
326
|
+
this._sessionId = null;
|
|
318
327
|
|
|
319
328
|
if (state.debounceTimer) clearTimeout(state.debounceTimer);
|
|
320
329
|
if (state.retryTimer) clearTimeout(state.retryTimer);
|
|
@@ -458,6 +467,7 @@ export class DaemonClient {
|
|
|
458
467
|
this._settings = { mode: 'simulator', endpoint: '', deviceHost: '', token: '' };
|
|
459
468
|
this._streamingEnabled = null;
|
|
460
469
|
this._restorePromise = null;
|
|
470
|
+
this._sessionId = null;
|
|
461
471
|
}
|
|
462
472
|
|
|
463
473
|
// ---- Private: Transport ----
|
|
@@ -629,7 +639,7 @@ export class DaemonClient {
|
|
|
629
639
|
}
|
|
630
640
|
|
|
631
641
|
private async doSendFullReport(state: StreamState): Promise<SendResult> {
|
|
632
|
-
const report = createDebugDeviceReport({ featureProvider: this._featureProvider });
|
|
642
|
+
const report = createDebugDeviceReport({ featureProvider: this._featureProvider, session: state.session });
|
|
633
643
|
const response = await this.doPost(
|
|
634
644
|
state.reportUrl,
|
|
635
645
|
this.fetchHeaders(state),
|
|
@@ -843,3 +853,18 @@ function readLogCount(value: unknown): Record<string, number> | undefined {
|
|
|
843
853
|
export function _resetDaemonClientForTesting(): void {
|
|
844
854
|
daemonClient._resetForTesting();
|
|
845
855
|
}
|
|
856
|
+
|
|
857
|
+
function generateSessionId(): string {
|
|
858
|
+
try {
|
|
859
|
+
return (globalThis as { crypto?: { randomUUID?: () => string } }).crypto?.randomUUID?.() ?? fallbackSessionId();
|
|
860
|
+
} catch {
|
|
861
|
+
return fallbackSessionId();
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function fallbackSessionId(): string {
|
|
866
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
867
|
+
const r = Math.random() * 16 | 0;
|
|
868
|
+
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
|
869
|
+
});
|
|
870
|
+
}
|
|
@@ -45,4 +45,5 @@ export const KEYS = {
|
|
|
45
45
|
consoleLogs: '@react_native_debug_toolkit/console_logs',
|
|
46
46
|
networkLogs: '@react_native_debug_toolkit/network_logs',
|
|
47
47
|
trackLogs: '@react_native_debug_toolkit/track_logs',
|
|
48
|
+
computerHost: '@react_native_debug_toolkit/computer_host',
|
|
48
49
|
} as const;
|
|
@@ -21,9 +21,15 @@ export interface DeviceInfo {
|
|
|
21
21
|
appVersion: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface SessionInfo {
|
|
25
|
+
id: string;
|
|
26
|
+
startedAt: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
export interface DebugDeviceReport {
|
|
25
30
|
version: 2;
|
|
26
31
|
device: DeviceInfo;
|
|
32
|
+
session?: SessionInfo;
|
|
27
33
|
logs: Record<string, unknown[] | undefined>;
|
|
28
34
|
}
|
|
29
35
|
|
|
@@ -161,7 +167,7 @@ function sanitizeValue(
|
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
export function createDebugDeviceReport(
|
|
164
|
-
options: DebugDeviceReportOptions & { featureProvider?: FeatureDataProvider } = {},
|
|
170
|
+
options: DebugDeviceReportOptions & { featureProvider?: FeatureDataProvider; session?: SessionInfo } = {},
|
|
165
171
|
): DebugDeviceReport {
|
|
166
172
|
const provider = options.featureProvider ?? debugToolkit;
|
|
167
173
|
const maxPerType = Math.max(1, Math.floor(options.maxPerType ?? DEFAULT_MAX_PER_TYPE));
|
|
@@ -200,6 +206,7 @@ export function createDebugDeviceReport(
|
|
|
200
206
|
osVersion: Platform.Version == null ? 'unknown' : String(Platform.Version),
|
|
201
207
|
appVersion: (constants?.appVersion as string) || 'unknown',
|
|
202
208
|
},
|
|
209
|
+
session: options.session,
|
|
203
210
|
logs,
|
|
204
211
|
};
|
|
205
212
|
}
|