@rozenite/network-activity-plugin 1.0.0 → 1.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 +9 -0
- package/dist/App.html +1 -1
- package/dist/assets/{App-C6wCDVkW.js → App-o_iVtD-5.js} +50 -7
- package/dist/boot-recording.cjs +1092 -0
- package/dist/boot-recording.js +1091 -0
- package/dist/react-native.cjs +3 -0
- package/dist/react-native.d.ts +3 -0
- package/dist/react-native.js +5 -1
- package/dist/rozenite.json +1 -1
- package/dist/src/react-native/boot-recording.d.ts +41 -0
- package/dist/src/react-native/config.d.ts +7 -4
- package/dist/src/react-native/events-listener.d.ts +44 -0
- package/dist/src/react-native/http/http-inspector.d.ts +10 -0
- package/dist/src/react-native/http/http-utils.d.ts +15 -0
- package/dist/src/react-native/inspector.d.ts +7 -0
- package/dist/src/react-native/network-inspector.d.ts +16 -0
- package/dist/src/react-native/sse/sse-inspector.d.ts +4 -7
- package/dist/src/react-native/useHttpInspector.d.ts +3 -0
- package/dist/src/react-native/useSSEInspector.d.ts +3 -0
- package/dist/src/react-native/useWebSocketInspector.d.ts +3 -0
- package/dist/src/react-native/websocket/websocket-inspector.d.ts +4 -7
- package/dist/src/shared/client.d.ts +3 -98
- package/dist/src/shared/http-events.d.ts +106 -0
- package/dist/src/shared/sse-events.d.ts +1 -1
- package/dist/src/ui/state/hooks.d.ts +3 -3
- package/dist/src/ui/state/model.d.ts +10 -0
- package/dist/useNetworkActivityDevTools.cjs +112 -993
- package/dist/useNetworkActivityDevTools.js +110 -989
- package/package.json +4 -4
- package/react-native.ts +8 -0
- package/src/react-native/boot-recording.ts +90 -0
- package/src/react-native/config.ts +9 -4
- package/src/react-native/events-listener.ts +102 -0
- package/src/react-native/http/http-inspector.ts +174 -0
- package/src/react-native/http/http-utils.ts +217 -0
- package/src/react-native/inspector.ts +10 -0
- package/src/react-native/network-inspector.ts +78 -0
- package/src/react-native/sse/sse-inspector.ts +12 -10
- package/src/react-native/useHttpInspector.ts +59 -0
- package/src/react-native/useNetworkActivityDevTools.ts +60 -115
- package/src/react-native/useSSEInspector.ts +35 -0
- package/src/react-native/useWebSocketInspector.ts +35 -0
- package/src/react-native/websocket/websocket-inspector.ts +18 -10
- package/src/shared/client.ts +4 -132
- package/src/shared/http-events.ts +140 -0
- package/src/shared/sse-events.ts +1 -1
- package/src/ui/components/RequestList.tsx +18 -6
- package/src/ui/components/Toolbar.tsx +3 -2
- package/src/ui/state/derived.ts +9 -3
- package/src/ui/state/model.ts +10 -0
- package/src/ui/state/store.ts +34 -3
- package/dist/src/react-native/http/network-inspector.d.ts +0 -8
- package/src/react-native/http/network-inspector.ts +0 -388
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { getHTTPInspector, HTTPInspector, HTTP_EVENTS } from './http/http-inspector';
|
|
2
|
+
import { getSSEInspector, SSEInspector, SSE_EVENTS } from './sse/sse-inspector';
|
|
3
|
+
import { getWebSocketInspector, WebSocketInspector, WEBSOCKET_EVENTS } from './websocket/websocket-inspector';
|
|
4
|
+
import { EventsListener } from './events-listener';
|
|
5
|
+
import { NetworkActivityEventMap } from '../shared/client';
|
|
6
|
+
import type { InspectorsConfig } from './config';
|
|
7
|
+
|
|
8
|
+
export type NetworkInspector = {
|
|
9
|
+
readonly http: HTTPInspector;
|
|
10
|
+
readonly sse: SSEInspector;
|
|
11
|
+
readonly websocket: WebSocketInspector;
|
|
12
|
+
setup: (eventsListener: EventsListener<NetworkActivityEventMap>) => void;
|
|
13
|
+
enable: (config?: InspectorsConfig) => void;
|
|
14
|
+
disable: () => void;
|
|
15
|
+
dispose: () => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const createNetworkInspectorInstance = (): NetworkInspector => {
|
|
19
|
+
const http = getHTTPInspector();
|
|
20
|
+
const sse = getSSEInspector();
|
|
21
|
+
const websocket = getWebSocketInspector();
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
http,
|
|
25
|
+
sse,
|
|
26
|
+
websocket,
|
|
27
|
+
|
|
28
|
+
setup(eventsListener: EventsListener<NetworkActivityEventMap>) {
|
|
29
|
+
HTTP_EVENTS.forEach(event => {
|
|
30
|
+
http.on(event, (data) => {
|
|
31
|
+
eventsListener.send(event, data);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
SSE_EVENTS.forEach(event => {
|
|
36
|
+
sse.on(event, (data) => {
|
|
37
|
+
eventsListener.send(data.type, data);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
WEBSOCKET_EVENTS.forEach(event => {
|
|
42
|
+
websocket.on(event, (data) => {
|
|
43
|
+
eventsListener.send(data.type, data);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
enable(config: InspectorsConfig = { http: true, sse: true, websocket: true }) {
|
|
49
|
+
if (config.http) http.enable();
|
|
50
|
+
if (config.sse) sse.enable();
|
|
51
|
+
if (config.websocket) websocket.enable();
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
disable() {
|
|
55
|
+
http.disable();
|
|
56
|
+
sse.disable();
|
|
57
|
+
websocket.disable();
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
dispose() {
|
|
61
|
+
http.dispose();
|
|
62
|
+
sse.dispose();
|
|
63
|
+
websocket.dispose();
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const getNetworkInspector = (() => {
|
|
69
|
+
let instance: NetworkInspector | null = null;
|
|
70
|
+
|
|
71
|
+
return (): NetworkInspector => {
|
|
72
|
+
if (!instance) {
|
|
73
|
+
instance = createNetworkInspectorInstance();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return instance;
|
|
77
|
+
};
|
|
78
|
+
})();
|
|
@@ -3,20 +3,23 @@ import { SSEInterceptor } from './sse-interceptor';
|
|
|
3
3
|
import { EventSourceWithInternals } from './types';
|
|
4
4
|
import { SSEEvent, SSEEventMap } from '../../shared/sse-events';
|
|
5
5
|
import { getContentType } from '../utils';
|
|
6
|
+
import type { Inspector } from '../inspector';
|
|
6
7
|
|
|
7
8
|
type NanoEventsMap = {
|
|
8
9
|
[K in keyof SSEEventMap]: (data: SSEEventMap[K]) => void;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
export type SSEInspector =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
export type SSEInspector = Inspector<SSEEventMap>;
|
|
13
|
+
|
|
14
|
+
export const SSE_EVENTS: (keyof SSEEventMap)[] = [
|
|
15
|
+
'sse-open',
|
|
16
|
+
'sse-message',
|
|
17
|
+
'sse-error',
|
|
18
|
+
'sse-close',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export const isSSEEvent = (type: string): type is keyof SSEEventMap => {
|
|
22
|
+
return (SSE_EVENTS as readonly string[]).includes(type);
|
|
20
23
|
};
|
|
21
24
|
|
|
22
25
|
export const getSSEInspector = (): SSEInspector => {
|
|
@@ -129,7 +132,6 @@ export const getSSEInspector = (): SSEInspector => {
|
|
|
129
132
|
isEnabled: () => SSEInterceptor.isInterceptorEnabled(),
|
|
130
133
|
dispose: () => {
|
|
131
134
|
SSEInterceptor.disableInterception();
|
|
132
|
-
eventEmitter.events = {};
|
|
133
135
|
},
|
|
134
136
|
on: <TEventType extends keyof SSEEventMap>(
|
|
135
137
|
event: TEventType,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import type { HTTPInspector } from './http/http-inspector';
|
|
3
|
+
import type { NetworkActivityDevToolsClient } from '../shared/client';
|
|
4
|
+
import { getResponseBody } from './http/http-utils';
|
|
5
|
+
import { getOverridesRegistry } from './http/overrides-registry';
|
|
6
|
+
|
|
7
|
+
const overridesRegistry = getOverridesRegistry();
|
|
8
|
+
|
|
9
|
+
export const useHttpInspector = (
|
|
10
|
+
client: NetworkActivityDevToolsClient | null,
|
|
11
|
+
httpInspector: HTTPInspector,
|
|
12
|
+
isEnabled: boolean,
|
|
13
|
+
isRecordingEnabled: boolean
|
|
14
|
+
) => {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!client || !isEnabled) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const networkRequestsRegistry =
|
|
21
|
+
httpInspector.getNetworkRequestsRegistry();
|
|
22
|
+
|
|
23
|
+
const subscriptions = [
|
|
24
|
+
client.onMessage('network-enable', () => {
|
|
25
|
+
httpInspector.enable();
|
|
26
|
+
}),
|
|
27
|
+
client.onMessage('network-disable', () => {
|
|
28
|
+
httpInspector.disable();
|
|
29
|
+
}),
|
|
30
|
+
client.onMessage('set-overrides', (data) => {
|
|
31
|
+
overridesRegistry.setOverrides(data.overrides);
|
|
32
|
+
}),
|
|
33
|
+
client.onMessage('get-response-body', async ({ requestId }) => {
|
|
34
|
+
const request = networkRequestsRegistry.getEntry(requestId);
|
|
35
|
+
|
|
36
|
+
if (!request) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const body = await getResponseBody(request);
|
|
41
|
+
|
|
42
|
+
client.send('response-body', {
|
|
43
|
+
requestId,
|
|
44
|
+
body,
|
|
45
|
+
});
|
|
46
|
+
}),
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
// If recording was previously enabled, enable the inspector (hot reload)
|
|
50
|
+
if (isRecordingEnabled) {
|
|
51
|
+
httpInspector.enable();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return () => {
|
|
55
|
+
subscriptions.forEach((subscription) => subscription.remove());
|
|
56
|
+
httpInspector.dispose();
|
|
57
|
+
};
|
|
58
|
+
}, [client, httpInspector, isEnabled, isRecordingEnabled]);
|
|
59
|
+
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
2
|
import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
3
|
-
import { getNetworkInspector } from './http/network-inspector';
|
|
4
|
-
import { getOverridesRegistry } from './http/overrides-registry';
|
|
5
3
|
import { NetworkActivityEventMap } from '../shared/client';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { getSSEInspector } from './sse/sse-inspector';
|
|
10
|
-
import { SSEEventMap } from '../shared/sse-events';
|
|
4
|
+
import { isHttpEvent } from './http/http-inspector';
|
|
5
|
+
import { isWebSocketEvent } from './websocket/websocket-inspector';
|
|
6
|
+
import { isSSEEvent } from './sse/sse-inspector';
|
|
11
7
|
import {
|
|
12
8
|
DEFAULT_CONFIG,
|
|
13
9
|
NetworkActivityDevToolsConfig,
|
|
14
10
|
validateConfig,
|
|
15
11
|
} from './config';
|
|
12
|
+
import { createNetworkInspectorsConfiguration } from './boot-recording';
|
|
13
|
+
import { useHttpInspector } from './useHttpInspector';
|
|
14
|
+
import { useWebSocketInspector } from './useWebSocketInspector';
|
|
15
|
+
import { useSSEInspector } from './useSSEInspector';
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const inspectorsConfig = createNetworkInspectorsConfiguration();
|
|
18
18
|
|
|
19
19
|
export const useNetworkActivityDevTools = (
|
|
20
|
-
config: NetworkActivityDevToolsConfig = DEFAULT_CONFIG
|
|
20
|
+
config: NetworkActivityDevToolsConfig = DEFAULT_CONFIG,
|
|
21
21
|
) => {
|
|
22
22
|
const isRecordingEnabledRef = useRef(false);
|
|
23
23
|
const client = useRozeniteDevToolsClient<NetworkActivityEventMap>({
|
|
@@ -26,9 +26,11 @@ export const useNetworkActivityDevTools = (
|
|
|
26
26
|
|
|
27
27
|
const isHttpInspectorEnabled = config.inspectors?.http ?? true;
|
|
28
28
|
const isWebSocketInspectorEnabled = config.inspectors?.websocket ?? true;
|
|
29
|
-
const isSSEInspectorEnabled = config.inspectors?.sse ?? true;
|
|
29
|
+
const isSSEInspectorEnabled = config.inspectors?.sse ?? true;
|
|
30
30
|
const showUrlAsName = config.clientUISettings?.showUrlAsName;
|
|
31
31
|
|
|
32
|
+
const { eventsListener, networkInspector } = inspectorsConfig;
|
|
33
|
+
|
|
32
34
|
useEffect(() => {
|
|
33
35
|
if (!client) {
|
|
34
36
|
return;
|
|
@@ -37,32 +39,44 @@ export const useNetworkActivityDevTools = (
|
|
|
37
39
|
validateConfig(config);
|
|
38
40
|
}, [config]);
|
|
39
41
|
|
|
40
|
-
/** Persist the recording state across hot reloads */
|
|
41
42
|
useEffect(() => {
|
|
42
43
|
if (!client) {
|
|
43
44
|
return;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
47
|
const sendClientUISettings = () => {
|
|
48
48
|
client.send('client-ui-settings', {
|
|
49
49
|
settings: {
|
|
50
|
-
showUrlAsName:
|
|
50
|
+
showUrlAsName:
|
|
51
|
+
showUrlAsName ?? DEFAULT_CONFIG.clientUISettings?.showUrlAsName,
|
|
51
52
|
},
|
|
52
53
|
});
|
|
53
|
-
}
|
|
54
|
+
};
|
|
54
55
|
|
|
55
56
|
const subscriptions = [
|
|
56
57
|
client.onMessage('network-enable', () => {
|
|
57
58
|
isRecordingEnabledRef.current = true;
|
|
59
|
+
|
|
60
|
+
// Connect the events listener to send events through the DevTools client
|
|
61
|
+
// This also automatically flushes any queued messages
|
|
62
|
+
eventsListener.connect(client.send, (message) => {
|
|
63
|
+
// The below allow filtering out events based on the configuration passed to the hook
|
|
64
|
+
const type = message.type;
|
|
65
|
+
if (isHttpEvent(type)) {
|
|
66
|
+
return isHttpInspectorEnabled;
|
|
67
|
+
}
|
|
68
|
+
if (isWebSocketEvent(type)) {
|
|
69
|
+
return isWebSocketInspectorEnabled;
|
|
70
|
+
}
|
|
71
|
+
if (isSSEEvent(type)) {
|
|
72
|
+
return isSSEInspectorEnabled;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
});
|
|
58
76
|
}),
|
|
59
77
|
client.onMessage('network-disable', () => {
|
|
60
78
|
isRecordingEnabledRef.current = false;
|
|
61
79
|
}),
|
|
62
|
-
client.onMessage('set-overrides', (data) => {
|
|
63
|
-
overridesRegistry.setOverrides(data.overrides);
|
|
64
|
-
}),
|
|
65
|
-
|
|
66
80
|
client.onMessage('get-client-ui-settings', () => {
|
|
67
81
|
sendClientUISettings();
|
|
68
82
|
}),
|
|
@@ -74,103 +88,34 @@ export const useNetworkActivityDevTools = (
|
|
|
74
88
|
return () => {
|
|
75
89
|
subscriptions.forEach((subscription) => subscription.remove());
|
|
76
90
|
};
|
|
77
|
-
}, [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
'websocket-message-sent',
|
|
106
|
-
'websocket-message-received',
|
|
107
|
-
'websocket-error',
|
|
108
|
-
'websocket-connection-status-changed',
|
|
109
|
-
];
|
|
110
|
-
const websocketInspector = getWebSocketInspector();
|
|
111
|
-
|
|
112
|
-
eventsToForward.forEach((event) => {
|
|
113
|
-
websocketInspector.on(event, (event) => {
|
|
114
|
-
client.send(event.type, event);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
client.onMessage('network-enable', () => {
|
|
119
|
-
websocketInspector.enable();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
client.onMessage('network-disable', () => {
|
|
123
|
-
websocketInspector.disable();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// If recording was previously enabled, enable the inspector (hot reload)
|
|
127
|
-
if (isRecordingEnabledRef.current) {
|
|
128
|
-
websocketInspector.enable();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return () => {
|
|
132
|
-
// Subscriptions will be disposed by the inspector
|
|
133
|
-
websocketInspector.dispose();
|
|
134
|
-
};
|
|
135
|
-
}, [client, isWebSocketInspectorEnabled]);
|
|
136
|
-
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
if (!client || !isSSEInspectorEnabled) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const eventsToForward: UnionToTuple<keyof SSEEventMap> = [
|
|
143
|
-
'sse-open',
|
|
144
|
-
'sse-message',
|
|
145
|
-
'sse-error',
|
|
146
|
-
'sse-close',
|
|
147
|
-
];
|
|
148
|
-
const sseInspector = getSSEInspector();
|
|
149
|
-
|
|
150
|
-
eventsToForward.forEach((event) => {
|
|
151
|
-
sseInspector.on(event, (event) => {
|
|
152
|
-
client.send(event.type, event);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
client.onMessage('network-enable', () => {
|
|
157
|
-
sseInspector.enable();
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
client.onMessage('network-disable', () => {
|
|
161
|
-
sseInspector.disable();
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// If recording was previously enabled, enable the inspector (hot reload)
|
|
165
|
-
if (isRecordingEnabledRef.current) {
|
|
166
|
-
sseInspector.enable();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return () => {
|
|
170
|
-
// Subscriptions will be disposed by the inspector
|
|
171
|
-
sseInspector.dispose();
|
|
172
|
-
};
|
|
173
|
-
}, [client, isSSEInspectorEnabled]);
|
|
91
|
+
}, [
|
|
92
|
+
client,
|
|
93
|
+
showUrlAsName,
|
|
94
|
+
isHttpInspectorEnabled,
|
|
95
|
+
isWebSocketInspectorEnabled,
|
|
96
|
+
isSSEInspectorEnabled,
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
useHttpInspector(
|
|
100
|
+
client,
|
|
101
|
+
networkInspector.http,
|
|
102
|
+
isHttpInspectorEnabled,
|
|
103
|
+
isRecordingEnabledRef.current,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
useWebSocketInspector(
|
|
107
|
+
client,
|
|
108
|
+
networkInspector.websocket,
|
|
109
|
+
isWebSocketInspectorEnabled,
|
|
110
|
+
isRecordingEnabledRef.current,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
useSSEInspector(
|
|
114
|
+
client,
|
|
115
|
+
networkInspector.sse,
|
|
116
|
+
isSSEInspectorEnabled,
|
|
117
|
+
isRecordingEnabledRef.current,
|
|
118
|
+
);
|
|
174
119
|
|
|
175
120
|
return client;
|
|
176
121
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import type { SSEInspector } from './sse/sse-inspector';
|
|
3
|
+
import type { NetworkActivityDevToolsClient } from '../shared/client';
|
|
4
|
+
|
|
5
|
+
export const useSSEInspector = (
|
|
6
|
+
client: NetworkActivityDevToolsClient | null,
|
|
7
|
+
sseInspector: SSEInspector,
|
|
8
|
+
isEnabled: boolean,
|
|
9
|
+
isRecordingEnabled: boolean
|
|
10
|
+
) => {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!client || !isEnabled) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const subscriptions = [
|
|
17
|
+
client.onMessage('network-enable', () => {
|
|
18
|
+
sseInspector.enable();
|
|
19
|
+
}),
|
|
20
|
+
client.onMessage('network-disable', () => {
|
|
21
|
+
sseInspector.disable();
|
|
22
|
+
}),
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// If recording was previously enabled, enable the inspector (hot reload)
|
|
26
|
+
if (isRecordingEnabled) {
|
|
27
|
+
sseInspector.enable();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return () => {
|
|
31
|
+
subscriptions.forEach((subscription) => subscription.remove());
|
|
32
|
+
sseInspector.dispose();
|
|
33
|
+
};
|
|
34
|
+
}, [client, sseInspector, isEnabled, isRecordingEnabled]);
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import type { WebSocketInspector } from './websocket/websocket-inspector';
|
|
3
|
+
import type { NetworkActivityDevToolsClient } from '../shared/client';
|
|
4
|
+
|
|
5
|
+
export const useWebSocketInspector = (
|
|
6
|
+
client: NetworkActivityDevToolsClient | null,
|
|
7
|
+
websocketInspector: WebSocketInspector,
|
|
8
|
+
isEnabled: boolean,
|
|
9
|
+
isRecordingEnabled: boolean
|
|
10
|
+
) => {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!client || !isEnabled) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const subscriptions = [
|
|
17
|
+
client.onMessage('network-enable', () => {
|
|
18
|
+
websocketInspector.enable();
|
|
19
|
+
}),
|
|
20
|
+
client.onMessage('network-disable', () => {
|
|
21
|
+
websocketInspector.disable();
|
|
22
|
+
}),
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// If recording was previously enabled, enable the inspector (hot reload)
|
|
26
|
+
if (isRecordingEnabled) {
|
|
27
|
+
websocketInspector.enable();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return () => {
|
|
31
|
+
subscriptions.forEach((subscription) => subscription.remove());
|
|
32
|
+
websocketInspector.dispose();
|
|
33
|
+
};
|
|
34
|
+
}, [client, websocketInspector, isEnabled, isRecordingEnabled]);
|
|
35
|
+
};
|
|
@@ -4,20 +4,28 @@ import {
|
|
|
4
4
|
WebSocketEvent,
|
|
5
5
|
WebSocketEventMap,
|
|
6
6
|
} from '../../shared/websocket-events';
|
|
7
|
+
import type { Inspector } from '../inspector';
|
|
7
8
|
|
|
8
9
|
type NanoEventsMap = {
|
|
9
10
|
[K in keyof WebSocketEventMap]: (data: WebSocketEventMap[K]) => void;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export type WebSocketInspector =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
export type WebSocketInspector = Inspector<WebSocketEventMap>;
|
|
14
|
+
|
|
15
|
+
export const WEBSOCKET_EVENTS: (keyof WebSocketEventMap)[] = [
|
|
16
|
+
'websocket-connect',
|
|
17
|
+
'websocket-open',
|
|
18
|
+
'websocket-close',
|
|
19
|
+
'websocket-message-sent',
|
|
20
|
+
'websocket-message-received',
|
|
21
|
+
'websocket-error',
|
|
22
|
+
'websocket-connection-status-changed',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export const isWebSocketEvent = (
|
|
26
|
+
type: string
|
|
27
|
+
): type is keyof WebSocketEventMap => {
|
|
28
|
+
return (WEBSOCKET_EVENTS as readonly string[]).includes(type);
|
|
21
29
|
};
|
|
22
30
|
|
|
23
31
|
export const getWebSocketInspector = (): WebSocketInspector => {
|
|
@@ -169,7 +177,7 @@ export const getWebSocketInspector = (): WebSocketInspector => {
|
|
|
169
177
|
},
|
|
170
178
|
isEnabled: () => webSocketInterceptor.isInterceptorEnabled(),
|
|
171
179
|
dispose: () => {
|
|
172
|
-
|
|
180
|
+
webSocketInterceptor.disableInterception();
|
|
173
181
|
socketUrlMap.clear();
|
|
174
182
|
},
|
|
175
183
|
on: <TEventType extends keyof WebSocketEventMap>(
|
package/src/shared/client.ts
CHANGED
|
@@ -1,93 +1,9 @@
|
|
|
1
1
|
import { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
2
2
|
import { WebSocketEventMap } from './websocket-events';
|
|
3
3
|
import { SSEEventMap } from './sse-events';
|
|
4
|
+
import { HttpEventMap } from './http-events';
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
-
export type XHRHeaders = NonNullable<XMLHttpRequest['responseHeaders']>;
|
|
7
|
-
|
|
8
|
-
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
|
|
9
|
-
|
|
10
|
-
export type RequestId = string;
|
|
11
|
-
export type Timestamp = number;
|
|
12
|
-
|
|
13
|
-
export type XHRPostData =
|
|
14
|
-
| string
|
|
15
|
-
| Blob
|
|
16
|
-
| FormData
|
|
17
|
-
| ArrayBuffer
|
|
18
|
-
| ArrayBufferView
|
|
19
|
-
| unknown
|
|
20
|
-
| null
|
|
21
|
-
| undefined;
|
|
22
|
-
|
|
23
|
-
export type RequestTextPostData = {
|
|
24
|
-
type: 'text';
|
|
25
|
-
value: string;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export type RequestBinaryPostData = {
|
|
29
|
-
type: 'binary';
|
|
30
|
-
value: {
|
|
31
|
-
size: number;
|
|
32
|
-
type?: string;
|
|
33
|
-
name?: string;
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type RequestFormDataPostData = {
|
|
38
|
-
type: 'form-data';
|
|
39
|
-
value: Record<string, RequestTextPostData | RequestBinaryPostData>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type RequestPostData =
|
|
43
|
-
| RequestTextPostData
|
|
44
|
-
| RequestFormDataPostData
|
|
45
|
-
| RequestBinaryPostData
|
|
46
|
-
| null
|
|
47
|
-
| undefined;
|
|
48
|
-
|
|
49
|
-
export type Cookie = {
|
|
50
|
-
name: string;
|
|
51
|
-
value: string;
|
|
52
|
-
domain?: string;
|
|
53
|
-
path?: string;
|
|
54
|
-
expires?: string;
|
|
55
|
-
maxAge?: string;
|
|
56
|
-
secure?: boolean;
|
|
57
|
-
httpOnly?: boolean;
|
|
58
|
-
sameSite?: string;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export type Request = {
|
|
62
|
-
url: string;
|
|
63
|
-
method: HttpMethod;
|
|
64
|
-
headers: HttpHeaders;
|
|
65
|
-
postData?: RequestPostData;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export type Response = {
|
|
69
|
-
url: string;
|
|
70
|
-
status: number;
|
|
71
|
-
statusText: string;
|
|
72
|
-
headers: HttpHeaders;
|
|
73
|
-
contentType: string;
|
|
74
|
-
size: number | null;
|
|
75
|
-
responseTime: Timestamp;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export type Initiator = {
|
|
79
|
-
type: string;
|
|
80
|
-
url?: string;
|
|
81
|
-
lineNumber?: number;
|
|
82
|
-
columnNumber?: number;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export type ResourceType = 'XHR' | 'Fetch' | 'Other';
|
|
86
|
-
|
|
87
|
-
export type RequestOverride = {
|
|
88
|
-
status?: number;
|
|
89
|
-
body?: string;
|
|
90
|
-
};
|
|
6
|
+
export * from './http-events';
|
|
91
7
|
|
|
92
8
|
export type NetworkActivityClientUISettings = {
|
|
93
9
|
showUrlAsName?: boolean;
|
|
@@ -103,52 +19,8 @@ export type NetworkActivityEventMap = {
|
|
|
103
19
|
'client-ui-settings': {
|
|
104
20
|
settings?: NetworkActivityClientUISettings;
|
|
105
21
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
'request-sent': {
|
|
109
|
-
requestId: RequestId;
|
|
110
|
-
request: Request;
|
|
111
|
-
timestamp: Timestamp;
|
|
112
|
-
initiator: Initiator;
|
|
113
|
-
type: ResourceType;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
'response-received': {
|
|
117
|
-
requestId: RequestId;
|
|
118
|
-
timestamp: Timestamp;
|
|
119
|
-
type: ResourceType;
|
|
120
|
-
response: Response;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
'request-completed': {
|
|
124
|
-
requestId: RequestId;
|
|
125
|
-
timestamp: Timestamp;
|
|
126
|
-
duration: number;
|
|
127
|
-
size: number | null;
|
|
128
|
-
ttfb: number;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
'request-failed': {
|
|
132
|
-
requestId: RequestId;
|
|
133
|
-
timestamp: Timestamp;
|
|
134
|
-
type: ResourceType;
|
|
135
|
-
error: string;
|
|
136
|
-
canceled: boolean;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
'get-response-body': {
|
|
140
|
-
requestId: RequestId;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
'response-body': {
|
|
144
|
-
requestId: RequestId;
|
|
145
|
-
body: string | null;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
'set-overrides': {
|
|
149
|
-
overrides: [string, RequestOverride][];
|
|
150
|
-
};
|
|
151
|
-
} & WebSocketEventMap &
|
|
22
|
+
} & HttpEventMap &
|
|
23
|
+
WebSocketEventMap &
|
|
152
24
|
SSEEventMap;
|
|
153
25
|
|
|
154
26
|
export type NetworkActivityDevToolsClient =
|