react-native-debug-toolkit 3.1.3 → 3.1.4
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 +4 -2
- package/README.zh-CN.md +4 -2
- package/lib/commonjs/core/DebugToolkit.js +118 -97
- package/lib/commonjs/core/DebugToolkit.js.map +1 -1
- package/lib/commonjs/core/initialize.js +4 -4
- package/lib/commonjs/core/initialize.js.map +1 -1
- package/lib/commonjs/features/environment/index.js +22 -24
- package/lib/commonjs/features/environment/index.js.map +1 -1
- package/lib/commonjs/features/network/index.js +25 -47
- package/lib/commonjs/features/network/index.js.map +1 -1
- package/lib/commonjs/features/network/networkInterceptor.js +3 -3
- package/lib/commonjs/features/network/networkInterceptor.js.map +1 -1
- package/lib/commonjs/index.js +0 -30
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/DaemonClient.js +13 -51
- package/lib/commonjs/utils/DaemonClient.js.map +1 -1
- package/lib/commonjs/utils/createChannelFeature.js +8 -1
- package/lib/commonjs/utils/createChannelFeature.js.map +1 -1
- package/lib/commonjs/utils/deviceReport.js +2 -1
- package/lib/commonjs/utils/deviceReport.js.map +1 -1
- package/lib/commonjs/utils/urlRewriter.js +15 -0
- package/lib/commonjs/utils/urlRewriter.js.map +1 -0
- package/lib/module/core/DebugToolkit.js +117 -96
- package/lib/module/core/DebugToolkit.js.map +1 -1
- package/lib/module/core/initialize.js +6 -7
- package/lib/module/core/initialize.js.map +1 -1
- package/lib/module/features/environment/index.js +22 -24
- package/lib/module/features/environment/index.js.map +1 -1
- package/lib/module/features/network/index.js +25 -46
- package/lib/module/features/network/index.js.map +1 -1
- package/lib/module/features/network/networkInterceptor.js +3 -3
- package/lib/module/features/network/networkInterceptor.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/DaemonClient.js +14 -42
- package/lib/module/utils/DaemonClient.js.map +1 -1
- package/lib/module/utils/createChannelFeature.js +8 -1
- package/lib/module/utils/createChannelFeature.js.map +1 -1
- package/lib/module/utils/deviceReport.js +3 -2
- package/lib/module/utils/deviceReport.js.map +1 -1
- package/lib/module/utils/urlRewriter.js +10 -0
- package/lib/module/utils/urlRewriter.js.map +1 -0
- package/lib/typescript/src/core/DebugToolkit.d.ts +23 -10
- package/lib/typescript/src/core/DebugToolkit.d.ts.map +1 -1
- package/lib/typescript/src/core/initialize.d.ts.map +1 -1
- package/lib/typescript/src/features/environment/index.d.ts.map +1 -1
- package/lib/typescript/src/features/network/index.d.ts +3 -3
- package/lib/typescript/src/features/network/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types/feature.d.ts +5 -0
- package/lib/typescript/src/types/feature.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +1 -1
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/DaemonClient.d.ts +4 -11
- package/lib/typescript/src/utils/DaemonClient.d.ts.map +1 -1
- package/lib/typescript/src/utils/createChannelFeature.d.ts +4 -0
- package/lib/typescript/src/utils/createChannelFeature.d.ts.map +1 -1
- package/lib/typescript/src/utils/deviceReport.d.ts +4 -1
- package/lib/typescript/src/utils/deviceReport.d.ts.map +1 -1
- package/lib/typescript/src/utils/urlRewriter.d.ts +5 -0
- package/lib/typescript/src/utils/urlRewriter.d.ts.map +1 -0
- package/node/daemon/src/console/console.html +94 -15
- package/node/daemon/src/server.js +32 -2
- package/node/mcp/src/logs.js +15 -4
- package/node/mcp/src/tools.js +4 -2
- package/package.json +1 -1
- package/src/core/DebugToolkit.tsx +119 -105
- package/src/core/initialize.ts +7 -8
- package/src/features/environment/index.ts +25 -27
- package/src/features/network/index.ts +30 -52
- package/src/features/network/networkInterceptor.ts +3 -3
- package/src/index.ts +3 -8
- package/src/types/feature.ts +6 -0
- package/src/types/index.ts +1 -0
- package/src/utils/DaemonClient.ts +14 -56
- package/src/utils/createChannelFeature.ts +12 -1
- package/src/utils/deviceReport.ts +5 -3
- package/src/utils/urlRewriter.ts +11 -0
- package/lib/commonjs/utils/urlRewriterRegistry.js +0 -14
- package/lib/commonjs/utils/urlRewriterRegistry.js.map +0 -1
- package/lib/module/utils/urlRewriterRegistry.js +0 -10
- package/lib/module/utils/urlRewriterRegistry.js.map +0 -1
- package/lib/typescript/src/utils/urlRewriterRegistry.d.ts +0 -7
- package/lib/typescript/src/utils/urlRewriterRegistry.d.ts.map +0 -1
- package/src/utils/urlRewriterRegistry.ts +0 -10
|
@@ -1,176 +1,190 @@
|
|
|
1
|
-
import type { AnyDebugFeature } from '../types';
|
|
1
|
+
import type { AnyDebugFeature, DebugFeatureListener, FeatureDataProvider } from '../types';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
class DebugToolkitCore implements FeatureDataProvider {
|
|
4
|
+
private _features: AnyDebugFeature[] = [];
|
|
5
|
+
private _launcherVisible = false;
|
|
6
|
+
private _panelOpen = false;
|
|
7
|
+
private _enabled = true;
|
|
8
|
+
private _listeners = new Set<DebugFeatureListener>();
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
let _panelOpen = false;
|
|
9
|
-
let _enabled = true;
|
|
10
|
+
private notify(): void {
|
|
11
|
+
this._listeners.forEach((l) => l());
|
|
12
|
+
}
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
listeners.forEach((l) => l());
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function setupFeature(feature: AnyDebugFeature): void {
|
|
16
|
-
feature.setup?.();
|
|
17
|
-
}
|
|
14
|
+
// --- FeatureDataProvider ---
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
16
|
+
get features(): AnyDebugFeature[] {
|
|
17
|
+
return [...this._features];
|
|
18
|
+
}
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
listeners.add(listener);
|
|
20
|
+
subscribe(listener: DebugFeatureListener): () => void {
|
|
21
|
+
this._listeners.add(listener);
|
|
26
22
|
return () => {
|
|
27
|
-
|
|
23
|
+
this._listeners.delete(listener);
|
|
28
24
|
};
|
|
29
|
-
}
|
|
25
|
+
}
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
return [..._features];
|
|
33
|
-
},
|
|
27
|
+
// --- Enabled ---
|
|
34
28
|
|
|
35
29
|
get enabled(): boolean {
|
|
36
|
-
return _enabled;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get launcherVisible(): boolean {
|
|
40
|
-
return _launcherVisible;
|
|
41
|
-
},
|
|
30
|
+
return this._enabled;
|
|
31
|
+
}
|
|
42
32
|
|
|
43
33
|
setEnabled(enabled: boolean): void {
|
|
44
|
-
if (_enabled === enabled) return;
|
|
45
|
-
_enabled = enabled;
|
|
34
|
+
if (this._enabled === enabled) return;
|
|
35
|
+
this._enabled = enabled;
|
|
46
36
|
if (!enabled) {
|
|
47
|
-
_launcherVisible = false;
|
|
48
|
-
_features.forEach(
|
|
49
|
-
_features = [];
|
|
37
|
+
this._launcherVisible = false;
|
|
38
|
+
this._features.forEach((f) => f.cleanup?.());
|
|
39
|
+
this._features = [];
|
|
50
40
|
}
|
|
51
|
-
notify();
|
|
52
|
-
}
|
|
41
|
+
this.notify();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// --- Feature Management ---
|
|
53
45
|
|
|
54
46
|
replaceFeatures(features: AnyDebugFeature[]): void {
|
|
55
|
-
if (!_enabled) return;
|
|
47
|
+
if (!this._enabled) return;
|
|
56
48
|
const next = features.filter(
|
|
57
49
|
(f, i, arr) =>
|
|
58
50
|
f && typeof f.name === 'string' && arr.findIndex((item) => item.name === f.name) === i,
|
|
59
51
|
);
|
|
60
|
-
const prevMap = new Map(_features.map((f) => [f.name, f]));
|
|
52
|
+
const prevMap = new Map(this._features.map((f) => [f.name, f]));
|
|
61
53
|
const nextMap = new Map(next.map((f) => [f.name, f]));
|
|
62
54
|
|
|
63
|
-
_features.forEach((f) => {
|
|
64
|
-
if (!nextMap.get(f.name) || nextMap.get(f.name) !== f)
|
|
55
|
+
this._features.forEach((f) => {
|
|
56
|
+
if (!nextMap.get(f.name) || nextMap.get(f.name) !== f) f.cleanup?.();
|
|
65
57
|
});
|
|
66
58
|
next.forEach((f) => {
|
|
67
|
-
if (!prevMap.get(f.name) || prevMap.get(f.name) !== f)
|
|
59
|
+
if (!prevMap.get(f.name) || prevMap.get(f.name) !== f) f.setup?.();
|
|
68
60
|
});
|
|
69
61
|
|
|
70
|
-
_features = next;
|
|
71
|
-
notify();
|
|
72
|
-
}
|
|
62
|
+
this._features = next;
|
|
63
|
+
this.notify();
|
|
64
|
+
}
|
|
73
65
|
|
|
74
66
|
addFeature(feature: AnyDebugFeature): void {
|
|
75
|
-
if (!_enabled || !feature || typeof feature.name !== 'string') {
|
|
67
|
+
if (!this._enabled || !feature || typeof feature.name !== 'string') {
|
|
76
68
|
return;
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
const existingIndex = _features.findIndex((f) => f.name === feature.name);
|
|
71
|
+
const existingIndex = this._features.findIndex((f) => f.name === feature.name);
|
|
80
72
|
if (existingIndex >= 0) {
|
|
81
|
-
const existing = _features[existingIndex]!;
|
|
73
|
+
const existing = this._features[existingIndex]!;
|
|
82
74
|
if (existing === feature) {
|
|
83
75
|
return;
|
|
84
76
|
}
|
|
85
77
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
_features = [
|
|
89
|
-
..._features.slice(0, existingIndex),
|
|
78
|
+
existing.cleanup?.();
|
|
79
|
+
feature.setup?.();
|
|
80
|
+
this._features = [
|
|
81
|
+
...this._features.slice(0, existingIndex),
|
|
90
82
|
feature,
|
|
91
|
-
..._features.slice(existingIndex + 1),
|
|
83
|
+
...this._features.slice(existingIndex + 1),
|
|
92
84
|
];
|
|
93
|
-
notify();
|
|
85
|
+
this.notify();
|
|
94
86
|
return;
|
|
95
87
|
}
|
|
96
88
|
|
|
97
|
-
|
|
98
|
-
_features = [..._features, feature];
|
|
99
|
-
notify();
|
|
100
|
-
}
|
|
89
|
+
feature.setup?.();
|
|
90
|
+
this._features = [...this._features, feature];
|
|
91
|
+
this.notify();
|
|
92
|
+
}
|
|
101
93
|
|
|
102
94
|
removeFeature(name: string): void {
|
|
103
|
-
if (!_enabled) {
|
|
95
|
+
if (!this._enabled) {
|
|
104
96
|
return;
|
|
105
97
|
}
|
|
106
98
|
|
|
107
|
-
const feature = _features.find((f) => f.name === name);
|
|
99
|
+
const feature = this._features.find((f) => f.name === name);
|
|
108
100
|
if (!feature) {
|
|
109
101
|
return;
|
|
110
102
|
}
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
_features = _features.filter((f) => f.name !== name);
|
|
114
|
-
if (_features.length === 0) {
|
|
115
|
-
_launcherVisible = false;
|
|
104
|
+
feature.cleanup?.();
|
|
105
|
+
this._features = this._features.filter((f) => f.name !== name);
|
|
106
|
+
if (this._features.length === 0) {
|
|
107
|
+
this._launcherVisible = false;
|
|
116
108
|
}
|
|
117
|
-
notify();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
reset(): void {
|
|
121
|
-
_launcherVisible = false;
|
|
122
|
-
_panelOpen = false;
|
|
123
|
-
_features.forEach(cleanupFeature);
|
|
124
|
-
_features = [];
|
|
125
|
-
notify();
|
|
126
|
-
},
|
|
109
|
+
this.notify();
|
|
110
|
+
}
|
|
127
111
|
|
|
128
112
|
hasFeatures(): boolean {
|
|
129
|
-
return _features.length > 0;
|
|
130
|
-
}
|
|
113
|
+
return this._features.length > 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// --- Panel ---
|
|
131
117
|
|
|
132
118
|
get panelOpen(): boolean {
|
|
133
|
-
return _panelOpen;
|
|
134
|
-
}
|
|
119
|
+
return this._panelOpen;
|
|
120
|
+
}
|
|
135
121
|
|
|
136
122
|
openPanel(): void {
|
|
137
|
-
if (!_enabled || _panelOpen) return;
|
|
138
|
-
_panelOpen = true;
|
|
139
|
-
notify();
|
|
140
|
-
}
|
|
123
|
+
if (!this._enabled || this._panelOpen) return;
|
|
124
|
+
this._panelOpen = true;
|
|
125
|
+
this.notify();
|
|
126
|
+
}
|
|
141
127
|
|
|
142
128
|
closePanel(): void {
|
|
143
|
-
if (!_panelOpen) return;
|
|
144
|
-
_panelOpen = false;
|
|
145
|
-
notify();
|
|
146
|
-
}
|
|
129
|
+
if (!this._panelOpen) return;
|
|
130
|
+
this._panelOpen = false;
|
|
131
|
+
this.notify();
|
|
132
|
+
}
|
|
147
133
|
|
|
148
134
|
togglePanel(): void {
|
|
149
|
-
if (_panelOpen) {
|
|
150
|
-
|
|
135
|
+
if (this._panelOpen) {
|
|
136
|
+
this.closePanel();
|
|
151
137
|
} else {
|
|
152
|
-
|
|
138
|
+
this.openPanel();
|
|
153
139
|
}
|
|
154
|
-
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// --- Launcher ---
|
|
143
|
+
|
|
144
|
+
get launcherVisible(): boolean {
|
|
145
|
+
return this._launcherVisible;
|
|
146
|
+
}
|
|
155
147
|
|
|
156
148
|
showLauncher(): void {
|
|
157
|
-
if (!_enabled) return;
|
|
158
|
-
_launcherVisible = true;
|
|
159
|
-
notify();
|
|
160
|
-
}
|
|
149
|
+
if (!this._enabled) return;
|
|
150
|
+
this._launcherVisible = true;
|
|
151
|
+
this.notify();
|
|
152
|
+
}
|
|
161
153
|
|
|
162
154
|
hideLauncher(): void {
|
|
163
|
-
_launcherVisible
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
if (!this._launcherVisible) return;
|
|
156
|
+
this._launcherVisible = false;
|
|
157
|
+
this.notify();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// --- Bulk Operations ---
|
|
166
161
|
|
|
167
162
|
clearAll(): void {
|
|
168
|
-
_features.forEach((f) => f.clear?.());
|
|
169
|
-
notify();
|
|
170
|
-
}
|
|
163
|
+
this._features.forEach((f) => f.clear?.());
|
|
164
|
+
this.notify();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
reset(): void {
|
|
168
|
+
this._launcherVisible = false;
|
|
169
|
+
this._panelOpen = false;
|
|
170
|
+
this._features.forEach((f) => f.cleanup?.());
|
|
171
|
+
this._features = [];
|
|
172
|
+
this.notify();
|
|
173
|
+
}
|
|
171
174
|
|
|
172
175
|
destroy(): void {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
}
|
|
176
|
+
this.reset();
|
|
177
|
+
this._listeners.clear();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Module-level default instance for non-React scenarios and backward compatibility. */
|
|
182
|
+
export const debugToolkit = new DebugToolkitCore();
|
|
183
|
+
|
|
184
|
+
export type DebugToolkit = DebugToolkitCore;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @deprecated Use `debugToolkit` or get instance from `initializeDebugToolkit()`.
|
|
188
|
+
* This is the default module-level instance exported for backward compatibility.
|
|
189
|
+
*/
|
|
190
|
+
export const DebugToolkit = debugToolkit;
|
package/src/core/initialize.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DebugToolkit } from './DebugToolkit';
|
|
2
|
-
import { createNetworkFeature } from '../features/network';
|
|
2
|
+
import { createNetworkFeature, addToBlacklist } from '../features/network';
|
|
3
3
|
import type { NetworkFeatureConfig } from '../features/network';
|
|
4
4
|
import { createConsoleLogFeature } from '../features/console';
|
|
5
5
|
import type { ConsoleFeatureConfig } from '../features/console';
|
|
@@ -11,16 +11,11 @@ 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
|
|
15
|
-
import { _addDaemonEndpointToNetworkBlacklist } from '../features/network';
|
|
14
|
+
import { daemonClient } from '../utils/DaemonClient';
|
|
16
15
|
import type { AnyDebugFeature, BuiltInFeatureName } from '../types';
|
|
17
16
|
|
|
18
17
|
const isDebugMode = __DEV__;
|
|
19
18
|
|
|
20
|
-
daemonClient.setEndpointDetector((url) => {
|
|
21
|
-
_addDaemonEndpointToNetworkBlacklist(url);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
19
|
/** Feature-specific configuration map */
|
|
25
20
|
export interface FeatureConfigs {
|
|
26
21
|
network?: boolean | NetworkFeatureConfig;
|
|
@@ -114,13 +109,17 @@ export function initializeDebugToolkit(
|
|
|
114
109
|
|
|
115
110
|
DebugToolkit.replaceFeatures(resolvedFeatures);
|
|
116
111
|
|
|
112
|
+
daemonClient.setEndpointDetector((url) => {
|
|
113
|
+
addToBlacklist(url);
|
|
114
|
+
});
|
|
115
|
+
|
|
117
116
|
if (DebugToolkit.hasFeatures()) {
|
|
118
117
|
DebugToolkit.showLauncher();
|
|
119
118
|
} else {
|
|
120
119
|
DebugToolkit.hideLauncher();
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
|
|
122
|
+
daemonClient.restore().catch(() => {});
|
|
124
123
|
|
|
125
124
|
return DebugToolkit;
|
|
126
125
|
} catch (error) {
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
EnvironmentConfig,
|
|
6
6
|
EnvironmentState,
|
|
7
7
|
} from '../../types';
|
|
8
|
-
import {
|
|
8
|
+
import { setUrlRewriter } from '../../utils/urlRewriter';
|
|
9
9
|
|
|
10
10
|
// Lazy AsyncStorage loader
|
|
11
11
|
type AsyncStorageModule = {
|
|
@@ -32,10 +32,6 @@ function getAsyncStorage(): AsyncStorageModule | null {
|
|
|
32
32
|
|
|
33
33
|
const STORAGE_KEY = 'debug_toolkit_env_id';
|
|
34
34
|
|
|
35
|
-
// Module-level state for synchronous URL rewriting
|
|
36
|
-
let currentHostsMap: Map<string, string> | null = null;
|
|
37
|
-
let activeEnvironmentId: string | null = null;
|
|
38
|
-
|
|
39
35
|
function buildHostsMap(
|
|
40
36
|
environments: EnvironmentConfig[],
|
|
41
37
|
targetId: string | null,
|
|
@@ -53,24 +49,6 @@ function buildHostsMap(
|
|
|
53
49
|
return map;
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
function createUrlRewriter(): (url: string) => string {
|
|
57
|
-
return (url: string): string => {
|
|
58
|
-
if (!currentHostsMap) return url;
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
const parsed = new URL(url);
|
|
62
|
-
const targetHost = currentHostsMap.get(parsed.host);
|
|
63
|
-
if (targetHost) {
|
|
64
|
-
return url.replace(parsed.host, targetHost);
|
|
65
|
-
}
|
|
66
|
-
} catch {
|
|
67
|
-
// Not a valid URL or relative URL — return unchanged
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return url;
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
52
|
export interface EnvironmentFeatureAPI extends DebugFeature<EnvironmentState> {
|
|
75
53
|
registerEnvironments: (environments: EnvironmentConfig[]) => void;
|
|
76
54
|
switchEnvironment: (environmentId: string | null) => void;
|
|
@@ -83,6 +61,26 @@ export const createEnvironmentFeature = (
|
|
|
83
61
|
const listeners = new Set<DebugFeatureListener>();
|
|
84
62
|
let environments: EnvironmentConfig[] = initialEnvironments ?? [];
|
|
85
63
|
let initialized = false;
|
|
64
|
+
let currentHostsMap: Map<string, string> | null = null;
|
|
65
|
+
let activeEnvironmentId: string | null = null;
|
|
66
|
+
|
|
67
|
+
const createUrlRewriter = (): ((url: string) => string) => {
|
|
68
|
+
return (url: string): string => {
|
|
69
|
+
if (!currentHostsMap) return url;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const parsed = new URL(url);
|
|
73
|
+
const targetHost = currentHostsMap.get(parsed.host);
|
|
74
|
+
if (targetHost) {
|
|
75
|
+
return url.replace(parsed.host, targetHost);
|
|
76
|
+
}
|
|
77
|
+
} catch {
|
|
78
|
+
// Not a valid URL or relative URL — return unchanged
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return url;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
86
84
|
|
|
87
85
|
const getCurrentState = (): EnvironmentState => ({
|
|
88
86
|
environments,
|
|
@@ -102,9 +100,9 @@ export const createEnvironmentFeature = (
|
|
|
102
100
|
if (initialized) {
|
|
103
101
|
try {
|
|
104
102
|
if (envId && environments.length > 0) {
|
|
105
|
-
|
|
103
|
+
setUrlRewriter(createUrlRewriter());
|
|
106
104
|
} else {
|
|
107
|
-
|
|
105
|
+
setUrlRewriter(null);
|
|
108
106
|
}
|
|
109
107
|
} catch (err) {
|
|
110
108
|
if (__DEV__) console.warn('[DebugToolkit] Failed to set URL rewriter:', err);
|
|
@@ -149,7 +147,7 @@ export const createEnvironmentFeature = (
|
|
|
149
147
|
|
|
150
148
|
// Install rewriter if an environment is already selected
|
|
151
149
|
if (activeEnvironmentId && environments.length > 0) {
|
|
152
|
-
|
|
150
|
+
setUrlRewriter(createUrlRewriter());
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
// Async persistence load (will override if a preference exists)
|
|
@@ -162,7 +160,7 @@ export const createEnvironmentFeature = (
|
|
|
162
160
|
},
|
|
163
161
|
cleanup: () => {
|
|
164
162
|
if (!initialized) return;
|
|
165
|
-
|
|
163
|
+
setUrlRewriter(null);
|
|
166
164
|
activeEnvironmentId = null;
|
|
167
165
|
currentHostsMap = null;
|
|
168
166
|
notify();
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { NetworkLogTab } from './NetworkLogTab';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { NetworkLogEntry } from '../../types';
|
|
4
|
+
import { createChannelFeature } from '../../utils/createChannelFeature';
|
|
4
5
|
import { createEventChannel } from '../../utils/createEventChannel';
|
|
5
|
-
import { createPersistedObservableStore } from '../../utils/createPersistedObservableStore';
|
|
6
6
|
import { KEYS } from '../../utils/debugPreferences';
|
|
7
|
-
import { urlRewriter } from '../../utils/urlRewriterRegistry';
|
|
8
7
|
import {
|
|
9
8
|
startXMLHttpRequest,
|
|
10
9
|
resetInterceptors,
|
|
11
10
|
} from './networkInterceptor';
|
|
12
11
|
import type { NetworkLogPayload } from './networkInterceptor';
|
|
12
|
+
import { setUrlRewriter as setInterceptorUrlRewriter } from '../../utils/urlRewriter';
|
|
13
13
|
|
|
14
14
|
// ─── Utilities ────────────────────────────────────────
|
|
15
15
|
|
|
@@ -35,7 +35,6 @@ function emitNetworkLog(entry: NetworkLogPayload): void {
|
|
|
35
35
|
|
|
36
36
|
// ─── Feature factory ──────────────────────────────────
|
|
37
37
|
|
|
38
|
-
const DEFAULT_MAX_LOGS = 200;
|
|
39
38
|
const daemonEndpointBlacklist: Array<string | RegExp> = [];
|
|
40
39
|
|
|
41
40
|
export interface NetworkFeatureConfig {
|
|
@@ -45,54 +44,33 @@ export interface NetworkFeatureConfig {
|
|
|
45
44
|
blacklist?: Array<string | RegExp>;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
export const createNetworkFeature = (config?: NetworkFeatureConfig)
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
unsubscribeLogs = networkChannel.subscribe(handleLog);
|
|
75
|
-
stopXhrFn = startXMLHttpRequest(emitNetworkLog);
|
|
76
|
-
initialized = true;
|
|
47
|
+
export const createNetworkFeature = (config?: NetworkFeatureConfig) => {
|
|
48
|
+
const userBlacklist = config?.blacklist ? [...config.blacklist] : [];
|
|
49
|
+
|
|
50
|
+
return createChannelFeature<NetworkLogPayload, NetworkLogEntry>(
|
|
51
|
+
() => networkChannel,
|
|
52
|
+
(payload, id) => ({ ...payload, id }),
|
|
53
|
+
{
|
|
54
|
+
name: 'network',
|
|
55
|
+
label: 'Network',
|
|
56
|
+
renderContent: NetworkLogTab,
|
|
57
|
+
maxLogs: config?.maxLogs,
|
|
58
|
+
persist: { storageKey: KEYS.networkLogs, maxPersist: 30 },
|
|
59
|
+
beforePush: (payload) => {
|
|
60
|
+
if (isUrlBlacklisted(payload.request.url, [...userBlacklist, ...daemonEndpointBlacklist])) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return payload;
|
|
64
|
+
},
|
|
65
|
+
onSetup: () => {
|
|
66
|
+
const stopXhr = startXMLHttpRequest(emitNetworkLog);
|
|
67
|
+
return () => {
|
|
68
|
+
setInterceptorUrlRewriter(null);
|
|
69
|
+
stopXhr();
|
|
70
|
+
};
|
|
71
|
+
},
|
|
77
72
|
},
|
|
78
|
-
|
|
79
|
-
clear: () => {
|
|
80
|
-
logStore.clear();
|
|
81
|
-
},
|
|
82
|
-
cleanup: () => {
|
|
83
|
-
if (!initialized) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
urlRewriter.set(null);
|
|
87
|
-
unsubscribeLogs?.();
|
|
88
|
-
unsubscribeLogs = null;
|
|
89
|
-
stopXhrFn?.();
|
|
90
|
-
stopXhrFn = null;
|
|
91
|
-
logStore.clear();
|
|
92
|
-
initialized = false;
|
|
93
|
-
},
|
|
94
|
-
subscribe: (listener) => logStore.subscribe(listener),
|
|
95
|
-
};
|
|
73
|
+
);
|
|
96
74
|
};
|
|
97
75
|
|
|
98
76
|
function normalizeDaemonEndpoint(endpoint: string): string {
|
|
@@ -109,7 +87,7 @@ function normalizeDaemonEndpoint(endpoint: string): string {
|
|
|
109
87
|
}
|
|
110
88
|
}
|
|
111
89
|
|
|
112
|
-
export function
|
|
90
|
+
export function addToBlacklist(endpoint: string): void {
|
|
113
91
|
const normalized = normalizeDaemonEndpoint(endpoint);
|
|
114
92
|
if (!normalized || daemonEndpointBlacklist.includes(normalized)) {
|
|
115
93
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { NetworkLogEntry } from '../../types';
|
|
2
|
-
import {
|
|
2
|
+
import { getUrlRewriter } from '../../utils/urlRewriter';
|
|
3
3
|
|
|
4
4
|
type NetworkLogPayload = Omit<NetworkLogEntry, 'id'>;
|
|
5
5
|
|
|
@@ -11,7 +11,7 @@ export type { NetworkLogPayload };
|
|
|
11
11
|
// ─── Shared helpers ────────────────────────────────────
|
|
12
12
|
|
|
13
13
|
function rewriteUrl(url: string): string {
|
|
14
|
-
const rewriter =
|
|
14
|
+
const rewriter = getUrlRewriter();
|
|
15
15
|
if (!rewriter) {
|
|
16
16
|
return url;
|
|
17
17
|
}
|
|
@@ -193,7 +193,7 @@ export function startXMLHttpRequest(
|
|
|
193
193
|
url: string,
|
|
194
194
|
...args: unknown[]
|
|
195
195
|
) {
|
|
196
|
-
const rewrittenUrl =
|
|
196
|
+
const rewrittenUrl = rewriteUrl(url);
|
|
197
197
|
if (shouldIgnoreUrl(rewrittenUrl)) {
|
|
198
198
|
return originalXhrOpen!.call(this, method, rewrittenUrl, ...args);
|
|
199
199
|
}
|
package/src/index.ts
CHANGED
|
@@ -42,21 +42,16 @@ export type {
|
|
|
42
42
|
ReportResult,
|
|
43
43
|
ReportToDaemonOptions,
|
|
44
44
|
} from './utils/DaemonClient';
|
|
45
|
-
export {
|
|
46
|
-
getDefaultDaemonEndpoint,
|
|
47
|
-
reportDebugDeviceToDaemon,
|
|
48
|
-
checkDaemonConnection,
|
|
49
|
-
startStreaming,
|
|
50
|
-
stopStreaming,
|
|
51
|
-
isStreaming,
|
|
52
|
-
} from './utils/DaemonClient';
|
|
45
|
+
export { getDefaultDaemonEndpoint } from './utils/DaemonClient';
|
|
53
46
|
|
|
54
47
|
// Types
|
|
55
48
|
export type {
|
|
56
49
|
AnyDebugFeature,
|
|
57
50
|
BuiltInFeatureName,
|
|
58
51
|
DebugFeature,
|
|
52
|
+
DebugFeatureListener,
|
|
59
53
|
DebugFeatureRenderProps,
|
|
54
|
+
FeatureDataProvider,
|
|
60
55
|
NetworkLogEntry,
|
|
61
56
|
ConsoleLogEntry,
|
|
62
57
|
ZustandLogEntry,
|
package/src/types/feature.ts
CHANGED
|
@@ -19,6 +19,12 @@ export interface DebugFeatureRenderProps<TSnapshot = unknown> {
|
|
|
19
19
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
20
|
export type AnyDebugFeature = DebugFeature<any>;
|
|
21
21
|
|
|
22
|
+
/** Provides feature list and change notifications to consumers (e.g., DaemonClient). */
|
|
23
|
+
export interface FeatureDataProvider {
|
|
24
|
+
readonly features: AnyDebugFeature[];
|
|
25
|
+
subscribe(listener: DebugFeatureListener): () => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
export interface DebugFeature<TSnapshot = unknown> {
|
|
23
29
|
name: string;
|
|
24
30
|
label: string;
|