@rozenite/network-activity-plugin 1.0.0-alpha.8 → 1.0.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 +2 -0
- package/dist/App.html +2 -2
- package/dist/assets/{App-R2ZMH9wJ.css → App-BrSkOkws.css} +269 -2
- package/dist/assets/{App-lNMijPJ4.js → App-C6wCDVkW.js} +17485 -10814
- package/dist/event-source.cjs +22 -0
- package/dist/event-source.js +23 -0
- package/dist/react-native.cjs +4 -1
- package/dist/react-native.js +4 -1
- package/dist/rozenite.json +1 -1
- package/dist/src/react-native/config.d.ts +20 -0
- package/dist/src/react-native/{network-inspector.d.ts → http/network-inspector.d.ts} +1 -1
- package/dist/src/react-native/http/overrides-registry.d.ts +6 -0
- package/dist/src/react-native/{xhr-interceptor.d.ts → http/xhr-interceptor.d.ts} +7 -1
- package/dist/src/react-native/sse/event-source.d.ts +2 -0
- package/dist/src/react-native/sse/sse-inspector.d.ts +9 -0
- package/dist/src/react-native/sse/sse-interceptor.d.ts +36 -0
- package/dist/src/react-native/sse/types.d.ts +6 -0
- package/dist/src/react-native/useNetworkActivityDevTools.d.ts +2 -1
- package/dist/src/react-native/utils/getBlobName.d.ts +35 -0
- package/dist/src/react-native/utils/getFormDataEntries.d.ts +18 -0
- package/dist/src/react-native/utils.d.ts +6 -0
- package/dist/src/react-native/websocket/websocket-inspector.d.ts +9 -0
- package/dist/src/react-native/websocket/websocket-interceptor.d.ts +74 -0
- package/dist/src/shared/client.d.ts +53 -6
- package/dist/src/shared/sse-events.d.ts +38 -0
- package/dist/src/shared/websocket-events.d.ts +60 -0
- package/dist/src/ui/components/Badge.d.ts +1 -1
- package/dist/src/ui/components/Button.d.ts +2 -2
- package/dist/src/ui/components/CodeBlock.d.ts +3 -0
- package/dist/src/ui/components/CodeEditor.d.ts +5 -0
- package/dist/src/ui/components/CookieCard.d.ts +7 -0
- package/dist/src/ui/components/CopyRequestDropdown.d.ts +7 -0
- package/dist/src/ui/components/DropdownMenu.d.ts +27 -0
- package/dist/src/ui/components/FilterBar.d.ts +10 -0
- package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +7 -0
- package/dist/src/ui/components/KeyValueGrid.d.ts +13 -0
- package/dist/src/ui/components/OverrideResponse.d.ts +8 -0
- package/dist/src/ui/components/RequestBody.d.ts +6 -0
- package/dist/src/ui/components/RequestList.d.ts +13 -28
- package/dist/src/ui/components/ScrollArea.d.ts +3 -2
- package/dist/src/ui/components/Section.d.ts +8 -0
- package/dist/src/ui/components/Separator.d.ts +2 -1
- package/dist/src/ui/components/SidePanel.d.ts +1 -0
- package/dist/src/ui/components/Tabs.d.ts +7 -0
- package/dist/src/ui/components/Toolbar.d.ts +1 -0
- package/dist/src/ui/hooks/useCopyToClipboard.d.ts +4 -0
- package/dist/src/ui/state/derived.d.ts +5 -0
- package/dist/src/ui/state/hooks.d.ts +21 -0
- package/dist/src/ui/state/model.d.ts +103 -0
- package/dist/src/ui/state/store.d.ts +48 -0
- package/dist/src/ui/tabs/CookiesTab.d.ts +3 -6
- package/dist/src/ui/tabs/HeadersTab.d.ts +3 -15
- package/dist/src/ui/tabs/MessagesTab.d.ts +5 -0
- package/dist/src/ui/tabs/RequestTab.d.ts +2 -7
- package/dist/src/ui/tabs/ResponseTab.d.ts +2 -8
- package/dist/src/ui/tabs/SSEMessagesTab.d.ts +5 -0
- package/dist/src/ui/tabs/TimingTab.d.ts +3 -5
- package/dist/src/ui/types.d.ts +4 -1
- package/dist/src/ui/utils/assert.d.ts +1 -0
- package/dist/src/ui/utils/checkRequestBodyBinary.d.ts +2 -0
- package/dist/src/ui/utils/copyToClipboard.d.ts +1 -0
- package/dist/src/ui/utils/escapeShellArg.d.ts +1 -0
- package/dist/src/ui/utils/generateCurlCommand.d.ts +2 -0
- package/dist/src/ui/utils/generateFetchCall.d.ts +2 -0
- package/dist/src/ui/utils/generateMultipartBody.d.ts +4 -0
- package/dist/src/ui/utils/getId.d.ts +1 -0
- package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
- package/dist/src/utils/applyReactNativeRequestHeadersLogic.d.ts +7 -0
- package/dist/src/utils/applyReactNativeResponseHeadersLogic.d.ts +9 -0
- package/dist/src/utils/cookieParser.d.ts +6 -0
- package/dist/src/utils/getContentTypeMimeType.d.ts +2 -0
- package/dist/src/utils/getHttpHeader.d.ts +5 -0
- package/dist/src/utils/getHttpHeaderValueAsString.d.ts +11 -0
- package/dist/src/utils/getStringSizeInBytes.d.ts +1 -0
- package/dist/src/utils/inferContentTypeFromPostData.d.ts +2 -0
- package/dist/src/utils/safeStringify.d.ts +1 -0
- package/dist/src/utils/typeChecks.d.ts +9 -0
- package/dist/useNetworkActivityDevTools.cjs +724 -40
- package/dist/useNetworkActivityDevTools.js +723 -41
- package/package.json +22 -8
- package/react-native.ts +6 -1
- package/src/react-native/config.ts +43 -0
- package/src/react-native/http/network-inspector.ts +388 -0
- package/src/react-native/http/overrides-registry.ts +32 -0
- package/src/react-native/{xhr-interceptor.ts → http/xhr-interceptor.ts} +19 -2
- package/src/react-native/{xml-request.d.ts → http/xml-request.d.ts} +1 -0
- package/src/react-native/sse/event-source.ts +25 -0
- package/src/react-native/sse/sse-inspector.ts +139 -0
- package/src/react-native/sse/sse-interceptor.ts +180 -0
- package/src/react-native/sse/types.ts +9 -0
- package/src/react-native/useNetworkActivityDevTools.ts +156 -4
- package/src/react-native/utils/getBlobName.ts +45 -0
- package/src/react-native/utils/getFormDataEntries.ts +32 -0
- package/src/react-native/utils.ts +43 -0
- package/src/react-native/websocket/websocket-inspector.ts +180 -0
- package/src/react-native/websocket/websocket-interceptor.d.ts +4 -0
- package/src/react-native/websocket/websocket-interceptor.ts +166 -0
- package/src/shared/client.ts +79 -6
- package/src/shared/sse-events.ts +47 -0
- package/src/shared/websocket-events.ts +79 -0
- package/src/ui/components/Button.tsx +1 -0
- package/src/ui/components/CodeBlock.tsx +19 -0
- package/src/ui/components/CodeEditor.tsx +26 -0
- package/src/ui/components/CookieCard.tsx +64 -0
- package/src/ui/components/CopyRequestDropdown.tsx +95 -0
- package/src/ui/components/DropdownMenu.tsx +206 -0
- package/src/ui/components/FilterBar.tsx +117 -0
- package/src/ui/components/Input.tsx +1 -1
- package/src/ui/components/JsonTree.tsx +20 -0
- package/src/ui/components/JsonTreeCopyableItem.tsx +37 -0
- package/src/ui/components/KeyValueGrid.tsx +51 -0
- package/src/ui/components/OverrideResponse.tsx +132 -0
- package/src/ui/components/RequestBody.tsx +86 -0
- package/src/ui/components/RequestList.tsx +101 -131
- package/src/ui/components/ScrollArea.tsx +1 -0
- package/src/ui/components/Section.tsx +46 -0
- package/src/ui/components/SidePanel.tsx +333 -0
- package/src/ui/components/Tabs.tsx +1 -1
- package/src/ui/components/Toolbar.tsx +45 -0
- package/src/ui/globals.css +4 -0
- package/src/ui/hooks/useCopyToClipboard.ts +28 -0
- package/src/ui/state/derived.ts +112 -0
- package/src/ui/state/hooks.ts +52 -0
- package/src/ui/state/model.ts +140 -0
- package/src/ui/state/store.ts +669 -0
- package/src/ui/tabs/CookiesTab.tsx +61 -278
- package/src/ui/tabs/HeadersTab.tsx +85 -103
- package/src/ui/tabs/MessagesTab.tsx +276 -0
- package/src/ui/tabs/RequestTab.tsx +58 -51
- package/src/ui/tabs/ResponseTab.tsx +101 -74
- package/src/ui/tabs/SSEMessagesTab.tsx +224 -0
- package/src/ui/tabs/TimingTab.tsx +30 -43
- package/src/ui/types.ts +4 -1
- package/src/ui/utils/assert.ts +5 -0
- package/src/ui/utils/checkRequestBodyBinary.ts +7 -0
- package/src/ui/utils/copyToClipboard.ts +3 -0
- package/src/ui/utils/escapeShellArg.ts +12 -0
- package/src/ui/utils/generateCurlCommand.ts +83 -0
- package/src/ui/utils/generateFetchCall.ts +64 -0
- package/src/ui/utils/generateMultipartBody.ts +19 -0
- package/src/ui/utils/getId.ts +10 -0
- package/src/ui/utils/getStatusColor.ts +15 -0
- package/src/ui/views/InspectorView.tsx +35 -319
- package/src/utils/applyReactNativeRequestHeadersLogic.ts +30 -0
- package/src/utils/applyReactNativeResponseHeadersLogic.ts +28 -0
- package/src/utils/cookieParser.ts +126 -0
- package/src/utils/getContentTypeMimeType.ts +17 -0
- package/src/utils/getHttpHeader.ts +17 -0
- package/src/utils/getHttpHeaderValueAsString.ts +13 -0
- package/src/utils/getStringSizeInBytes.ts +3 -0
- package/src/utils/inferContentTypeFromPostData.ts +9 -0
- package/src/utils/safeStringify.ts +7 -0
- package/src/utils/typeChecks.ts +27 -0
- package/tailwind.config.ts +3 -0
- package/vite.config.ts +12 -0
- package/dist/src/ui/utils/getHttpHeaderValue.d.ts +0 -2
- package/src/react-native/network-inspector.ts +0 -247
- package/src/ui/utils/getHttpHeaderValue.ts +0 -14
- /package/dist/src/react-native/{network-requests-registry.d.ts → http/network-requests-registry.d.ts} +0 -0
- /package/src/react-native/{network-requests-registry.ts → http/network-requests-registry.ts} +0 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { createNanoEvents } from 'nanoevents';
|
|
2
|
+
import { getWebSocketInterceptor } from './websocket-interceptor';
|
|
3
|
+
import {
|
|
4
|
+
WebSocketEvent,
|
|
5
|
+
WebSocketEventMap,
|
|
6
|
+
} from '../../shared/websocket-events';
|
|
7
|
+
|
|
8
|
+
type NanoEventsMap = {
|
|
9
|
+
[K in keyof WebSocketEventMap]: (data: WebSocketEventMap[K]) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type WebSocketInspector = {
|
|
13
|
+
enable: () => void;
|
|
14
|
+
disable: () => void;
|
|
15
|
+
isEnabled: () => boolean;
|
|
16
|
+
dispose: () => void;
|
|
17
|
+
on: <TEventType extends keyof WebSocketEventMap>(
|
|
18
|
+
event: TEventType,
|
|
19
|
+
callback: (data: WebSocketEventMap[TEventType]) => void
|
|
20
|
+
) => () => void;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const getWebSocketInspector = (): WebSocketInspector => {
|
|
24
|
+
const eventEmitter = createNanoEvents<NanoEventsMap>();
|
|
25
|
+
const socketUrlMap = new Map<number, string>();
|
|
26
|
+
const webSocketInterceptor = getWebSocketInterceptor();
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
enable: () => {
|
|
30
|
+
webSocketInterceptor.setConnectCallback(
|
|
31
|
+
(
|
|
32
|
+
url: string,
|
|
33
|
+
protocols: string[] | null,
|
|
34
|
+
options: string[],
|
|
35
|
+
socketId: number
|
|
36
|
+
) => {
|
|
37
|
+
socketUrlMap.set(socketId, url);
|
|
38
|
+
const event: WebSocketEvent = {
|
|
39
|
+
type: 'websocket-connect',
|
|
40
|
+
url,
|
|
41
|
+
socketId,
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
protocols,
|
|
44
|
+
options,
|
|
45
|
+
};
|
|
46
|
+
eventEmitter.emit('websocket-connect', event);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
webSocketInterceptor.setCloseCallback(
|
|
51
|
+
(code: number | null, reason: string | null, socketId: number) => {
|
|
52
|
+
const url = socketUrlMap.get(socketId);
|
|
53
|
+
|
|
54
|
+
if (!url) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const event: WebSocketEvent = {
|
|
59
|
+
type: 'websocket-close',
|
|
60
|
+
url,
|
|
61
|
+
socketId,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
code: code || 0,
|
|
64
|
+
reason: reason || undefined,
|
|
65
|
+
};
|
|
66
|
+
eventEmitter.emit('websocket-close', event);
|
|
67
|
+
socketUrlMap.delete(socketId);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
webSocketInterceptor.setOnMessageCallback(
|
|
72
|
+
(data: string, socketId: number) => {
|
|
73
|
+
const url = socketUrlMap.get(socketId);
|
|
74
|
+
|
|
75
|
+
if (!url) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const event: WebSocketEvent = {
|
|
80
|
+
type: 'websocket-message-received',
|
|
81
|
+
url,
|
|
82
|
+
socketId,
|
|
83
|
+
timestamp: Date.now(),
|
|
84
|
+
data,
|
|
85
|
+
messageType: typeof data === 'string' ? 'text' : 'binary',
|
|
86
|
+
};
|
|
87
|
+
eventEmitter.emit('websocket-message-received', event);
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
webSocketInterceptor.setOnErrorCallback(
|
|
92
|
+
(error: string, socketId: number) => {
|
|
93
|
+
const url = socketUrlMap.get(socketId);
|
|
94
|
+
|
|
95
|
+
if (!url) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const event: WebSocketEvent = {
|
|
100
|
+
type: 'websocket-error',
|
|
101
|
+
url,
|
|
102
|
+
socketId,
|
|
103
|
+
timestamp: Date.now(),
|
|
104
|
+
error,
|
|
105
|
+
};
|
|
106
|
+
eventEmitter.emit('websocket-error', event);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
webSocketInterceptor.setSendCallback((data: string, socketId: number) => {
|
|
111
|
+
const url = socketUrlMap.get(socketId);
|
|
112
|
+
|
|
113
|
+
if (!url) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const event: WebSocketEvent = {
|
|
118
|
+
type: 'websocket-message-sent',
|
|
119
|
+
url,
|
|
120
|
+
socketId,
|
|
121
|
+
timestamp: Date.now(),
|
|
122
|
+
data,
|
|
123
|
+
messageType: typeof data === 'string' ? 'text' : 'binary',
|
|
124
|
+
};
|
|
125
|
+
eventEmitter.emit('websocket-message-sent', event);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
webSocketInterceptor.setOnOpenCallback((socketId: number) => {
|
|
129
|
+
const url = socketUrlMap.get(socketId);
|
|
130
|
+
|
|
131
|
+
if (!url) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const event: WebSocketEvent = {
|
|
136
|
+
type: 'websocket-open',
|
|
137
|
+
url,
|
|
138
|
+
socketId,
|
|
139
|
+
timestamp: Date.now(),
|
|
140
|
+
};
|
|
141
|
+
eventEmitter.emit('websocket-open', event);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
webSocketInterceptor.setOnCloseCallback(
|
|
145
|
+
(error: { code: number; reason?: string }, socketId: number) => {
|
|
146
|
+
const url = socketUrlMap.get(socketId);
|
|
147
|
+
|
|
148
|
+
if (!url) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const event: WebSocketEvent = {
|
|
153
|
+
type: 'websocket-close',
|
|
154
|
+
url,
|
|
155
|
+
socketId,
|
|
156
|
+
timestamp: Date.now(),
|
|
157
|
+
code: error.code,
|
|
158
|
+
reason: error.reason,
|
|
159
|
+
};
|
|
160
|
+
eventEmitter.emit('websocket-close', event);
|
|
161
|
+
socketUrlMap.delete(socketId);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
webSocketInterceptor.enableInterception();
|
|
166
|
+
},
|
|
167
|
+
disable: () => {
|
|
168
|
+
webSocketInterceptor.disableInterception();
|
|
169
|
+
},
|
|
170
|
+
isEnabled: () => webSocketInterceptor.isInterceptorEnabled(),
|
|
171
|
+
dispose: () => {
|
|
172
|
+
eventEmitter.events = {};
|
|
173
|
+
socketUrlMap.clear();
|
|
174
|
+
},
|
|
175
|
+
on: <TEventType extends keyof WebSocketEventMap>(
|
|
176
|
+
event: TEventType,
|
|
177
|
+
callback: (data: WebSocketEventMap[TEventType]) => void
|
|
178
|
+
) => eventEmitter.on(event, callback as NanoEventsMap[TEventType]),
|
|
179
|
+
};
|
|
180
|
+
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import WebSocketInterceptor from 'react-native/Libraries/WebSocket/WebSocketInterceptor';
|
|
3
|
+
|
|
4
|
+
export interface WebSocketInterceptor {
|
|
5
|
+
/**
|
|
6
|
+
* Invoked when RCTWebSocketModule.close(...) is called.
|
|
7
|
+
*/
|
|
8
|
+
setCloseCallback(
|
|
9
|
+
callback: (
|
|
10
|
+
code: number | null,
|
|
11
|
+
reason: string | null,
|
|
12
|
+
socketId: number
|
|
13
|
+
) => void
|
|
14
|
+
): void;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Invoked when RCTWebSocketModule.send(...) or sendBinary(...) is called.
|
|
18
|
+
*/
|
|
19
|
+
setSendCallback(callback: (data: string, socketId: number) => void): void;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Invoked when RCTWebSocketModule.connect(...) is called.
|
|
23
|
+
*/
|
|
24
|
+
setConnectCallback(
|
|
25
|
+
callback: (
|
|
26
|
+
url: string,
|
|
27
|
+
protocols: string[] | null,
|
|
28
|
+
options: string[],
|
|
29
|
+
socketId: number
|
|
30
|
+
) => void
|
|
31
|
+
): void;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Invoked when event "websocketOpen" happens.
|
|
35
|
+
*/
|
|
36
|
+
setOnOpenCallback(callback: (socketId: number) => void): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Invoked when event "websocketMessage" happens.
|
|
40
|
+
*/
|
|
41
|
+
setOnMessageCallback(
|
|
42
|
+
callback: (data: string, socketId: number) => void
|
|
43
|
+
): void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Invoked when event "websocketFailed" happens.
|
|
47
|
+
*/
|
|
48
|
+
setOnErrorCallback(callback: (error: string, socketId: number) => void): void;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Invoked when event "websocketClosed" happens.
|
|
52
|
+
*/
|
|
53
|
+
setOnCloseCallback(
|
|
54
|
+
callback: (
|
|
55
|
+
error: { code: number; reason?: string },
|
|
56
|
+
socketId: number
|
|
57
|
+
) => void
|
|
58
|
+
): void;
|
|
59
|
+
|
|
60
|
+
isInterceptorEnabled(): boolean;
|
|
61
|
+
enableInterception(): void;
|
|
62
|
+
disableInterception(): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface WebSocketInterceptorPreRN079 {
|
|
66
|
+
/**
|
|
67
|
+
* Invoked when RCTWebSocketModule.close(...) is called.
|
|
68
|
+
*/
|
|
69
|
+
setCloseCallback(
|
|
70
|
+
callback: (
|
|
71
|
+
code: number | null,
|
|
72
|
+
reason: string | null,
|
|
73
|
+
socketId: number
|
|
74
|
+
) => void
|
|
75
|
+
): void;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Invoked when RCTWebSocketModule.send(...) or sendBinary(...) is called.
|
|
79
|
+
*/
|
|
80
|
+
setSendCallback(callback: (data: string, socketId: number) => void): void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Invoked when RCTWebSocketModule.connect(...) is called.
|
|
84
|
+
*/
|
|
85
|
+
setConnectCallback(
|
|
86
|
+
callback: (
|
|
87
|
+
url: string,
|
|
88
|
+
protocols: string[] | null,
|
|
89
|
+
options: string[],
|
|
90
|
+
socketId: number
|
|
91
|
+
) => void
|
|
92
|
+
): void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Invoked when event "websocketOpen" happens.
|
|
96
|
+
*/
|
|
97
|
+
setOnOpenCallback(callback: (socketId: number) => void): void;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Invoked when event "websocketMessage" happens.
|
|
101
|
+
*/
|
|
102
|
+
setOnMessageCallback(
|
|
103
|
+
callback: (socketId: number, data: string) => void
|
|
104
|
+
): void;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Invoked when event "websocketFailed" happens.
|
|
108
|
+
*/
|
|
109
|
+
setOnErrorCallback(callback: (socketId: number, error: string) => void): void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Invoked when event "websocketClosed" happens.
|
|
113
|
+
*/
|
|
114
|
+
setOnCloseCallback(
|
|
115
|
+
callback: (
|
|
116
|
+
socketId: number,
|
|
117
|
+
error: { code: number; reason?: string }
|
|
118
|
+
) => void
|
|
119
|
+
): void;
|
|
120
|
+
|
|
121
|
+
isInterceptorEnabled(): boolean;
|
|
122
|
+
enableInterception(): void;
|
|
123
|
+
disableInterception(): void;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const getWebSocketInterceptor = (): WebSocketInterceptor => {
|
|
127
|
+
/**
|
|
128
|
+
* Note: RN 0.79 changed the order of the arguments.
|
|
129
|
+
* @see https://github.com/facebook/react-native/commit/d2adb976abebcb0f38750903d98fbb5a3f50924b
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
if (Platform.constants.reactNativeVersion.minor >= 79) {
|
|
133
|
+
return WebSocketInterceptor as WebSocketInterceptor;
|
|
134
|
+
} else {
|
|
135
|
+
const WebSocketInterceptorPreRN079 =
|
|
136
|
+
WebSocketInterceptor as WebSocketInterceptorPreRN079;
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
...WebSocketInterceptorPreRN079,
|
|
140
|
+
setOnMessageCallback: (
|
|
141
|
+
callback: (data: string, socketId: number) => void
|
|
142
|
+
) => {
|
|
143
|
+
WebSocketInterceptorPreRN079.setOnMessageCallback((socketId, data) => {
|
|
144
|
+
callback(data, socketId);
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
setOnCloseCallback: (
|
|
148
|
+
callback: (
|
|
149
|
+
error: { code: number; reason?: string },
|
|
150
|
+
socketId: number
|
|
151
|
+
) => void
|
|
152
|
+
) => {
|
|
153
|
+
WebSocketInterceptorPreRN079.setOnCloseCallback((error, socketId) => {
|
|
154
|
+
callback(socketId, error);
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
setOnErrorCallback: (
|
|
158
|
+
callback: (error: string, socketId: number) => void
|
|
159
|
+
) => {
|
|
160
|
+
WebSocketInterceptorPreRN079.setOnErrorCallback((error, socketId) => {
|
|
161
|
+
callback(socketId, error);
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
} as WebSocketInterceptor;
|
|
165
|
+
}
|
|
166
|
+
};
|
package/src/shared/client.ts
CHANGED
|
@@ -1,15 +1,68 @@
|
|
|
1
1
|
import { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
2
|
+
import { WebSocketEventMap } from './websocket-events';
|
|
3
|
+
import { SSEEventMap } from './sse-events';
|
|
2
4
|
|
|
3
|
-
export type HttpHeaders = Record<string, string>;
|
|
5
|
+
export type HttpHeaders = Record<string, string | string[]>;
|
|
6
|
+
export type XHRHeaders = NonNullable<XMLHttpRequest['responseHeaders']>;
|
|
7
|
+
|
|
8
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
|
|
4
9
|
|
|
5
10
|
export type RequestId = string;
|
|
6
11
|
export type Timestamp = number;
|
|
7
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
|
+
|
|
8
61
|
export type Request = {
|
|
9
62
|
url: string;
|
|
10
|
-
method:
|
|
63
|
+
method: HttpMethod;
|
|
11
64
|
headers: HttpHeaders;
|
|
12
|
-
postData?:
|
|
65
|
+
postData?: RequestPostData;
|
|
13
66
|
};
|
|
14
67
|
|
|
15
68
|
export type Response = {
|
|
@@ -18,7 +71,7 @@ export type Response = {
|
|
|
18
71
|
statusText: string;
|
|
19
72
|
headers: HttpHeaders;
|
|
20
73
|
contentType: string;
|
|
21
|
-
size: number;
|
|
74
|
+
size: number | null;
|
|
22
75
|
responseTime: Timestamp;
|
|
23
76
|
};
|
|
24
77
|
|
|
@@ -31,11 +84,26 @@ export type Initiator = {
|
|
|
31
84
|
|
|
32
85
|
export type ResourceType = 'XHR' | 'Fetch' | 'Other';
|
|
33
86
|
|
|
87
|
+
export type RequestOverride = {
|
|
88
|
+
status?: number;
|
|
89
|
+
body?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type NetworkActivityClientUISettings = {
|
|
93
|
+
showUrlAsName?: boolean;
|
|
94
|
+
};
|
|
95
|
+
|
|
34
96
|
export type NetworkActivityEventMap = {
|
|
35
97
|
// Control events
|
|
36
98
|
'network-enable': unknown;
|
|
37
99
|
'network-disable': unknown;
|
|
38
100
|
|
|
101
|
+
// Client UI settings events
|
|
102
|
+
'get-client-ui-settings': unknown;
|
|
103
|
+
'client-ui-settings': {
|
|
104
|
+
settings?: NetworkActivityClientUISettings;
|
|
105
|
+
};
|
|
106
|
+
|
|
39
107
|
// Network request events
|
|
40
108
|
'request-sent': {
|
|
41
109
|
requestId: RequestId;
|
|
@@ -56,7 +124,7 @@ export type NetworkActivityEventMap = {
|
|
|
56
124
|
requestId: RequestId;
|
|
57
125
|
timestamp: Timestamp;
|
|
58
126
|
duration: number;
|
|
59
|
-
size: number;
|
|
127
|
+
size: number | null;
|
|
60
128
|
ttfb: number;
|
|
61
129
|
};
|
|
62
130
|
|
|
@@ -76,7 +144,12 @@ export type NetworkActivityEventMap = {
|
|
|
76
144
|
requestId: RequestId;
|
|
77
145
|
body: string | null;
|
|
78
146
|
};
|
|
79
|
-
|
|
147
|
+
|
|
148
|
+
'set-overrides': {
|
|
149
|
+
overrides: [string, RequestOverride][];
|
|
150
|
+
};
|
|
151
|
+
} & WebSocketEventMap &
|
|
152
|
+
SSEEventMap;
|
|
80
153
|
|
|
81
154
|
export type NetworkActivityDevToolsClient =
|
|
82
155
|
RozeniteDevToolsClient<NetworkActivityEventMap>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Response } from './client';
|
|
2
|
+
|
|
3
|
+
export type SSEConnectionStatus = 'connecting' | 'open' | 'closed';
|
|
4
|
+
export type SSERequestId = string;
|
|
5
|
+
|
|
6
|
+
export type SSEOpenEvent = {
|
|
7
|
+
type: 'sse-open';
|
|
8
|
+
requestId: SSERequestId;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
response: Response;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SSEMessageEvent = {
|
|
14
|
+
type: 'sse-message';
|
|
15
|
+
requestId: SSERequestId;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
payload: {
|
|
18
|
+
type: string;
|
|
19
|
+
data: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type SSEErrorEvent = {
|
|
24
|
+
type: 'sse-error';
|
|
25
|
+
requestId: SSERequestId;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
error: {
|
|
28
|
+
type: 'error' | 'timeout' | 'exception';
|
|
29
|
+
message: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type SSECloseEvent = {
|
|
34
|
+
type: 'sse-close';
|
|
35
|
+
requestId: SSERequestId;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type SSEEvent =
|
|
40
|
+
| SSEOpenEvent
|
|
41
|
+
| SSEMessageEvent
|
|
42
|
+
| SSEErrorEvent
|
|
43
|
+
| SSECloseEvent;
|
|
44
|
+
|
|
45
|
+
export type SSEEventMap = {
|
|
46
|
+
[K in SSEEvent['type']]: Extract<SSEEvent, { type: K }>;
|
|
47
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export type WebSocketMessageType = 'text' | 'binary';
|
|
2
|
+
|
|
3
|
+
export type WebSocketConnectionStatus =
|
|
4
|
+
| 'connecting'
|
|
5
|
+
| 'open'
|
|
6
|
+
| 'closing'
|
|
7
|
+
| 'closed';
|
|
8
|
+
|
|
9
|
+
export type WebSocketConnectEvent = {
|
|
10
|
+
type: 'websocket-connect';
|
|
11
|
+
url: string;
|
|
12
|
+
socketId: number;
|
|
13
|
+
timestamp: number;
|
|
14
|
+
protocols: string[] | null;
|
|
15
|
+
options: string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type WebSocketOpenEvent = {
|
|
19
|
+
type: 'websocket-open';
|
|
20
|
+
url: string;
|
|
21
|
+
socketId: number;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type WebSocketCloseEvent = {
|
|
26
|
+
type: 'websocket-close';
|
|
27
|
+
url: string;
|
|
28
|
+
socketId: number;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
code: number;
|
|
31
|
+
reason?: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type WebSocketMessageSentEvent = {
|
|
35
|
+
type: 'websocket-message-sent';
|
|
36
|
+
url: string;
|
|
37
|
+
socketId: number;
|
|
38
|
+
timestamp: number;
|
|
39
|
+
data: string;
|
|
40
|
+
messageType: WebSocketMessageType;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type WebSocketMessageReceivedEvent = {
|
|
44
|
+
type: 'websocket-message-received';
|
|
45
|
+
url: string;
|
|
46
|
+
socketId: number;
|
|
47
|
+
timestamp: number;
|
|
48
|
+
data: string;
|
|
49
|
+
messageType: WebSocketMessageType;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type WebSocketErrorEvent = {
|
|
53
|
+
type: 'websocket-error';
|
|
54
|
+
url: string;
|
|
55
|
+
socketId: number;
|
|
56
|
+
timestamp: number;
|
|
57
|
+
error: string;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type WebSocketConnectionStatusChangedEvent = {
|
|
61
|
+
type: 'websocket-connection-status-changed';
|
|
62
|
+
url: string;
|
|
63
|
+
socketId: number;
|
|
64
|
+
timestamp: number;
|
|
65
|
+
status: WebSocketConnectionStatus;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type WebSocketEvent =
|
|
69
|
+
| WebSocketConnectEvent
|
|
70
|
+
| WebSocketOpenEvent
|
|
71
|
+
| WebSocketCloseEvent
|
|
72
|
+
| WebSocketMessageSentEvent
|
|
73
|
+
| WebSocketMessageReceivedEvent
|
|
74
|
+
| WebSocketErrorEvent
|
|
75
|
+
| WebSocketConnectionStatusChangedEvent;
|
|
76
|
+
|
|
77
|
+
export type WebSocketEventMap = {
|
|
78
|
+
[K in WebSocketEvent['type']]: Extract<WebSocketEvent, { type: K }>;
|
|
79
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { HTMLProps } from 'react';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
|
|
4
|
+
export type CodeBlockProps = HTMLProps<HTMLPreElement>;
|
|
5
|
+
|
|
6
|
+
const codeBlockClassNames =
|
|
7
|
+
'text-sm font-mono text-gray-300 whitespace-pre-wrap bg-gray-800 p-3 rounded-md border border-gray-700 overflow-x-auto wrap-anywhere';
|
|
8
|
+
|
|
9
|
+
export const CodeBlock = ({
|
|
10
|
+
children,
|
|
11
|
+
className,
|
|
12
|
+
...props
|
|
13
|
+
}: CodeBlockProps) => {
|
|
14
|
+
return (
|
|
15
|
+
<pre className={cn(codeBlockClassNames, className)} {...props}>
|
|
16
|
+
{children}
|
|
17
|
+
</pre>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export type CodeEditorProps = {
|
|
4
|
+
data: string | undefined;
|
|
5
|
+
onInput?: (event: React.FormEvent<HTMLPreElement>) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const CodeEditor = forwardRef<HTMLPreElement, CodeEditorProps>(
|
|
9
|
+
({ data, onInput }, ref) => {
|
|
10
|
+
return (
|
|
11
|
+
<pre
|
|
12
|
+
ref={ref}
|
|
13
|
+
contentEditable
|
|
14
|
+
suppressContentEditableWarning
|
|
15
|
+
className={
|
|
16
|
+
'w-full text-sm font-mono text-gray-300 whitespace-pre-wrap bg-gray-800 p-3 rounded-md border border-gray-700 overflow-x-auto wrap-anywhere ring-offset-blue-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2'
|
|
17
|
+
}
|
|
18
|
+
onInput={onInput}
|
|
19
|
+
>
|
|
20
|
+
{data}
|
|
21
|
+
</pre>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CodeEditor.displayName = 'CodeEditor';
|