@rozenite/network-activity-plugin 1.0.0-alpha.7 → 1.0.0-alpha.9
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/dist/App.html +2 -2
- package/dist/assets/{App-CIflVb88.js → App-CA1Fbh0I.js} +12009 -10809
- package/dist/assets/{App-Czu6Vt2P.css → App-DoHQsY5s.css} +43 -0
- package/dist/event-source.cjs +22 -0
- package/dist/event-source.js +23 -0
- package/dist/rozenite.json +1 -1
- package/dist/src/react-native/{network-inspector.d.ts → http/network-inspector.d.ts} +1 -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/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 +8 -4
- package/dist/src/shared/sse-events.d.ts +35 -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 +1 -1
- package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +7 -0
- package/dist/src/ui/components/RequestList.d.ts +6 -26
- package/dist/src/ui/components/SidePanel.d.ts +1 -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 +17 -0
- package/dist/src/ui/state/model.d.ts +98 -0
- package/dist/src/ui/state/store.d.ts +24 -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 +6 -3
- package/dist/src/ui/utils/assert.d.ts +1 -0
- package/dist/src/ui/utils/copyToClipboard.d.ts +1 -0
- package/dist/src/ui/utils/getHttpHeaderValue.d.ts +2 -0
- package/dist/src/ui/utils/getId.d.ts +1 -0
- package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
- package/dist/useNetworkActivityDevTools.cjs +433 -34
- package/dist/useNetworkActivityDevTools.js +431 -34
- package/package.json +19 -8
- package/src/react-native/{network-inspector.ts → http/network-inspector.ts} +14 -32
- 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 +117 -0
- package/src/react-native/sse/sse-interceptor.ts +162 -0
- package/src/react-native/sse/types.ts +9 -0
- package/src/react-native/useNetworkActivityDevTools.ts +75 -1
- 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 +10 -4
- package/src/shared/sse-events.ts +44 -0
- package/src/shared/websocket-events.ts +79 -0
- package/src/ui/components/Badge.tsx +1 -1
- package/src/ui/components/Button.tsx +1 -1
- package/src/ui/components/Input.tsx +1 -1
- package/src/ui/components/JsonTree.tsx +13 -0
- package/src/ui/components/JsonTreeCopyableItem.tsx +33 -0
- package/src/ui/components/RequestList.tsx +42 -123
- package/src/ui/components/ScrollArea.tsx +1 -1
- package/src/ui/components/Separator.tsx +1 -1
- package/src/ui/components/SidePanel.tsx +323 -0
- package/src/ui/components/Tabs.tsx +2 -2
- package/src/ui/components/Toolbar.tsx +45 -0
- package/src/ui/hooks/useCopyToClipboard.ts +28 -0
- package/src/ui/state/derived.ts +112 -0
- package/src/ui/state/hooks.ts +44 -0
- package/src/ui/state/model.ts +129 -0
- package/src/ui/state/store.ts +559 -0
- package/src/ui/tabs/CookiesTab.tsx +168 -179
- package/src/ui/tabs/HeadersTab.tsx +24 -31
- package/src/ui/tabs/MessagesTab.tsx +276 -0
- package/src/ui/tabs/RequestTab.tsx +28 -31
- package/src/ui/tabs/ResponseTab.tsx +10 -12
- package/src/ui/tabs/SSEMessagesTab.tsx +213 -0
- package/src/ui/tabs/TimingTab.tsx +33 -44
- package/src/ui/types.ts +6 -2
- package/src/ui/utils/assert.ts +5 -0
- package/src/ui/utils/copyToClipboard.ts +3 -0
- package/src/ui/utils/getHttpHeaderValue.ts +14 -0
- package/src/ui/utils/getId.ts +10 -0
- package/src/ui/utils/getStatusColor.ts +15 -0
- package/src/ui/views/InspectorView.tsx +24 -320
- package/tailwind.config.ts +3 -0
- package/vite.config.ts +12 -0
- /package/dist/src/react-native/{network-requests-registry.d.ts → http/network-requests-registry.d.ts} +0 -0
- /package/dist/src/react-native/{xhr-interceptor.d.ts → http/xhr-interceptor.d.ts} +0 -0
- /package/dist/src/ui/{utils.d.ts → utils/cn.d.ts} +0 -0
- /package/src/react-native/{network-requests-registry.ts → http/network-requests-registry.ts} +0 -0
- /package/src/react-native/{xhr-interceptor.ts → http/xhr-interceptor.ts} +0 -0
- /package/src/ui/{utils.ts → utils/cn.ts} +0 -0
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import { useRozeniteDevToolsClient } from "@rozenite/plugin-bridge";
|
|
3
|
+
import { createNanoEvents } from "nanoevents";
|
|
4
|
+
import { Platform } from "react-native";
|
|
5
|
+
import WebSocketInterceptor from "react-native/Libraries/WebSocket/WebSocketInterceptor";
|
|
6
|
+
import { g as getEventSource } from "./event-source.js";
|
|
7
|
+
function getHttpHeaderValue(headers, name) {
|
|
8
|
+
const lowerName = name.toLowerCase();
|
|
9
|
+
for (const key in headers) {
|
|
10
|
+
if (key.toLowerCase() === lowerName) {
|
|
11
|
+
return headers[key];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const getContentType = (request) => {
|
|
17
|
+
const responseHeaders = request.responseHeaders;
|
|
18
|
+
const responseType = request.responseType;
|
|
19
|
+
const contentType = getHttpHeaderValue(responseHeaders || {}, "content-type");
|
|
20
|
+
if (contentType) {
|
|
21
|
+
return contentType.split(";")[0].trim();
|
|
22
|
+
}
|
|
23
|
+
switch (responseType) {
|
|
24
|
+
case "arraybuffer":
|
|
25
|
+
case "blob":
|
|
26
|
+
return "application/octet-stream";
|
|
27
|
+
case "text":
|
|
28
|
+
case "":
|
|
29
|
+
return "text/plain";
|
|
30
|
+
case "json":
|
|
31
|
+
return "application/json";
|
|
32
|
+
case "document":
|
|
33
|
+
return "text/html";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
3
36
|
const REQUEST_TTL = 1e3 * 60 * 5;
|
|
4
37
|
const getNetworkRequestsRegistry = () => {
|
|
5
38
|
const registry = /* @__PURE__ */ new Map();
|
|
@@ -41,7 +74,7 @@ let sendCallback;
|
|
|
41
74
|
let requestHeaderCallback;
|
|
42
75
|
let headerReceivedCallback;
|
|
43
76
|
let responseCallback;
|
|
44
|
-
let isInterceptorEnabled = false;
|
|
77
|
+
let isInterceptorEnabled$1 = false;
|
|
45
78
|
const XHRInterceptor = {
|
|
46
79
|
/**
|
|
47
80
|
* Invoked before XMLHttpRequest.open(...) is called.
|
|
@@ -74,10 +107,10 @@ const XHRInterceptor = {
|
|
|
74
107
|
requestHeaderCallback = callback;
|
|
75
108
|
},
|
|
76
109
|
isInterceptorEnabled() {
|
|
77
|
-
return isInterceptorEnabled;
|
|
110
|
+
return isInterceptorEnabled$1;
|
|
78
111
|
},
|
|
79
112
|
enableInterception() {
|
|
80
|
-
if (isInterceptorEnabled) {
|
|
113
|
+
if (isInterceptorEnabled$1) {
|
|
81
114
|
return;
|
|
82
115
|
}
|
|
83
116
|
XMLHttpRequest.prototype.open = function(method, url) {
|
|
@@ -100,7 +133,7 @@ const XHRInterceptor = {
|
|
|
100
133
|
this.addEventListener(
|
|
101
134
|
"readystatechange",
|
|
102
135
|
() => {
|
|
103
|
-
if (!isInterceptorEnabled) {
|
|
136
|
+
if (!isInterceptorEnabled$1) {
|
|
104
137
|
return;
|
|
105
138
|
}
|
|
106
139
|
if (this.readyState === this.HEADERS_RECEIVED) {
|
|
@@ -140,14 +173,14 @@ const XHRInterceptor = {
|
|
|
140
173
|
}
|
|
141
174
|
originalXHRSend.apply(this, arguments);
|
|
142
175
|
};
|
|
143
|
-
isInterceptorEnabled = true;
|
|
176
|
+
isInterceptorEnabled$1 = true;
|
|
144
177
|
},
|
|
145
178
|
// Unpatch XMLHttpRequest methods and remove the callbacks.
|
|
146
179
|
disableInterception() {
|
|
147
|
-
if (!isInterceptorEnabled) {
|
|
180
|
+
if (!isInterceptorEnabled$1) {
|
|
148
181
|
return;
|
|
149
182
|
}
|
|
150
|
-
isInterceptorEnabled = false;
|
|
183
|
+
isInterceptorEnabled$1 = false;
|
|
151
184
|
XMLHttpRequest.prototype.send = originalXHRSend;
|
|
152
185
|
XMLHttpRequest.prototype.open = originalXHROpen;
|
|
153
186
|
XMLHttpRequest.prototype.setRequestHeader = originalXHRSetRequestHeader;
|
|
@@ -159,25 +192,6 @@ const XHRInterceptor = {
|
|
|
159
192
|
}
|
|
160
193
|
};
|
|
161
194
|
const networkRequestsRegistry = getNetworkRequestsRegistry();
|
|
162
|
-
const getContentType = (request) => {
|
|
163
|
-
const responseHeaders = request.responseHeaders;
|
|
164
|
-
const responseType = request.responseType;
|
|
165
|
-
if (responseHeaders == null ? void 0 : responseHeaders["content-type"]) {
|
|
166
|
-
return responseHeaders["content-type"].split(";")[0].trim();
|
|
167
|
-
}
|
|
168
|
-
switch (responseType) {
|
|
169
|
-
case "arraybuffer":
|
|
170
|
-
case "blob":
|
|
171
|
-
return "application/octet-stream";
|
|
172
|
-
case "text":
|
|
173
|
-
case "":
|
|
174
|
-
return "text/plain";
|
|
175
|
-
case "json":
|
|
176
|
-
return "application/json";
|
|
177
|
-
case "document":
|
|
178
|
-
return "text/html";
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
195
|
const getResponseSize = (request) => {
|
|
182
196
|
if (typeof request.response === "object") {
|
|
183
197
|
return request.response.size;
|
|
@@ -186,7 +200,7 @@ const getResponseSize = (request) => {
|
|
|
186
200
|
};
|
|
187
201
|
const getResponseBody = async (request) => {
|
|
188
202
|
const responseType = request.responseType;
|
|
189
|
-
if (responseType === "text") {
|
|
203
|
+
if (responseType === "" || responseType === "text") {
|
|
190
204
|
return request.responseText;
|
|
191
205
|
}
|
|
192
206
|
if (responseType === "blob") {
|
|
@@ -231,12 +245,13 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
231
245
|
const handleRequestSend = (data, request) => {
|
|
232
246
|
const sendTime = Date.now();
|
|
233
247
|
const requestId = generateRequestId();
|
|
248
|
+
request._rozeniteRequestId = requestId;
|
|
234
249
|
const initiator = getInitiatorFromStack();
|
|
235
250
|
networkRequestsRegistry.addEntry(requestId, request);
|
|
236
251
|
let ttfb = 0;
|
|
237
252
|
pluginClient.send("request-sent", {
|
|
238
253
|
requestId,
|
|
239
|
-
timestamp: sendTime
|
|
254
|
+
timestamp: sendTime,
|
|
240
255
|
request: {
|
|
241
256
|
url: request._url,
|
|
242
257
|
method: request._method,
|
|
@@ -254,23 +269,23 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
254
269
|
request.addEventListener("load", () => {
|
|
255
270
|
pluginClient.send("response-received", {
|
|
256
271
|
requestId,
|
|
257
|
-
timestamp: Date.now()
|
|
272
|
+
timestamp: Date.now(),
|
|
258
273
|
type: "XHR",
|
|
259
274
|
response: {
|
|
260
275
|
url: request._url,
|
|
261
276
|
status: request.status,
|
|
262
277
|
statusText: request.statusText,
|
|
263
|
-
headers: request.responseHeaders,
|
|
278
|
+
headers: request.responseHeaders || {},
|
|
264
279
|
contentType: getContentType(request),
|
|
265
280
|
size: getResponseSize(request),
|
|
266
|
-
responseTime: Date.now()
|
|
281
|
+
responseTime: Date.now()
|
|
267
282
|
}
|
|
268
283
|
});
|
|
269
284
|
});
|
|
270
285
|
request.addEventListener("loadend", () => {
|
|
271
286
|
pluginClient.send("request-completed", {
|
|
272
287
|
requestId,
|
|
273
|
-
timestamp: Date.now()
|
|
288
|
+
timestamp: Date.now(),
|
|
274
289
|
duration: Date.now() - sendTime,
|
|
275
290
|
size: getResponseSize(request),
|
|
276
291
|
ttfb
|
|
@@ -279,7 +294,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
279
294
|
request.addEventListener("error", () => {
|
|
280
295
|
pluginClient.send("request-failed", {
|
|
281
296
|
requestId,
|
|
282
|
-
timestamp: Date.now()
|
|
297
|
+
timestamp: Date.now(),
|
|
283
298
|
type: "XHR",
|
|
284
299
|
error: "Failed",
|
|
285
300
|
canceled: false
|
|
@@ -288,7 +303,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
288
303
|
request.addEventListener("abort", () => {
|
|
289
304
|
pluginClient.send("request-failed", {
|
|
290
305
|
requestId,
|
|
291
|
-
timestamp: Date.now()
|
|
306
|
+
timestamp: Date.now(),
|
|
292
307
|
type: "XHR",
|
|
293
308
|
error: "Aborted",
|
|
294
309
|
canceled: true
|
|
@@ -340,6 +355,333 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
340
355
|
dispose
|
|
341
356
|
};
|
|
342
357
|
};
|
|
358
|
+
const getWebSocketInterceptor = () => {
|
|
359
|
+
if (Platform.constants.reactNativeVersion.minor >= 79) {
|
|
360
|
+
return WebSocketInterceptor;
|
|
361
|
+
} else {
|
|
362
|
+
const WebSocketInterceptorPreRN079 = WebSocketInterceptor;
|
|
363
|
+
return {
|
|
364
|
+
...WebSocketInterceptorPreRN079,
|
|
365
|
+
setOnMessageCallback: (callback) => {
|
|
366
|
+
WebSocketInterceptorPreRN079.setOnMessageCallback((socketId, data) => {
|
|
367
|
+
callback(data, socketId);
|
|
368
|
+
});
|
|
369
|
+
},
|
|
370
|
+
setOnCloseCallback: (callback) => {
|
|
371
|
+
WebSocketInterceptorPreRN079.setOnCloseCallback((error, socketId) => {
|
|
372
|
+
callback(socketId, error);
|
|
373
|
+
});
|
|
374
|
+
},
|
|
375
|
+
setOnErrorCallback: (callback) => {
|
|
376
|
+
WebSocketInterceptorPreRN079.setOnErrorCallback((error, socketId) => {
|
|
377
|
+
callback(socketId, error);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const getWebSocketInspector = () => {
|
|
384
|
+
const eventEmitter = createNanoEvents();
|
|
385
|
+
const socketUrlMap = /* @__PURE__ */ new Map();
|
|
386
|
+
const webSocketInterceptor = getWebSocketInterceptor();
|
|
387
|
+
return {
|
|
388
|
+
enable: () => {
|
|
389
|
+
webSocketInterceptor.setConnectCallback(
|
|
390
|
+
(url, protocols, options, socketId) => {
|
|
391
|
+
socketUrlMap.set(socketId, url);
|
|
392
|
+
const event = {
|
|
393
|
+
type: "websocket-connect",
|
|
394
|
+
url,
|
|
395
|
+
socketId,
|
|
396
|
+
timestamp: Date.now(),
|
|
397
|
+
protocols,
|
|
398
|
+
options
|
|
399
|
+
};
|
|
400
|
+
eventEmitter.emit("websocket-connect", event);
|
|
401
|
+
}
|
|
402
|
+
);
|
|
403
|
+
webSocketInterceptor.setCloseCallback(
|
|
404
|
+
(code, reason, socketId) => {
|
|
405
|
+
const url = socketUrlMap.get(socketId);
|
|
406
|
+
if (!url) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const event = {
|
|
410
|
+
type: "websocket-close",
|
|
411
|
+
url,
|
|
412
|
+
socketId,
|
|
413
|
+
timestamp: Date.now(),
|
|
414
|
+
code: code || 0,
|
|
415
|
+
reason: reason || void 0
|
|
416
|
+
};
|
|
417
|
+
eventEmitter.emit("websocket-close", event);
|
|
418
|
+
socketUrlMap.delete(socketId);
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
webSocketInterceptor.setOnMessageCallback(
|
|
422
|
+
(data, socketId) => {
|
|
423
|
+
const url = socketUrlMap.get(socketId);
|
|
424
|
+
if (!url) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const event = {
|
|
428
|
+
type: "websocket-message-received",
|
|
429
|
+
url,
|
|
430
|
+
socketId,
|
|
431
|
+
timestamp: Date.now(),
|
|
432
|
+
data,
|
|
433
|
+
messageType: typeof data === "string" ? "text" : "binary"
|
|
434
|
+
};
|
|
435
|
+
eventEmitter.emit("websocket-message-received", event);
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
webSocketInterceptor.setOnErrorCallback(
|
|
439
|
+
(error, socketId) => {
|
|
440
|
+
const url = socketUrlMap.get(socketId);
|
|
441
|
+
if (!url) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const event = {
|
|
445
|
+
type: "websocket-error",
|
|
446
|
+
url,
|
|
447
|
+
socketId,
|
|
448
|
+
timestamp: Date.now(),
|
|
449
|
+
error
|
|
450
|
+
};
|
|
451
|
+
eventEmitter.emit("websocket-error", event);
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
webSocketInterceptor.setSendCallback((data, socketId) => {
|
|
455
|
+
const url = socketUrlMap.get(socketId);
|
|
456
|
+
if (!url) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const event = {
|
|
460
|
+
type: "websocket-message-sent",
|
|
461
|
+
url,
|
|
462
|
+
socketId,
|
|
463
|
+
timestamp: Date.now(),
|
|
464
|
+
data,
|
|
465
|
+
messageType: typeof data === "string" ? "text" : "binary"
|
|
466
|
+
};
|
|
467
|
+
eventEmitter.emit("websocket-message-sent", event);
|
|
468
|
+
});
|
|
469
|
+
webSocketInterceptor.setOnOpenCallback((socketId) => {
|
|
470
|
+
const url = socketUrlMap.get(socketId);
|
|
471
|
+
if (!url) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const event = {
|
|
475
|
+
type: "websocket-open",
|
|
476
|
+
url,
|
|
477
|
+
socketId,
|
|
478
|
+
timestamp: Date.now()
|
|
479
|
+
};
|
|
480
|
+
eventEmitter.emit("websocket-open", event);
|
|
481
|
+
});
|
|
482
|
+
webSocketInterceptor.setOnCloseCallback(
|
|
483
|
+
(error, socketId) => {
|
|
484
|
+
const url = socketUrlMap.get(socketId);
|
|
485
|
+
if (!url) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const event = {
|
|
489
|
+
type: "websocket-close",
|
|
490
|
+
url,
|
|
491
|
+
socketId,
|
|
492
|
+
timestamp: Date.now(),
|
|
493
|
+
code: error.code,
|
|
494
|
+
reason: error.reason
|
|
495
|
+
};
|
|
496
|
+
eventEmitter.emit("websocket-close", event);
|
|
497
|
+
socketUrlMap.delete(socketId);
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
webSocketInterceptor.enableInterception();
|
|
501
|
+
},
|
|
502
|
+
disable: () => {
|
|
503
|
+
webSocketInterceptor.disableInterception();
|
|
504
|
+
},
|
|
505
|
+
isEnabled: () => webSocketInterceptor.isInterceptorEnabled(),
|
|
506
|
+
dispose: () => {
|
|
507
|
+
eventEmitter.events = {};
|
|
508
|
+
socketUrlMap.clear();
|
|
509
|
+
},
|
|
510
|
+
on: (event, callback) => eventEmitter.on(event, callback)
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
let connectCallback;
|
|
514
|
+
let messageCallback;
|
|
515
|
+
let errorCallback;
|
|
516
|
+
let openEventCallback;
|
|
517
|
+
let closeCallback;
|
|
518
|
+
let isInterceptorEnabled = false;
|
|
519
|
+
const eventSourceClass = getEventSource();
|
|
520
|
+
const originalOpen = eventSourceClass.prototype.open;
|
|
521
|
+
const SSEInterceptor = {
|
|
522
|
+
/**
|
|
523
|
+
* Invoked when EventSource.open() is called (connection attempt starting).
|
|
524
|
+
*/
|
|
525
|
+
setConnectCallback(callback) {
|
|
526
|
+
connectCallback = callback;
|
|
527
|
+
},
|
|
528
|
+
/**
|
|
529
|
+
* Invoked when a message event is received.
|
|
530
|
+
*/
|
|
531
|
+
setMessageCallback(callback) {
|
|
532
|
+
messageCallback = callback;
|
|
533
|
+
},
|
|
534
|
+
/**
|
|
535
|
+
* Invoked when an error event occurs.
|
|
536
|
+
*/
|
|
537
|
+
setErrorCallback(callback) {
|
|
538
|
+
errorCallback = callback;
|
|
539
|
+
},
|
|
540
|
+
/**
|
|
541
|
+
* Invoked when the connection is successfully opened (open event fired).
|
|
542
|
+
*/
|
|
543
|
+
setOpenEventCallback(callback) {
|
|
544
|
+
openEventCallback = callback;
|
|
545
|
+
},
|
|
546
|
+
/**
|
|
547
|
+
* Invoked when the connection is closed.
|
|
548
|
+
*/
|
|
549
|
+
setCloseCallback(callback) {
|
|
550
|
+
closeCallback = callback;
|
|
551
|
+
},
|
|
552
|
+
isInterceptorEnabled() {
|
|
553
|
+
return isInterceptorEnabled;
|
|
554
|
+
},
|
|
555
|
+
enableInterception() {
|
|
556
|
+
if (isInterceptorEnabled) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
eventSourceClass.prototype.open = function() {
|
|
560
|
+
if (connectCallback) {
|
|
561
|
+
connectCallback(this.url, this);
|
|
562
|
+
}
|
|
563
|
+
this.addEventListener("open", (event) => {
|
|
564
|
+
if (openEventCallback) {
|
|
565
|
+
openEventCallback(event, this);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
this.addEventListener("message", (event) => {
|
|
569
|
+
if (messageCallback) {
|
|
570
|
+
messageCallback(event, this);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
this.addEventListener(
|
|
574
|
+
"error",
|
|
575
|
+
(event) => {
|
|
576
|
+
if (errorCallback) {
|
|
577
|
+
errorCallback(event, this);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
);
|
|
581
|
+
this.addEventListener("close", (event) => {
|
|
582
|
+
if (closeCallback) {
|
|
583
|
+
closeCallback(event, this);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
return originalOpen.call(this);
|
|
587
|
+
};
|
|
588
|
+
isInterceptorEnabled = true;
|
|
589
|
+
},
|
|
590
|
+
// Unpatch EventSource open method and remove the callbacks.
|
|
591
|
+
disableInterception() {
|
|
592
|
+
if (!isInterceptorEnabled) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
isInterceptorEnabled = false;
|
|
596
|
+
eventSourceClass.prototype.open = originalOpen;
|
|
597
|
+
connectCallback = null;
|
|
598
|
+
messageCallback = null;
|
|
599
|
+
errorCallback = null;
|
|
600
|
+
openEventCallback = null;
|
|
601
|
+
closeCallback = null;
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
const getSSEInspector = () => {
|
|
605
|
+
const eventEmitter = createNanoEvents();
|
|
606
|
+
const getRequestId = (eventSource) => {
|
|
607
|
+
var _a;
|
|
608
|
+
const requestId = (_a = eventSource._xhr) == null ? void 0 : _a._rozeniteRequestId;
|
|
609
|
+
if (!requestId) {
|
|
610
|
+
throw new Error(
|
|
611
|
+
"No request ID found for EventSource. This should never happen!"
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
return requestId;
|
|
615
|
+
};
|
|
616
|
+
return {
|
|
617
|
+
enable: () => {
|
|
618
|
+
SSEInterceptor.setOpenEventCallback((_, eventSource) => {
|
|
619
|
+
const sseEventSource = eventSource;
|
|
620
|
+
const requestId = getRequestId(sseEventSource);
|
|
621
|
+
const sseXhr = sseEventSource._xhr;
|
|
622
|
+
const event = {
|
|
623
|
+
type: "sse-open",
|
|
624
|
+
requestId,
|
|
625
|
+
timestamp: Date.now(),
|
|
626
|
+
response: {
|
|
627
|
+
url: sseXhr._url,
|
|
628
|
+
status: sseXhr.status,
|
|
629
|
+
statusText: sseXhr.statusText,
|
|
630
|
+
headers: sseXhr.responseHeaders || {},
|
|
631
|
+
contentType: getContentType(sseXhr),
|
|
632
|
+
size: 0,
|
|
633
|
+
responseTime: Date.now()
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
eventEmitter.emit("sse-open", event);
|
|
637
|
+
});
|
|
638
|
+
SSEInterceptor.setMessageCallback((messageEvent, eventSource) => {
|
|
639
|
+
const sseEventSource = eventSource;
|
|
640
|
+
const requestId = getRequestId(sseEventSource);
|
|
641
|
+
const event = {
|
|
642
|
+
type: "sse-message",
|
|
643
|
+
requestId,
|
|
644
|
+
timestamp: Date.now(),
|
|
645
|
+
data: messageEvent.data || ""
|
|
646
|
+
};
|
|
647
|
+
eventEmitter.emit("sse-message", event);
|
|
648
|
+
});
|
|
649
|
+
SSEInterceptor.setErrorCallback((errorEvent, eventSource) => {
|
|
650
|
+
const sseEventSource = eventSource;
|
|
651
|
+
const requestId = getRequestId(sseEventSource);
|
|
652
|
+
const event = {
|
|
653
|
+
type: "sse-error",
|
|
654
|
+
requestId,
|
|
655
|
+
timestamp: Date.now(),
|
|
656
|
+
error: {
|
|
657
|
+
type: errorEvent.type,
|
|
658
|
+
message: errorEvent.type === "timeout" ? "Timeout" : errorEvent.message
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
eventEmitter.emit("sse-error", event);
|
|
662
|
+
});
|
|
663
|
+
SSEInterceptor.setCloseCallback((_, eventSource) => {
|
|
664
|
+
const sseEventSource = eventSource;
|
|
665
|
+
const requestId = getRequestId(sseEventSource);
|
|
666
|
+
const event = {
|
|
667
|
+
type: "sse-close",
|
|
668
|
+
requestId,
|
|
669
|
+
timestamp: Date.now()
|
|
670
|
+
};
|
|
671
|
+
eventEmitter.emit("sse-close", event);
|
|
672
|
+
});
|
|
673
|
+
SSEInterceptor.enableInterception();
|
|
674
|
+
},
|
|
675
|
+
disable: () => {
|
|
676
|
+
SSEInterceptor.disableInterception();
|
|
677
|
+
},
|
|
678
|
+
isEnabled: () => SSEInterceptor.isInterceptorEnabled(),
|
|
679
|
+
dispose: () => {
|
|
680
|
+
eventEmitter.events = {};
|
|
681
|
+
},
|
|
682
|
+
on: (event, callback) => eventEmitter.on(event, callback)
|
|
683
|
+
};
|
|
684
|
+
};
|
|
343
685
|
const useNetworkActivityDevTools = () => {
|
|
344
686
|
const client = useRozeniteDevToolsClient({
|
|
345
687
|
pluginId: "@rozenite/network-activity-plugin"
|
|
@@ -353,6 +695,61 @@ const useNetworkActivityDevTools = () => {
|
|
|
353
695
|
networkInspector.dispose();
|
|
354
696
|
};
|
|
355
697
|
}, [client]);
|
|
698
|
+
useEffect(() => {
|
|
699
|
+
if (!client) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
const eventsToForward = [
|
|
703
|
+
"websocket-connect",
|
|
704
|
+
"websocket-open",
|
|
705
|
+
"websocket-close",
|
|
706
|
+
"websocket-message-sent",
|
|
707
|
+
"websocket-message-received",
|
|
708
|
+
"websocket-error",
|
|
709
|
+
"websocket-connection-status-changed"
|
|
710
|
+
];
|
|
711
|
+
const websocketInspector = getWebSocketInspector();
|
|
712
|
+
eventsToForward.forEach((event) => {
|
|
713
|
+
websocketInspector.on(event, (event2) => {
|
|
714
|
+
client.send(event2.type, event2);
|
|
715
|
+
});
|
|
716
|
+
});
|
|
717
|
+
client.onMessage("network-enable", () => {
|
|
718
|
+
websocketInspector.enable();
|
|
719
|
+
});
|
|
720
|
+
client.onMessage("network-disable", () => {
|
|
721
|
+
websocketInspector.disable();
|
|
722
|
+
});
|
|
723
|
+
return () => {
|
|
724
|
+
websocketInspector.dispose();
|
|
725
|
+
};
|
|
726
|
+
}, [client]);
|
|
727
|
+
useEffect(() => {
|
|
728
|
+
if (!client) {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const eventsToForward = [
|
|
732
|
+
"sse-open",
|
|
733
|
+
"sse-message",
|
|
734
|
+
"sse-error",
|
|
735
|
+
"sse-close"
|
|
736
|
+
];
|
|
737
|
+
const sseInspector = getSSEInspector();
|
|
738
|
+
eventsToForward.forEach((event) => {
|
|
739
|
+
sseInspector.on(event, (event2) => {
|
|
740
|
+
client.send(event2.type, event2);
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
client.onMessage("network-enable", () => {
|
|
744
|
+
sseInspector.enable();
|
|
745
|
+
});
|
|
746
|
+
client.onMessage("network-disable", () => {
|
|
747
|
+
sseInspector.disable();
|
|
748
|
+
});
|
|
749
|
+
return () => {
|
|
750
|
+
sseInspector.dispose();
|
|
751
|
+
};
|
|
752
|
+
}, [client]);
|
|
356
753
|
return client;
|
|
357
754
|
};
|
|
358
755
|
export {
|
package/package.json
CHANGED
|
@@ -1,37 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rozenite/network-activity-plugin",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.9",
|
|
4
4
|
"description": "Network Activity for Rozenite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/react-native.cjs",
|
|
7
7
|
"module": "./dist/react-native.js",
|
|
8
8
|
"types": "./dist/react-native.d.ts",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"
|
|
10
|
+
"nanoevents": "^9.1.0",
|
|
11
|
+
"@rozenite/plugin-bridge": "1.0.0-alpha.9"
|
|
11
12
|
},
|
|
12
13
|
"devDependencies": {
|
|
14
|
+
"@floating-ui/react": "^0.26.0",
|
|
13
15
|
"@radix-ui/react-scroll-area": "^1.2.9",
|
|
14
16
|
"@radix-ui/react-separator": "^1.1.7",
|
|
15
17
|
"@radix-ui/react-slot": "^1.2.3",
|
|
16
18
|
"@radix-ui/react-tabs": "^1.1.12",
|
|
17
19
|
"@tanstack/react-table": "^8.21.3",
|
|
20
|
+
"@tanstack/react-virtual": "^3.0.0",
|
|
18
21
|
"autoprefixer": "^10.4.21",
|
|
19
22
|
"class-variance-authority": "^0.7.1",
|
|
20
23
|
"clsx": "^2.1.1",
|
|
24
|
+
"lucide-react": "^0.263.1",
|
|
21
25
|
"postcss": "^8.5.6",
|
|
26
|
+
"proxy-memoize": "^3.0.1",
|
|
22
27
|
"react": "*",
|
|
23
28
|
"react-json-tree": "^0.20.0",
|
|
24
|
-
"react-native": "
|
|
29
|
+
"react-native-sse": "^1.2.1",
|
|
25
30
|
"tailwind-merge": "^3.3.1",
|
|
26
31
|
"tailwindcss": "^3.4.17",
|
|
27
32
|
"tailwindcss-animate": "^1.0.7",
|
|
28
33
|
"typescript": "^5.7.3",
|
|
29
34
|
"vite": "^6.0.0",
|
|
30
|
-
"
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
"zustand": "^5.0.6",
|
|
36
|
+
"@rozenite/vite-plugin": "1.0.0-alpha.9",
|
|
37
|
+
"rozenite": "1.0.0-alpha.9"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react-native-sse": "*"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"react-native-sse": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
35
46
|
},
|
|
36
47
|
"license": "MIT",
|
|
37
48
|
"scripts": {
|