react-native-debug-toolkit 2.3.0 → 3.1.2
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 +115 -97
- package/README.zh-CN.md +113 -95
- package/bin/debug-toolkit.js +114 -0
- package/lib/commonjs/core/initialize.js +5 -0
- package/lib/commonjs/core/initialize.js.map +1 -1
- package/lib/commonjs/features/network/index.js +28 -2
- package/lib/commonjs/features/network/index.js.map +1 -1
- package/lib/commonjs/features/network/networkInterceptor.js +14 -6
- package/lib/commonjs/features/network/networkInterceptor.js.map +1 -1
- package/lib/commonjs/index.js +56 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/panel/DebugPanel.js +25 -0
- package/lib/commonjs/ui/panel/DebugPanel.js.map +1 -1
- package/lib/commonjs/ui/panel/FloatPanelView.js +15 -62
- package/lib/commonjs/ui/panel/FloatPanelView.js.map +1 -1
- package/lib/commonjs/ui/panel/StreamingSettingsModal.js +495 -0
- package/lib/commonjs/ui/panel/StreamingSettingsModal.js.map +1 -0
- package/lib/commonjs/ui/panel/useTabAnimation.js +71 -0
- package/lib/commonjs/ui/panel/useTabAnimation.js.map +1 -0
- package/lib/commonjs/utils/DaemonClient.js +721 -0
- package/lib/commonjs/utils/DaemonClient.js.map +1 -0
- package/lib/commonjs/utils/createPersistedObservableStore.js +23 -3
- package/lib/commonjs/utils/createPersistedObservableStore.js.map +1 -1
- package/lib/commonjs/utils/deviceReport.js +132 -0
- package/lib/commonjs/utils/deviceReport.js.map +1 -0
- package/lib/module/core/initialize.js +6 -0
- package/lib/module/core/initialize.js.map +1 -1
- package/lib/module/features/network/index.js +25 -1
- package/lib/module/features/network/index.js.map +1 -1
- package/lib/module/features/network/networkInterceptor.js +14 -6
- package/lib/module/features/network/networkInterceptor.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/panel/DebugPanel.js +26 -1
- package/lib/module/ui/panel/DebugPanel.js.map +1 -1
- package/lib/module/ui/panel/FloatPanelView.js +16 -63
- package/lib/module/ui/panel/FloatPanelView.js.map +1 -1
- package/lib/module/ui/panel/StreamingSettingsModal.js +490 -0
- package/lib/module/ui/panel/StreamingSettingsModal.js.map +1 -0
- package/lib/module/ui/panel/useTabAnimation.js +67 -0
- package/lib/module/ui/panel/useTabAnimation.js.map +1 -0
- package/lib/module/utils/DaemonClient.js +703 -0
- package/lib/module/utils/DaemonClient.js.map +1 -0
- package/lib/module/utils/createPersistedObservableStore.js +23 -3
- package/lib/module/utils/createPersistedObservableStore.js.map +1 -1
- package/lib/module/utils/deviceReport.js +128 -0
- package/lib/module/utils/deviceReport.js.map +1 -0
- package/lib/typescript/src/core/initialize.d.ts.map +1 -1
- package/lib/typescript/src/features/network/index.d.ts +2 -0
- package/lib/typescript/src/features/network/index.d.ts.map +1 -1
- package/lib/typescript/src/features/network/networkInterceptor.d.ts +1 -1
- package/lib/typescript/src/features/network/networkInterceptor.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/DebugPanel.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/FloatPanelView.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts +8 -0
- package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts.map +1 -0
- package/lib/typescript/src/ui/panel/useTabAnimation.d.ts +14 -0
- package/lib/typescript/src/ui/panel/useTabAnimation.d.ts.map +1 -0
- package/lib/typescript/src/utils/DaemonClient.d.ts +141 -0
- package/lib/typescript/src/utils/DaemonClient.d.ts.map +1 -0
- package/lib/typescript/src/utils/createPersistedObservableStore.d.ts +2 -1
- package/lib/typescript/src/utils/createPersistedObservableStore.d.ts.map +1 -1
- package/lib/typescript/src/utils/deviceReport.d.ts +18 -0
- package/lib/typescript/src/utils/deviceReport.d.ts.map +1 -0
- package/node/daemon/src/cli.js +82 -0
- package/node/daemon/src/console/console.html +1662 -0
- package/node/daemon/src/console/index.js +47 -0
- package/node/daemon/src/constants.js +38 -0
- package/node/daemon/src/index.js +11 -0
- package/node/daemon/src/server.js +447 -0
- package/node/daemon/src/store.js +187 -0
- package/node/mcp/src/cli.js +31 -0
- package/node/mcp/src/constants.js +13 -0
- package/node/mcp/src/daemonClient.js +132 -0
- package/node/mcp/src/httpClient.js +49 -0
- package/node/mcp/src/index.js +15 -0
- package/node/mcp/src/logs.js +96 -0
- package/node/mcp/src/server.js +144 -0
- package/node/mcp/src/tools.js +84 -0
- package/package.json +8 -3
- package/src/core/initialize.ts +8 -0
- package/src/features/network/index.ts +30 -3
- package/src/features/network/networkInterceptor.ts +19 -6
- package/src/index.ts +22 -0
- package/src/ui/panel/DebugPanel.tsx +23 -1
- package/src/ui/panel/FloatPanelView.tsx +10 -68
- package/src/ui/panel/StreamingSettingsModal.tsx +528 -0
- package/src/ui/panel/useTabAnimation.ts +77 -0
- package/src/utils/DaemonClient.ts +887 -0
- package/src/utils/createPersistedObservableStore.ts +16 -3
- package/src/utils/deviceReport.ts +203 -0
|
@@ -9,8 +9,9 @@ export interface PersistedStoreOptions<T> {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface PersistedObservableStore<T> extends ObservableStore<T> {
|
|
12
|
-
/** Returns the next auto-incrementing ID and advances the counter. */
|
|
13
12
|
nextId: () => string;
|
|
13
|
+
ready: Promise<void>;
|
|
14
|
+
destroy: () => void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export function createPersistedObservableStore<T extends { id?: string }>(
|
|
@@ -20,13 +21,15 @@ export function createPersistedObservableStore<T extends { id?: string }>(
|
|
|
20
21
|
const store = createObservableStore<T>();
|
|
21
22
|
let writeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
22
23
|
let idCounter = 0;
|
|
24
|
+
let resolveReady: () => void;
|
|
25
|
+
const ready = new Promise<void>((resolve) => { resolveReady = resolve; });
|
|
23
26
|
|
|
24
27
|
// Restore from storage (single notify via pushBatch)
|
|
25
28
|
getPreference(storageKey).then((raw) => {
|
|
26
|
-
if (!raw) return;
|
|
29
|
+
if (!raw) { resolveReady(); return; }
|
|
27
30
|
try {
|
|
28
31
|
const entries = JSON.parse(raw) as T[];
|
|
29
|
-
if (!Array.isArray(entries)) return;
|
|
32
|
+
if (!Array.isArray(entries)) { resolveReady(); return; }
|
|
30
33
|
const restored = entries.slice(-maxPersist);
|
|
31
34
|
store.pushBatch(restored);
|
|
32
35
|
// Fix ID counter to avoid collision with restored entries
|
|
@@ -39,6 +42,7 @@ export function createPersistedObservableStore<T extends { id?: string }>(
|
|
|
39
42
|
} catch {
|
|
40
43
|
// ignore corrupt data
|
|
41
44
|
}
|
|
45
|
+
resolveReady();
|
|
42
46
|
});
|
|
43
47
|
|
|
44
48
|
function scheduleWrite(): void {
|
|
@@ -72,5 +76,14 @@ export function createPersistedObservableStore<T extends { id?: string }>(
|
|
|
72
76
|
},
|
|
73
77
|
subscribe: store.subscribe,
|
|
74
78
|
nextId: () => String(idCounter++),
|
|
79
|
+
ready,
|
|
80
|
+
destroy: () => {
|
|
81
|
+
if (writeTimer !== null) {
|
|
82
|
+
clearTimeout(writeTimer);
|
|
83
|
+
writeTimer = null;
|
|
84
|
+
}
|
|
85
|
+
store.clear();
|
|
86
|
+
setPreference(storageKey, '[]');
|
|
87
|
+
},
|
|
75
88
|
};
|
|
76
89
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { DebugToolkit } from '../core/DebugToolkit';
|
|
4
|
+
import { safeStringify } from './safeStringify';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_MAX_PER_TYPE = 50;
|
|
7
|
+
const DEFAULT_MAX_BODY_BYTES = 16 * 1024;
|
|
8
|
+
const MAX_DEPTH = 8;
|
|
9
|
+
|
|
10
|
+
export interface DebugDeviceReportOptions {
|
|
11
|
+
maxPerType?: number;
|
|
12
|
+
maxBodyBytes?: number;
|
|
13
|
+
includeTypes?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DeviceInfo {
|
|
17
|
+
platform: string;
|
|
18
|
+
model: string;
|
|
19
|
+
osVersion: string;
|
|
20
|
+
appVersion: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DebugDeviceReport {
|
|
24
|
+
version: 2;
|
|
25
|
+
device: DeviceInfo;
|
|
26
|
+
logs: Record<string, unknown[] | undefined>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface TruncatedValue {
|
|
30
|
+
__debugToolkitTruncated: true;
|
|
31
|
+
originalBytes: number;
|
|
32
|
+
preview: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function utf8ByteLength(value: string): number {
|
|
36
|
+
let bytes = 0;
|
|
37
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
38
|
+
const code = value.charCodeAt(index);
|
|
39
|
+
if (code <= 0x7f) {
|
|
40
|
+
bytes += 1;
|
|
41
|
+
} else if (code <= 0x7ff) {
|
|
42
|
+
bytes += 2;
|
|
43
|
+
} else if (code >= 0xd800 && code <= 0xdbff) {
|
|
44
|
+
bytes += 4;
|
|
45
|
+
index += 1;
|
|
46
|
+
} else {
|
|
47
|
+
bytes += 3;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return bytes;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function truncateUtf8(value: string, maxBytes: number): string {
|
|
54
|
+
if (utf8ByteLength(value) <= maxBytes) {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let bytes = 0;
|
|
59
|
+
let result = '';
|
|
60
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
61
|
+
const code = value.charCodeAt(index);
|
|
62
|
+
const char = value[index]!;
|
|
63
|
+
const charBytes = code <= 0x7f
|
|
64
|
+
? 1
|
|
65
|
+
: code <= 0x7ff
|
|
66
|
+
? 2
|
|
67
|
+
: code >= 0xd800 && code <= 0xdbff
|
|
68
|
+
? 4
|
|
69
|
+
: 3;
|
|
70
|
+
|
|
71
|
+
if (bytes + charBytes > maxBytes) {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
result += char;
|
|
76
|
+
bytes += charBytes;
|
|
77
|
+
|
|
78
|
+
if (charBytes === 4) {
|
|
79
|
+
index += 1;
|
|
80
|
+
result += value[index] ?? '';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return `${result}...[truncated]`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function truncateLargeValue(value: unknown, maxBytes: number): unknown | TruncatedValue {
|
|
88
|
+
const serialized = safeStringify(value);
|
|
89
|
+
const originalBytes = utf8ByteLength(serialized);
|
|
90
|
+
if (originalBytes <= maxBytes) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
__debugToolkitTruncated: true,
|
|
96
|
+
originalBytes,
|
|
97
|
+
preview: truncateUtf8(serialized, maxBytes),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function sanitizeValue(
|
|
102
|
+
value: unknown,
|
|
103
|
+
maxBodyBytes: number,
|
|
104
|
+
depth = 0,
|
|
105
|
+
seen = new WeakSet<object>(),
|
|
106
|
+
key = '',
|
|
107
|
+
): unknown {
|
|
108
|
+
if (typeof value === 'string') {
|
|
109
|
+
return truncateUtf8(value, maxBodyBytes);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (
|
|
113
|
+
value === null ||
|
|
114
|
+
typeof value === 'number' ||
|
|
115
|
+
typeof value === 'boolean' ||
|
|
116
|
+
typeof value === 'undefined'
|
|
117
|
+
) {
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof value === 'function' || typeof value === 'symbol' || typeof value === 'bigint') {
|
|
122
|
+
return String(value);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (value instanceof Date) {
|
|
126
|
+
return value.toISOString();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (typeof value !== 'object') {
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const normalizedKey = key.toLowerCase();
|
|
134
|
+
if (normalizedKey === 'body' || normalizedKey === 'data') {
|
|
135
|
+
const normalized = sanitizeValue(value, maxBodyBytes, depth + 1, seen);
|
|
136
|
+
return truncateLargeValue(normalized, maxBodyBytes);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (seen.has(value)) {
|
|
140
|
+
return '[Circular]';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (depth >= MAX_DEPTH) {
|
|
144
|
+
return '[MaxDepth]';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
seen.add(value);
|
|
148
|
+
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
return value.map((item) => sanitizeValue(item, maxBodyBytes, depth + 1, seen));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return Object.entries(value as Record<string, unknown>).reduce<Record<string, unknown>>(
|
|
154
|
+
(acc, [entryKey, entryValue]) => {
|
|
155
|
+
acc[entryKey] = sanitizeValue(entryValue, maxBodyBytes, depth + 1, seen, entryKey);
|
|
156
|
+
return acc;
|
|
157
|
+
},
|
|
158
|
+
{},
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function createDebugDeviceReport(
|
|
163
|
+
options: DebugDeviceReportOptions = {},
|
|
164
|
+
): DebugDeviceReport {
|
|
165
|
+
const maxPerType = Math.max(1, Math.floor(options.maxPerType ?? DEFAULT_MAX_PER_TYPE));
|
|
166
|
+
const maxBodyBytes = Math.max(256, Math.floor(options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES));
|
|
167
|
+
const includeTypes = options.includeTypes?.length ? new Set(options.includeTypes) : null;
|
|
168
|
+
const logs: DebugDeviceReport['logs'] = {};
|
|
169
|
+
|
|
170
|
+
DebugToolkit.features.forEach((feature) => {
|
|
171
|
+
if (includeTypes && !includeTypes.has(feature.name)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let snapshot: unknown;
|
|
176
|
+
try {
|
|
177
|
+
snapshot = feature.getSnapshot();
|
|
178
|
+
} catch {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!Array.isArray(snapshot)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
logs[feature.name] = snapshot
|
|
187
|
+
.slice(-maxPerType)
|
|
188
|
+
.map((entry) => sanitizeValue(entry, maxBodyBytes));
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const constants = Platform.constants as Record<string, unknown> | undefined;
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
version: 2,
|
|
195
|
+
device: {
|
|
196
|
+
platform: Platform.OS,
|
|
197
|
+
model: (constants?.model as string) || 'unknown',
|
|
198
|
+
osVersion: Platform.Version == null ? 'unknown' : String(Platform.Version),
|
|
199
|
+
appVersion: (constants?.appVersion as string) || 'unknown',
|
|
200
|
+
},
|
|
201
|
+
logs,
|
|
202
|
+
};
|
|
203
|
+
}
|