@rozenite/network-activity-plugin 1.5.1 → 1.7.0-rc.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/CHANGELOG.md +20 -0
- package/README.md +2 -0
- package/dist/{App.html → devtools/App.html} +2 -2
- package/dist/{boot-recording.cjs → react-native/chunks/boot-recording.cjs} +1 -1
- package/dist/{boot-recording.js → react-native/chunks/boot-recording.js} +3 -3
- package/dist/react-native/chunks/boot-recording.require.cjs +5 -0
- package/dist/react-native/chunks/boot-recording.require.js +5 -0
- package/dist/react-native/chunks/useNetworkActivityDevTools.require.cjs +1102 -0
- package/dist/react-native/chunks/useNetworkActivityDevTools.require.js +1102 -0
- package/dist/{react-native.cjs → react-native/index.cjs} +2 -2
- package/dist/react-native/index.d.ts +305 -0
- package/dist/{react-native.js → react-native/index.js} +2 -2
- package/dist/rozenite.json +1 -1
- package/package.json +27 -7
- package/src/react-native/agent/__tests__/network-activity-agent-state.test.ts +250 -0
- package/src/react-native/agent/state.ts +869 -0
- package/src/react-native/agent/tools.ts +146 -0
- package/src/react-native/agent/use-network-activity-agent-tools.ts +244 -0
- package/src/react-native/http/http-inspector.ts +0 -1
- package/src/react-native/useNetworkActivityDevTools.ts +11 -0
- package/tsconfig.json +3 -0
- package/dist/react-native.d.ts +0 -4
- package/dist/rozenite.config.d.ts +0 -7
- package/dist/src/react-native/boot-recording.d.ts +0 -41
- package/dist/src/react-native/config.d.ts +0 -23
- package/dist/src/react-native/events-listener.d.ts +0 -44
- package/dist/src/react-native/http/http-inspector.d.ts +0 -10
- package/dist/src/react-native/http/http-utils.d.ts +0 -15
- package/dist/src/react-native/http/network-requests-registry.d.ts +0 -6
- package/dist/src/react-native/http/overrides-registry.d.ts +0 -6
- package/dist/src/react-native/http/xhr-interceptor.d.ts +0 -44
- package/dist/src/react-native/inspector.d.ts +0 -7
- package/dist/src/react-native/network-inspector.d.ts +0 -16
- package/dist/src/react-native/sse/event-source.d.ts +0 -2
- package/dist/src/react-native/sse/sse-inspector.d.ts +0 -6
- package/dist/src/react-native/sse/sse-interceptor.d.ts +0 -36
- package/dist/src/react-native/sse/types.d.ts +0 -6
- package/dist/src/react-native/useHttpInspector.d.ts +0 -3
- package/dist/src/react-native/useNetworkActivityDevTools.d.ts +0 -3
- package/dist/src/react-native/useSSEInspector.d.ts +0 -3
- package/dist/src/react-native/useWebSocketInspector.d.ts +0 -3
- package/dist/src/react-native/utils/getBlobName.d.ts +0 -35
- package/dist/src/react-native/utils/getFormDataEntries.d.ts +0 -18
- package/dist/src/react-native/utils.d.ts +0 -6
- package/dist/src/react-native/websocket/websocket-inspector.d.ts +0 -6
- package/dist/src/react-native/websocket/websocket-interceptor.d.ts +0 -73
- package/dist/src/shared/client.d.ts +0 -17
- package/dist/src/shared/http-events.d.ts +0 -106
- package/dist/src/shared/sse-events.d.ts +0 -38
- package/dist/src/shared/websocket-events.d.ts +0 -60
- package/dist/src/ui/App.d.ts +0 -1
- package/dist/src/ui/components/Badge.d.ts +0 -9
- package/dist/src/ui/components/Button.d.ts +0 -11
- package/dist/src/ui/components/CodeBlock.d.ts +0 -3
- package/dist/src/ui/components/CodeEditor.d.ts +0 -5
- package/dist/src/ui/components/CookieCard.d.ts +0 -7
- package/dist/src/ui/components/CopyRequestDropdown.d.ts +0 -7
- package/dist/src/ui/components/DropdownMenu.d.ts +0 -27
- package/dist/src/ui/components/FilterBar.d.ts +0 -10
- package/dist/src/ui/components/Input.d.ts +0 -3
- package/dist/src/ui/components/JsonTree.d.ts +0 -5
- package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +0 -7
- package/dist/src/ui/components/KeyValueGrid.d.ts +0 -13
- package/dist/src/ui/components/OverrideResponse.d.ts +0 -8
- package/dist/src/ui/components/RequestBody.d.ts +0 -6
- package/dist/src/ui/components/RequestList.d.ts +0 -30
- package/dist/src/ui/components/ScrollArea.d.ts +0 -5
- package/dist/src/ui/components/Section.d.ts +0 -8
- package/dist/src/ui/components/Separator.d.ts +0 -4
- package/dist/src/ui/components/SidePanel.d.ts +0 -1
- package/dist/src/ui/components/Tabs.d.ts +0 -7
- package/dist/src/ui/components/Toolbar.d.ts +0 -1
- package/dist/src/ui/hooks/useCopyToClipboard.d.ts +0 -4
- package/dist/src/ui/state/derived.d.ts +0 -5
- package/dist/src/ui/state/hooks.d.ts +0 -21
- package/dist/src/ui/state/model.d.ts +0 -113
- package/dist/src/ui/state/store.d.ts +0 -48
- package/dist/src/ui/tabs/CookiesTab.d.ts +0 -5
- package/dist/src/ui/tabs/HeadersTab.d.ts +0 -5
- package/dist/src/ui/tabs/MessagesTab.d.ts +0 -5
- package/dist/src/ui/tabs/RequestTab.d.ts +0 -5
- package/dist/src/ui/tabs/ResponseTab.d.ts +0 -6
- package/dist/src/ui/tabs/SSEMessagesTab.d.ts +0 -5
- package/dist/src/ui/tabs/TimingTab.d.ts +0 -5
- package/dist/src/ui/types.d.ts +0 -26
- package/dist/src/ui/utils/assert.d.ts +0 -1
- package/dist/src/ui/utils/checkRequestBodyBinary.d.ts +0 -2
- package/dist/src/ui/utils/cn.d.ts +0 -2
- package/dist/src/ui/utils/copyToClipboard.d.ts +0 -1
- package/dist/src/ui/utils/escapeShellArg.d.ts +0 -1
- package/dist/src/ui/utils/generateCurlCommand.d.ts +0 -2
- package/dist/src/ui/utils/generateFetchCall.d.ts +0 -2
- package/dist/src/ui/utils/generateMultipartBody.d.ts +0 -4
- package/dist/src/ui/utils/getId.d.ts +0 -1
- package/dist/src/ui/utils/getStatusColor.d.ts +0 -1
- package/dist/src/ui/views/InspectorView.d.ts +0 -5
- package/dist/src/ui/views/LoadingView.d.ts +0 -1
- package/dist/src/utils/applyReactNativeRequestHeadersLogic.d.ts +0 -7
- package/dist/src/utils/applyReactNativeResponseHeadersLogic.d.ts +0 -9
- package/dist/src/utils/cookieParser.d.ts +0 -6
- package/dist/src/utils/getContentTypeMimeType.d.ts +0 -2
- package/dist/src/utils/getHttpHeader.d.ts +0 -5
- package/dist/src/utils/getHttpHeaderValueAsString.d.ts +0 -11
- package/dist/src/utils/getStringSizeInBytes.d.ts +0 -1
- package/dist/src/utils/inferContentTypeFromPostData.d.ts +0 -2
- package/dist/src/utils/safeStringify.d.ts +0 -1
- package/dist/src/utils/typeChecks.d.ts +0 -9
- package/dist/useNetworkActivityDevTools.cjs +0 -171
- package/dist/useNetworkActivityDevTools.js +0 -171
- /package/dist/{assets → devtools/assets}/App-BrSkOkws.css +0 -0
- /package/dist/{assets/App-CGt4qucR.js → devtools/assets/App-pokLiGYV.js} +0 -0
- /package/dist/{event-source.cjs → react-native/chunks/event-source.cjs} +0 -0
- /package/dist/{event-source.js → react-native/chunks/event-source.js} +0 -0
|
@@ -6,8 +6,8 @@ const isWeb = typeof window !== "undefined" && window.navigator.product !== "Rea
|
|
|
6
6
|
const isDev = process.env.NODE_ENV !== "production";
|
|
7
7
|
const isServer = typeof window === "undefined";
|
|
8
8
|
if (isDev && !isWeb && !isServer) {
|
|
9
|
-
exports.useNetworkActivityDevTools = require("./useNetworkActivityDevTools.cjs").useNetworkActivityDevTools;
|
|
10
|
-
exports.withOnBootNetworkActivityRecording = require("./boot-recording.cjs").withOnBootNetworkActivityRecording;
|
|
9
|
+
exports.useNetworkActivityDevTools = require("./chunks/useNetworkActivityDevTools.require.cjs").useNetworkActivityDevTools;
|
|
10
|
+
exports.withOnBootNetworkActivityRecording = require("./chunks/boot-recording.require.cjs").withOnBootNetworkActivityRecording;
|
|
11
11
|
} else {
|
|
12
12
|
exports.useNetworkActivityDevTools = () => null;
|
|
13
13
|
exports.withOnBootNetworkActivityRecording = (options) => null;
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
2
|
+
|
|
3
|
+
export declare type BootRecordingOptions = NetworkInspectorConfig & EventsListenerOptions & {
|
|
4
|
+
/**
|
|
5
|
+
* Enable queuing of events during boot before DevTools connects.
|
|
6
|
+
* When true, network activity is captured and queued until DevTools is ready.
|
|
7
|
+
* When false, nothing is queued and inspectors are not even set up.
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
enableBootRecording?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
declare type EventsListenerOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* Maximum number of messages to queue before DevTools connects.
|
|
16
|
+
* @default 200
|
|
17
|
+
*/
|
|
18
|
+
maxQueueSize?: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
declare type HttpEventMap = {
|
|
22
|
+
'request-sent': {
|
|
23
|
+
requestId: RequestId;
|
|
24
|
+
request: Request_2;
|
|
25
|
+
timestamp: Timestamp;
|
|
26
|
+
initiator: Initiator;
|
|
27
|
+
type: ResourceType;
|
|
28
|
+
};
|
|
29
|
+
'response-received': {
|
|
30
|
+
requestId: RequestId;
|
|
31
|
+
timestamp: Timestamp;
|
|
32
|
+
type: ResourceType;
|
|
33
|
+
response: Response_2;
|
|
34
|
+
};
|
|
35
|
+
'request-completed': {
|
|
36
|
+
requestId: RequestId;
|
|
37
|
+
timestamp: Timestamp;
|
|
38
|
+
duration: number;
|
|
39
|
+
size: number | null;
|
|
40
|
+
ttfb: number;
|
|
41
|
+
};
|
|
42
|
+
'request-failed': {
|
|
43
|
+
requestId: RequestId;
|
|
44
|
+
timestamp: Timestamp;
|
|
45
|
+
type: ResourceType;
|
|
46
|
+
error: string;
|
|
47
|
+
canceled: boolean;
|
|
48
|
+
};
|
|
49
|
+
'request-progress': {
|
|
50
|
+
requestId: RequestId;
|
|
51
|
+
timestamp: Timestamp;
|
|
52
|
+
loaded: number;
|
|
53
|
+
total: number;
|
|
54
|
+
lengthComputable: boolean;
|
|
55
|
+
};
|
|
56
|
+
'get-response-body': {
|
|
57
|
+
requestId: RequestId;
|
|
58
|
+
};
|
|
59
|
+
'response-body': {
|
|
60
|
+
requestId: RequestId;
|
|
61
|
+
body: string | null;
|
|
62
|
+
};
|
|
63
|
+
'set-overrides': {
|
|
64
|
+
overrides: [string, RequestOverride][];
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
declare type HttpHeaders = Record<string, string | string[]>;
|
|
69
|
+
|
|
70
|
+
declare type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
|
|
71
|
+
|
|
72
|
+
declare type Initiator = {
|
|
73
|
+
type: string;
|
|
74
|
+
url?: string;
|
|
75
|
+
lineNumber?: number;
|
|
76
|
+
columnNumber?: number;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
declare type InspectorsConfig = {
|
|
80
|
+
[key in InspectorType]?: boolean;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
declare type InspectorType = 'http' | 'websocket' | 'sse';
|
|
84
|
+
|
|
85
|
+
declare type NetworkActivityClientUISettings = {
|
|
86
|
+
showUrlAsName?: boolean;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export declare type NetworkActivityDevToolsConfig = NetworkInspectorConfig & {
|
|
90
|
+
clientUISettings?: {
|
|
91
|
+
/**
|
|
92
|
+
* If true, display the entire relative URL as the request name in the UI instead of only the last path segment.
|
|
93
|
+
* @default false
|
|
94
|
+
*/
|
|
95
|
+
showUrlAsName?: boolean;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
declare type NetworkActivityEventMap = {
|
|
100
|
+
'network-enable': unknown;
|
|
101
|
+
'network-disable': unknown;
|
|
102
|
+
'get-client-ui-settings': unknown;
|
|
103
|
+
'client-ui-settings': {
|
|
104
|
+
settings?: NetworkActivityClientUISettings;
|
|
105
|
+
};
|
|
106
|
+
} & HttpEventMap & WebSocketEventMap_2 & SSEEventMap;
|
|
107
|
+
|
|
108
|
+
declare type NetworkInspectorConfig = {
|
|
109
|
+
/**
|
|
110
|
+
* Specifies which network inspectors are enabled.
|
|
111
|
+
* Set to `false` to disable monitoring for a specific type of network traffic.
|
|
112
|
+
* @default { http: true, websocket: true, sse: true }
|
|
113
|
+
*/
|
|
114
|
+
inspectors?: InspectorsConfig;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
declare type Request_2 = {
|
|
118
|
+
url: string;
|
|
119
|
+
method: HttpMethod;
|
|
120
|
+
headers: HttpHeaders;
|
|
121
|
+
postData?: RequestPostData;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
declare type RequestBinaryPostData = {
|
|
125
|
+
type: 'binary';
|
|
126
|
+
value: {
|
|
127
|
+
size: number;
|
|
128
|
+
type?: string;
|
|
129
|
+
name?: string;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
declare type RequestFormDataPostData = {
|
|
134
|
+
type: 'form-data';
|
|
135
|
+
value: Record<string, RequestTextPostData | RequestBinaryPostData>;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
declare type RequestId = string;
|
|
139
|
+
|
|
140
|
+
declare type RequestOverride = {
|
|
141
|
+
status?: number;
|
|
142
|
+
body?: string;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
declare type RequestPostData = RequestTextPostData | RequestFormDataPostData | RequestBinaryPostData | null | undefined;
|
|
146
|
+
|
|
147
|
+
declare type RequestTextPostData = {
|
|
148
|
+
type: 'text';
|
|
149
|
+
value: string;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
declare type ResourceType = 'XHR' | 'Fetch' | 'Other';
|
|
153
|
+
|
|
154
|
+
declare type Response_2 = {
|
|
155
|
+
url: string;
|
|
156
|
+
status: number;
|
|
157
|
+
statusText: string;
|
|
158
|
+
headers: HttpHeaders;
|
|
159
|
+
contentType: string;
|
|
160
|
+
size: number | null;
|
|
161
|
+
responseTime: Timestamp;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
declare type SSECloseEvent = {
|
|
165
|
+
type: 'sse-close';
|
|
166
|
+
requestId: SSERequestId;
|
|
167
|
+
timestamp: number;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
declare type SSEErrorEvent = {
|
|
171
|
+
type: 'sse-error';
|
|
172
|
+
requestId: SSERequestId;
|
|
173
|
+
timestamp: number;
|
|
174
|
+
error: {
|
|
175
|
+
type: 'error' | 'timeout' | 'exception';
|
|
176
|
+
message: string;
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
declare type SSEEvent = SSEOpenEvent | SSEMessageEvent | SSEErrorEvent | SSECloseEvent;
|
|
181
|
+
|
|
182
|
+
declare type SSEEventMap = {
|
|
183
|
+
[K in SSEEvent['type']]: Extract<SSEEvent, {
|
|
184
|
+
type: K;
|
|
185
|
+
}>;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
declare type SSEMessageEvent = {
|
|
189
|
+
type: 'sse-message';
|
|
190
|
+
requestId: SSERequestId;
|
|
191
|
+
timestamp: number;
|
|
192
|
+
payload: {
|
|
193
|
+
type: string;
|
|
194
|
+
data: string;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
declare type SSEOpenEvent = {
|
|
199
|
+
type: 'sse-open';
|
|
200
|
+
requestId: SSERequestId;
|
|
201
|
+
timestamp: number;
|
|
202
|
+
response: Response_2;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
declare type SSERequestId = string;
|
|
206
|
+
|
|
207
|
+
declare type Timestamp = number;
|
|
208
|
+
|
|
209
|
+
export declare let useNetworkActivityDevTools: useNetworkActivityDevTools_2;
|
|
210
|
+
|
|
211
|
+
declare const useNetworkActivityDevTools_2: (config?: NetworkActivityDevToolsConfig) => RozeniteDevToolsClient<NetworkActivityEventMap> | null;
|
|
212
|
+
|
|
213
|
+
declare type WebSocketCloseEvent = {
|
|
214
|
+
type: 'websocket-close';
|
|
215
|
+
url: string;
|
|
216
|
+
socketId: number;
|
|
217
|
+
timestamp: number;
|
|
218
|
+
code: number;
|
|
219
|
+
reason?: string;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
declare type WebSocketConnectEvent = {
|
|
223
|
+
type: 'websocket-connect';
|
|
224
|
+
url: string;
|
|
225
|
+
socketId: number;
|
|
226
|
+
timestamp: number;
|
|
227
|
+
protocols: string[] | null;
|
|
228
|
+
options: string[];
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
declare type WebSocketConnectionStatus = 'connecting' | 'open' | 'closing' | 'closed';
|
|
232
|
+
|
|
233
|
+
declare type WebSocketConnectionStatusChangedEvent = {
|
|
234
|
+
type: 'websocket-connection-status-changed';
|
|
235
|
+
url: string;
|
|
236
|
+
socketId: number;
|
|
237
|
+
timestamp: number;
|
|
238
|
+
status: WebSocketConnectionStatus;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
declare type WebSocketErrorEvent = {
|
|
242
|
+
type: 'websocket-error';
|
|
243
|
+
url: string;
|
|
244
|
+
socketId: number;
|
|
245
|
+
timestamp: number;
|
|
246
|
+
error: string;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
declare type WebSocketEvent = WebSocketConnectEvent | WebSocketOpenEvent | WebSocketCloseEvent | WebSocketMessageSentEvent | WebSocketMessageReceivedEvent | WebSocketErrorEvent | WebSocketConnectionStatusChangedEvent;
|
|
250
|
+
|
|
251
|
+
declare type WebSocketEventMap_2 = {
|
|
252
|
+
[K in WebSocketEvent['type']]: Extract<WebSocketEvent, {
|
|
253
|
+
type: K;
|
|
254
|
+
}>;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
declare type WebSocketMessageReceivedEvent = {
|
|
258
|
+
type: 'websocket-message-received';
|
|
259
|
+
url: string;
|
|
260
|
+
socketId: number;
|
|
261
|
+
timestamp: number;
|
|
262
|
+
data: string;
|
|
263
|
+
messageType: WebSocketMessageType;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
declare type WebSocketMessageSentEvent = {
|
|
267
|
+
type: 'websocket-message-sent';
|
|
268
|
+
url: string;
|
|
269
|
+
socketId: number;
|
|
270
|
+
timestamp: number;
|
|
271
|
+
data: string;
|
|
272
|
+
messageType: WebSocketMessageType;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
declare type WebSocketMessageType = 'text' | 'binary';
|
|
276
|
+
|
|
277
|
+
declare type WebSocketOpenEvent = {
|
|
278
|
+
type: 'websocket-open';
|
|
279
|
+
url: string;
|
|
280
|
+
socketId: number;
|
|
281
|
+
timestamp: number;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
export declare let withOnBootNetworkActivityRecording: withOnBootNetworkActivityRecording_2;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Enable network activity recording during app boot, before DevTools connects.
|
|
288
|
+
* Call this at the root of your app to capture early network requests.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```tsx
|
|
292
|
+
* import { withOnBootNetworkActivityRecording } from '@rozenite/network-activity-plugin';
|
|
293
|
+
*
|
|
294
|
+
* // At app entry point, before any network requests
|
|
295
|
+
* withOnBootNetworkActivityRecording();
|
|
296
|
+
*
|
|
297
|
+
* function App() {
|
|
298
|
+
* useNetworkActivityDevTools();
|
|
299
|
+
* // ...
|
|
300
|
+
* }
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
declare const withOnBootNetworkActivityRecording_2: (options?: BootRecordingOptions) => void;
|
|
304
|
+
|
|
305
|
+
export { }
|
|
@@ -4,8 +4,8 @@ const isWeb = typeof window !== "undefined" && window.navigator.product !== "Rea
|
|
|
4
4
|
const isDev = process.env.NODE_ENV !== "production";
|
|
5
5
|
const isServer = typeof window === "undefined";
|
|
6
6
|
if (isDev && !isWeb && !isServer) {
|
|
7
|
-
useNetworkActivityDevTools = require("./useNetworkActivityDevTools.js").useNetworkActivityDevTools;
|
|
8
|
-
withOnBootNetworkActivityRecording = require("./boot-recording.js").withOnBootNetworkActivityRecording;
|
|
7
|
+
useNetworkActivityDevTools = require("./chunks/useNetworkActivityDevTools.require.js").useNetworkActivityDevTools;
|
|
8
|
+
withOnBootNetworkActivityRecording = require("./chunks/boot-recording.require.js").withOnBootNetworkActivityRecording;
|
|
9
9
|
} else {
|
|
10
10
|
useNetworkActivityDevTools = () => null;
|
|
11
11
|
withOnBootNetworkActivityRecording = (options) => null;
|
package/dist/rozenite.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@rozenite/network-activity-plugin","version":"1.
|
|
1
|
+
{"name":"@rozenite/network-activity-plugin","version":"1.7.0-rc.0","description":"Network Activity for Rozenite.","panels":[{"name":"Network Activity","source":"/devtools/App.html"}]}
|
package/package.json
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rozenite/network-activity-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0-rc.0",
|
|
4
4
|
"description": "Network Activity for Rozenite.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/react-native.cjs",
|
|
7
|
-
"module": "./dist/react-native.js",
|
|
8
|
-
"types": "./dist/react-native.d.ts",
|
|
6
|
+
"main": "./dist/react-native/index.cjs",
|
|
7
|
+
"module": "./dist/react-native/index.js",
|
|
8
|
+
"types": "./dist/react-native/index.d.ts",
|
|
9
|
+
"homepage": "https://github.com/callstackincubator/rozenite#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/callstackincubator/rozenite/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/callstackincubator/rozenite.git"
|
|
16
|
+
},
|
|
9
17
|
"dependencies": {
|
|
10
18
|
"nanoevents": "^9.1.0",
|
|
11
|
-
"@rozenite/
|
|
19
|
+
"@rozenite/agent-bridge": "1.7.0-rc.0",
|
|
20
|
+
"@rozenite/plugin-bridge": "1.7.0-rc.0"
|
|
12
21
|
},
|
|
13
22
|
"devDependencies": {
|
|
14
23
|
"@floating-ui/react": "^0.26.0",
|
|
@@ -39,8 +48,8 @@
|
|
|
39
48
|
"typescript": "~5.9.3",
|
|
40
49
|
"vite": "^7.3.1",
|
|
41
50
|
"zustand": "^5.0.6",
|
|
42
|
-
"@rozenite/vite-plugin": "1.
|
|
43
|
-
"rozenite": "1.
|
|
51
|
+
"@rozenite/vite-plugin": "1.7.0-rc.0",
|
|
52
|
+
"rozenite": "1.7.0-rc.0"
|
|
44
53
|
},
|
|
45
54
|
"peerDependencies": {
|
|
46
55
|
"react-native-sse": "*"
|
|
@@ -51,6 +60,17 @@
|
|
|
51
60
|
}
|
|
52
61
|
},
|
|
53
62
|
"license": "MIT",
|
|
63
|
+
"exports": {
|
|
64
|
+
".": {
|
|
65
|
+
"types": "./dist/react-native/index.d.ts",
|
|
66
|
+
"import": "./dist/react-native/index.js",
|
|
67
|
+
"require": "./dist/react-native/index.cjs"
|
|
68
|
+
},
|
|
69
|
+
"./package.json": "./package.json"
|
|
70
|
+
},
|
|
71
|
+
"publishConfig": {
|
|
72
|
+
"access": "public"
|
|
73
|
+
},
|
|
54
74
|
"scripts": {
|
|
55
75
|
"build": "rozenite build",
|
|
56
76
|
"dev": "rozenite dev",
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createNetworkActivityAgentState } from '../state';
|
|
3
|
+
import { NETWORK_ACTIVITY_AGENT_TOOLS } from '../tools';
|
|
4
|
+
import type { Request } from '../../../shared/client';
|
|
5
|
+
|
|
6
|
+
const createRequest = (overrides?: Partial<Request>): Request => ({
|
|
7
|
+
url: 'https://example.com/api',
|
|
8
|
+
method: 'POST',
|
|
9
|
+
headers: {
|
|
10
|
+
'content-type': 'application/json',
|
|
11
|
+
},
|
|
12
|
+
postData: {
|
|
13
|
+
type: 'text',
|
|
14
|
+
value: '{"hello":"world"}',
|
|
15
|
+
},
|
|
16
|
+
...overrides,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('network activity agent state', () => {
|
|
20
|
+
it('exposes the expected fallback and realtime tool names', () => {
|
|
21
|
+
expect(NETWORK_ACTIVITY_AGENT_TOOLS.map((tool) => tool.name)).toEqual([
|
|
22
|
+
'startRecording',
|
|
23
|
+
'stopRecording',
|
|
24
|
+
'getRecordingStatus',
|
|
25
|
+
'listRequests',
|
|
26
|
+
'getRequestDetails',
|
|
27
|
+
'getRequestBody',
|
|
28
|
+
'getResponseBody',
|
|
29
|
+
'listRealtimeConnections',
|
|
30
|
+
'getRealtimeConnectionDetails',
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('tracks HTTP requests with parity-oriented list/detail/body results', () => {
|
|
35
|
+
const state = createNetworkActivityAgentState();
|
|
36
|
+
state.startRecording();
|
|
37
|
+
|
|
38
|
+
state.onRequestSent({
|
|
39
|
+
requestId: 'req-1',
|
|
40
|
+
timestamp: 100,
|
|
41
|
+
request: createRequest(),
|
|
42
|
+
type: 'XHR',
|
|
43
|
+
initiator: { type: 'script', url: 'App.tsx', lineNumber: 12, columnNumber: 4 },
|
|
44
|
+
});
|
|
45
|
+
state.onResponseReceived({
|
|
46
|
+
requestId: 'req-1',
|
|
47
|
+
timestamp: 120,
|
|
48
|
+
type: 'XHR',
|
|
49
|
+
response: {
|
|
50
|
+
url: 'https://example.com/api',
|
|
51
|
+
status: 200,
|
|
52
|
+
statusText: 'OK',
|
|
53
|
+
headers: { 'content-type': 'application/json' },
|
|
54
|
+
contentType: 'application/json',
|
|
55
|
+
size: 17,
|
|
56
|
+
responseTime: 120,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
state.onRequestCompleted({
|
|
60
|
+
requestId: 'req-1',
|
|
61
|
+
timestamp: 130,
|
|
62
|
+
duration: 30,
|
|
63
|
+
size: 17,
|
|
64
|
+
ttfb: 20,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const list = state.listRequests({});
|
|
68
|
+
expect(list.items).toEqual([
|
|
69
|
+
{
|
|
70
|
+
requestId: 'req-1',
|
|
71
|
+
method: 'POST',
|
|
72
|
+
url: 'https://example.com/api',
|
|
73
|
+
status: 200,
|
|
74
|
+
type: 'XHR',
|
|
75
|
+
startTimeMs: 100,
|
|
76
|
+
endTimeMs: 130,
|
|
77
|
+
durationMs: 30,
|
|
78
|
+
transferSize: 17,
|
|
79
|
+
encodedDataLength: 17,
|
|
80
|
+
outcome: 'success',
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
const details = state.getRequestDetails('req-1');
|
|
85
|
+
expect(details.request).toMatchObject({
|
|
86
|
+
requestId: 'req-1',
|
|
87
|
+
method: 'POST',
|
|
88
|
+
url: 'https://example.com/api',
|
|
89
|
+
type: 'XHR',
|
|
90
|
+
loadingFinished: true,
|
|
91
|
+
loadingFailed: false,
|
|
92
|
+
ttfb: 20,
|
|
93
|
+
size: 17,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(state.getRequestBody('req-1')).toEqual({
|
|
97
|
+
requestId: 'req-1',
|
|
98
|
+
available: true,
|
|
99
|
+
body: '{"hello":"world"}',
|
|
100
|
+
base64Encoded: false,
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('returns unavailable request bodies when none were captured', () => {
|
|
105
|
+
const state = createNetworkActivityAgentState();
|
|
106
|
+
state.startRecording();
|
|
107
|
+
state.onRequestSent({
|
|
108
|
+
requestId: 'req-2',
|
|
109
|
+
timestamp: 10,
|
|
110
|
+
request: createRequest({ postData: undefined, method: 'GET' }),
|
|
111
|
+
type: 'Fetch',
|
|
112
|
+
initiator: { type: 'other' },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(state.getRequestBody('req-2')).toEqual({
|
|
116
|
+
requestId: 'req-2',
|
|
117
|
+
available: false,
|
|
118
|
+
reason: 'No request body is available for this request.',
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('supports realtime listing and details for websocket and sse traffic', () => {
|
|
123
|
+
const state = createNetworkActivityAgentState();
|
|
124
|
+
state.startRecording();
|
|
125
|
+
|
|
126
|
+
state.onWebSocketConnect({
|
|
127
|
+
type: 'websocket-connect',
|
|
128
|
+
url: 'wss://example.com/socket',
|
|
129
|
+
socketId: 7,
|
|
130
|
+
timestamp: 100,
|
|
131
|
+
protocols: ['chat'],
|
|
132
|
+
options: [],
|
|
133
|
+
});
|
|
134
|
+
state.onWebSocketOpen({
|
|
135
|
+
type: 'websocket-open',
|
|
136
|
+
url: 'wss://example.com/socket',
|
|
137
|
+
socketId: 7,
|
|
138
|
+
timestamp: 110,
|
|
139
|
+
});
|
|
140
|
+
state.onWebSocketMessageSent({
|
|
141
|
+
type: 'websocket-message-sent',
|
|
142
|
+
url: 'wss://example.com/socket',
|
|
143
|
+
socketId: 7,
|
|
144
|
+
timestamp: 120,
|
|
145
|
+
data: 'ping',
|
|
146
|
+
messageType: 'text',
|
|
147
|
+
});
|
|
148
|
+
state.onWebSocketMessageReceived({
|
|
149
|
+
type: 'websocket-message-received',
|
|
150
|
+
url: 'wss://example.com/socket',
|
|
151
|
+
socketId: 7,
|
|
152
|
+
timestamp: 121,
|
|
153
|
+
data: 'pong',
|
|
154
|
+
messageType: 'text',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
state.onRequestSent({
|
|
158
|
+
requestId: 'req-sse',
|
|
159
|
+
timestamp: 200,
|
|
160
|
+
request: createRequest({
|
|
161
|
+
method: 'GET',
|
|
162
|
+
url: 'https://example.com/stream',
|
|
163
|
+
postData: undefined,
|
|
164
|
+
}),
|
|
165
|
+
type: 'Fetch',
|
|
166
|
+
initiator: { type: 'script' },
|
|
167
|
+
});
|
|
168
|
+
state.onSSEOpen({
|
|
169
|
+
type: 'sse-open',
|
|
170
|
+
requestId: 'req-sse',
|
|
171
|
+
timestamp: 210,
|
|
172
|
+
response: {
|
|
173
|
+
url: 'https://example.com/stream',
|
|
174
|
+
status: 200,
|
|
175
|
+
statusText: 'OK',
|
|
176
|
+
headers: { 'content-type': 'text/event-stream' },
|
|
177
|
+
contentType: 'text/event-stream',
|
|
178
|
+
size: 0,
|
|
179
|
+
responseTime: 210,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
state.onSSEMessage({
|
|
183
|
+
type: 'sse-message',
|
|
184
|
+
requestId: 'req-sse',
|
|
185
|
+
timestamp: 220,
|
|
186
|
+
payload: {
|
|
187
|
+
type: 'message',
|
|
188
|
+
data: 'hello',
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const list = state.listRealtimeConnections({});
|
|
193
|
+
expect(list.items).toHaveLength(2);
|
|
194
|
+
expect(list.items[0]).toMatchObject({
|
|
195
|
+
requestId: 'req-sse',
|
|
196
|
+
kind: 'sse',
|
|
197
|
+
status: 'open',
|
|
198
|
+
messageCount: 1,
|
|
199
|
+
});
|
|
200
|
+
expect(list.items[1]).toMatchObject({
|
|
201
|
+
requestId: 'ws-7',
|
|
202
|
+
kind: 'websocket',
|
|
203
|
+
status: 'open',
|
|
204
|
+
messageCount: 2,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const websocketDetails = state.getRealtimeConnectionDetails('ws-7');
|
|
208
|
+
expect(websocketDetails.connection).toMatchObject({
|
|
209
|
+
requestId: 'ws-7',
|
|
210
|
+
kind: 'websocket',
|
|
211
|
+
url: 'wss://example.com/socket',
|
|
212
|
+
status: 'open',
|
|
213
|
+
});
|
|
214
|
+
expect(websocketDetails.connection.messages).toHaveLength(2);
|
|
215
|
+
|
|
216
|
+
const sseDetails = state.getRealtimeConnectionDetails('req-sse');
|
|
217
|
+
expect(sseDetails.connection).toMatchObject({
|
|
218
|
+
requestId: 'req-sse',
|
|
219
|
+
kind: 'sse',
|
|
220
|
+
status: 'open',
|
|
221
|
+
});
|
|
222
|
+
expect(sseDetails.connection.messages).toHaveLength(1);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('invalidates old cursors after a new recording starts', () => {
|
|
226
|
+
const state = createNetworkActivityAgentState();
|
|
227
|
+
state.startRecording();
|
|
228
|
+
state.onRequestSent({
|
|
229
|
+
requestId: 'req-1',
|
|
230
|
+
timestamp: 100,
|
|
231
|
+
request: createRequest(),
|
|
232
|
+
type: 'XHR',
|
|
233
|
+
initiator: { type: 'other' },
|
|
234
|
+
});
|
|
235
|
+
state.onRequestSent({
|
|
236
|
+
requestId: 'req-2',
|
|
237
|
+
timestamp: 101,
|
|
238
|
+
request: createRequest({ url: 'https://example.com/api/2' }),
|
|
239
|
+
type: 'XHR',
|
|
240
|
+
initiator: { type: 'other' },
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const firstPage = state.listRequests({ limit: 1 });
|
|
244
|
+
state.startRecording();
|
|
245
|
+
|
|
246
|
+
expect(() =>
|
|
247
|
+
state.listRequests({ limit: 1, cursor: firstPage.page.nextCursor })
|
|
248
|
+
).toThrow('Cursor does not match the requested listing. Run the command again.');
|
|
249
|
+
});
|
|
250
|
+
});
|