@rozenite/network-activity-plugin 1.0.0-alpha.8 → 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-lNMijPJ4.js → App-CA1Fbh0I.js} +11995 -10804
- package/dist/assets/{App-R2ZMH9wJ.css → App-DoHQsY5s.css} +46 -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 +5 -2
- 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 +4 -1
- 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/getId.d.ts +1 -0
- package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
- package/dist/useNetworkActivityDevTools.cjs +423 -34
- package/dist/useNetworkActivityDevTools.js +421 -34
- package/package.json +19 -8
- package/src/react-native/{network-inspector.ts → http/network-inspector.ts} +13 -34
- 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 +6 -2
- package/src/shared/sse-events.ts +44 -0
- package/src/shared/websocket-events.ts +79 -0
- package/src/ui/components/JsonTree.tsx +13 -0
- package/src/ui/components/JsonTreeCopyableItem.tsx +33 -0
- package/src/ui/components/RequestList.tsx +42 -124
- package/src/ui/components/SidePanel.tsx +323 -0
- package/src/ui/components/Tabs.tsx +1 -1
- 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 +162 -176
- package/src/ui/tabs/HeadersTab.tsx +23 -30
- package/src/ui/tabs/MessagesTab.tsx +276 -0
- package/src/ui/tabs/RequestTab.tsx +8 -13
- package/src/ui/tabs/ResponseTab.tsx +6 -10
- package/src/ui/tabs/SSEMessagesTab.tsx +213 -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/copyToClipboard.ts +3 -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/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
|
@@ -1,5 +1,9 @@
|
|
|
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";
|
|
3
7
|
function getHttpHeaderValue(headers, name) {
|
|
4
8
|
const lowerName = name.toLowerCase();
|
|
5
9
|
for (const key in headers) {
|
|
@@ -9,6 +13,26 @@ function getHttpHeaderValue(headers, name) {
|
|
|
9
13
|
}
|
|
10
14
|
return void 0;
|
|
11
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
|
+
};
|
|
12
36
|
const REQUEST_TTL = 1e3 * 60 * 5;
|
|
13
37
|
const getNetworkRequestsRegistry = () => {
|
|
14
38
|
const registry = /* @__PURE__ */ new Map();
|
|
@@ -50,7 +74,7 @@ let sendCallback;
|
|
|
50
74
|
let requestHeaderCallback;
|
|
51
75
|
let headerReceivedCallback;
|
|
52
76
|
let responseCallback;
|
|
53
|
-
let isInterceptorEnabled = false;
|
|
77
|
+
let isInterceptorEnabled$1 = false;
|
|
54
78
|
const XHRInterceptor = {
|
|
55
79
|
/**
|
|
56
80
|
* Invoked before XMLHttpRequest.open(...) is called.
|
|
@@ -83,10 +107,10 @@ const XHRInterceptor = {
|
|
|
83
107
|
requestHeaderCallback = callback;
|
|
84
108
|
},
|
|
85
109
|
isInterceptorEnabled() {
|
|
86
|
-
return isInterceptorEnabled;
|
|
110
|
+
return isInterceptorEnabled$1;
|
|
87
111
|
},
|
|
88
112
|
enableInterception() {
|
|
89
|
-
if (isInterceptorEnabled) {
|
|
113
|
+
if (isInterceptorEnabled$1) {
|
|
90
114
|
return;
|
|
91
115
|
}
|
|
92
116
|
XMLHttpRequest.prototype.open = function(method, url) {
|
|
@@ -109,7 +133,7 @@ const XHRInterceptor = {
|
|
|
109
133
|
this.addEventListener(
|
|
110
134
|
"readystatechange",
|
|
111
135
|
() => {
|
|
112
|
-
if (!isInterceptorEnabled) {
|
|
136
|
+
if (!isInterceptorEnabled$1) {
|
|
113
137
|
return;
|
|
114
138
|
}
|
|
115
139
|
if (this.readyState === this.HEADERS_RECEIVED) {
|
|
@@ -149,14 +173,14 @@ const XHRInterceptor = {
|
|
|
149
173
|
}
|
|
150
174
|
originalXHRSend.apply(this, arguments);
|
|
151
175
|
};
|
|
152
|
-
isInterceptorEnabled = true;
|
|
176
|
+
isInterceptorEnabled$1 = true;
|
|
153
177
|
},
|
|
154
178
|
// Unpatch XMLHttpRequest methods and remove the callbacks.
|
|
155
179
|
disableInterception() {
|
|
156
|
-
if (!isInterceptorEnabled) {
|
|
180
|
+
if (!isInterceptorEnabled$1) {
|
|
157
181
|
return;
|
|
158
182
|
}
|
|
159
|
-
isInterceptorEnabled = false;
|
|
183
|
+
isInterceptorEnabled$1 = false;
|
|
160
184
|
XMLHttpRequest.prototype.send = originalXHRSend;
|
|
161
185
|
XMLHttpRequest.prototype.open = originalXHROpen;
|
|
162
186
|
XMLHttpRequest.prototype.setRequestHeader = originalXHRSetRequestHeader;
|
|
@@ -168,26 +192,6 @@ const XHRInterceptor = {
|
|
|
168
192
|
}
|
|
169
193
|
};
|
|
170
194
|
const networkRequestsRegistry = getNetworkRequestsRegistry();
|
|
171
|
-
const getContentType = (request) => {
|
|
172
|
-
const responseHeaders = request.responseHeaders;
|
|
173
|
-
const responseType = request.responseType;
|
|
174
|
-
const contentType = getHttpHeaderValue(responseHeaders || {}, "content-type");
|
|
175
|
-
if (contentType) {
|
|
176
|
-
return contentType.split(";")[0].trim();
|
|
177
|
-
}
|
|
178
|
-
switch (responseType) {
|
|
179
|
-
case "arraybuffer":
|
|
180
|
-
case "blob":
|
|
181
|
-
return "application/octet-stream";
|
|
182
|
-
case "text":
|
|
183
|
-
case "":
|
|
184
|
-
return "text/plain";
|
|
185
|
-
case "json":
|
|
186
|
-
return "application/json";
|
|
187
|
-
case "document":
|
|
188
|
-
return "text/html";
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
195
|
const getResponseSize = (request) => {
|
|
192
196
|
if (typeof request.response === "object") {
|
|
193
197
|
return request.response.size;
|
|
@@ -196,7 +200,7 @@ const getResponseSize = (request) => {
|
|
|
196
200
|
};
|
|
197
201
|
const getResponseBody = async (request) => {
|
|
198
202
|
const responseType = request.responseType;
|
|
199
|
-
if (responseType === "text") {
|
|
203
|
+
if (responseType === "" || responseType === "text") {
|
|
200
204
|
return request.responseText;
|
|
201
205
|
}
|
|
202
206
|
if (responseType === "blob") {
|
|
@@ -241,12 +245,13 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
241
245
|
const handleRequestSend = (data, request) => {
|
|
242
246
|
const sendTime = Date.now();
|
|
243
247
|
const requestId = generateRequestId();
|
|
248
|
+
request._rozeniteRequestId = requestId;
|
|
244
249
|
const initiator = getInitiatorFromStack();
|
|
245
250
|
networkRequestsRegistry.addEntry(requestId, request);
|
|
246
251
|
let ttfb = 0;
|
|
247
252
|
pluginClient.send("request-sent", {
|
|
248
253
|
requestId,
|
|
249
|
-
timestamp: sendTime
|
|
254
|
+
timestamp: sendTime,
|
|
250
255
|
request: {
|
|
251
256
|
url: request._url,
|
|
252
257
|
method: request._method,
|
|
@@ -264,7 +269,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
264
269
|
request.addEventListener("load", () => {
|
|
265
270
|
pluginClient.send("response-received", {
|
|
266
271
|
requestId,
|
|
267
|
-
timestamp: Date.now()
|
|
272
|
+
timestamp: Date.now(),
|
|
268
273
|
type: "XHR",
|
|
269
274
|
response: {
|
|
270
275
|
url: request._url,
|
|
@@ -273,14 +278,14 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
273
278
|
headers: request.responseHeaders || {},
|
|
274
279
|
contentType: getContentType(request),
|
|
275
280
|
size: getResponseSize(request),
|
|
276
|
-
responseTime: Date.now()
|
|
281
|
+
responseTime: Date.now()
|
|
277
282
|
}
|
|
278
283
|
});
|
|
279
284
|
});
|
|
280
285
|
request.addEventListener("loadend", () => {
|
|
281
286
|
pluginClient.send("request-completed", {
|
|
282
287
|
requestId,
|
|
283
|
-
timestamp: Date.now()
|
|
288
|
+
timestamp: Date.now(),
|
|
284
289
|
duration: Date.now() - sendTime,
|
|
285
290
|
size: getResponseSize(request),
|
|
286
291
|
ttfb
|
|
@@ -289,7 +294,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
289
294
|
request.addEventListener("error", () => {
|
|
290
295
|
pluginClient.send("request-failed", {
|
|
291
296
|
requestId,
|
|
292
|
-
timestamp: Date.now()
|
|
297
|
+
timestamp: Date.now(),
|
|
293
298
|
type: "XHR",
|
|
294
299
|
error: "Failed",
|
|
295
300
|
canceled: false
|
|
@@ -298,7 +303,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
298
303
|
request.addEventListener("abort", () => {
|
|
299
304
|
pluginClient.send("request-failed", {
|
|
300
305
|
requestId,
|
|
301
|
-
timestamp: Date.now()
|
|
306
|
+
timestamp: Date.now(),
|
|
302
307
|
type: "XHR",
|
|
303
308
|
error: "Aborted",
|
|
304
309
|
canceled: true
|
|
@@ -350,6 +355,333 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
350
355
|
dispose
|
|
351
356
|
};
|
|
352
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
|
+
};
|
|
353
685
|
const useNetworkActivityDevTools = () => {
|
|
354
686
|
const client = useRozeniteDevToolsClient({
|
|
355
687
|
pluginId: "@rozenite/network-activity-plugin"
|
|
@@ -363,6 +695,61 @@ const useNetworkActivityDevTools = () => {
|
|
|
363
695
|
networkInspector.dispose();
|
|
364
696
|
};
|
|
365
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]);
|
|
366
753
|
return client;
|
|
367
754
|
};
|
|
368
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": {
|