@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
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const react = require("react");
|
|
4
4
|
const pluginBridge = require("@rozenite/plugin-bridge");
|
|
5
|
+
const nanoevents = require("nanoevents");
|
|
6
|
+
const reactNative = require("react-native");
|
|
7
|
+
const WebSocketInterceptor = require("react-native/Libraries/WebSocket/WebSocketInterceptor");
|
|
8
|
+
const eventSource = require("./event-source.cjs");
|
|
9
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
10
|
+
const WebSocketInterceptor__default = /* @__PURE__ */ _interopDefault(WebSocketInterceptor);
|
|
5
11
|
function getHttpHeaderValue(headers, name) {
|
|
6
12
|
const lowerName = name.toLowerCase();
|
|
7
13
|
for (const key in headers) {
|
|
@@ -11,6 +17,26 @@ function getHttpHeaderValue(headers, name) {
|
|
|
11
17
|
}
|
|
12
18
|
return void 0;
|
|
13
19
|
}
|
|
20
|
+
const getContentType = (request) => {
|
|
21
|
+
const responseHeaders = request.responseHeaders;
|
|
22
|
+
const responseType = request.responseType;
|
|
23
|
+
const contentType = getHttpHeaderValue(responseHeaders || {}, "content-type");
|
|
24
|
+
if (contentType) {
|
|
25
|
+
return contentType.split(";")[0].trim();
|
|
26
|
+
}
|
|
27
|
+
switch (responseType) {
|
|
28
|
+
case "arraybuffer":
|
|
29
|
+
case "blob":
|
|
30
|
+
return "application/octet-stream";
|
|
31
|
+
case "text":
|
|
32
|
+
case "":
|
|
33
|
+
return "text/plain";
|
|
34
|
+
case "json":
|
|
35
|
+
return "application/json";
|
|
36
|
+
case "document":
|
|
37
|
+
return "text/html";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
14
40
|
const REQUEST_TTL = 1e3 * 60 * 5;
|
|
15
41
|
const getNetworkRequestsRegistry = () => {
|
|
16
42
|
const registry = /* @__PURE__ */ new Map();
|
|
@@ -52,7 +78,7 @@ let sendCallback;
|
|
|
52
78
|
let requestHeaderCallback;
|
|
53
79
|
let headerReceivedCallback;
|
|
54
80
|
let responseCallback;
|
|
55
|
-
let isInterceptorEnabled = false;
|
|
81
|
+
let isInterceptorEnabled$1 = false;
|
|
56
82
|
const XHRInterceptor = {
|
|
57
83
|
/**
|
|
58
84
|
* Invoked before XMLHttpRequest.open(...) is called.
|
|
@@ -85,10 +111,10 @@ const XHRInterceptor = {
|
|
|
85
111
|
requestHeaderCallback = callback;
|
|
86
112
|
},
|
|
87
113
|
isInterceptorEnabled() {
|
|
88
|
-
return isInterceptorEnabled;
|
|
114
|
+
return isInterceptorEnabled$1;
|
|
89
115
|
},
|
|
90
116
|
enableInterception() {
|
|
91
|
-
if (isInterceptorEnabled) {
|
|
117
|
+
if (isInterceptorEnabled$1) {
|
|
92
118
|
return;
|
|
93
119
|
}
|
|
94
120
|
XMLHttpRequest.prototype.open = function(method, url) {
|
|
@@ -111,7 +137,7 @@ const XHRInterceptor = {
|
|
|
111
137
|
this.addEventListener(
|
|
112
138
|
"readystatechange",
|
|
113
139
|
() => {
|
|
114
|
-
if (!isInterceptorEnabled) {
|
|
140
|
+
if (!isInterceptorEnabled$1) {
|
|
115
141
|
return;
|
|
116
142
|
}
|
|
117
143
|
if (this.readyState === this.HEADERS_RECEIVED) {
|
|
@@ -151,14 +177,14 @@ const XHRInterceptor = {
|
|
|
151
177
|
}
|
|
152
178
|
originalXHRSend.apply(this, arguments);
|
|
153
179
|
};
|
|
154
|
-
isInterceptorEnabled = true;
|
|
180
|
+
isInterceptorEnabled$1 = true;
|
|
155
181
|
},
|
|
156
182
|
// Unpatch XMLHttpRequest methods and remove the callbacks.
|
|
157
183
|
disableInterception() {
|
|
158
|
-
if (!isInterceptorEnabled) {
|
|
184
|
+
if (!isInterceptorEnabled$1) {
|
|
159
185
|
return;
|
|
160
186
|
}
|
|
161
|
-
isInterceptorEnabled = false;
|
|
187
|
+
isInterceptorEnabled$1 = false;
|
|
162
188
|
XMLHttpRequest.prototype.send = originalXHRSend;
|
|
163
189
|
XMLHttpRequest.prototype.open = originalXHROpen;
|
|
164
190
|
XMLHttpRequest.prototype.setRequestHeader = originalXHRSetRequestHeader;
|
|
@@ -170,26 +196,6 @@ const XHRInterceptor = {
|
|
|
170
196
|
}
|
|
171
197
|
};
|
|
172
198
|
const networkRequestsRegistry = getNetworkRequestsRegistry();
|
|
173
|
-
const getContentType = (request) => {
|
|
174
|
-
const responseHeaders = request.responseHeaders;
|
|
175
|
-
const responseType = request.responseType;
|
|
176
|
-
const contentType = getHttpHeaderValue(responseHeaders || {}, "content-type");
|
|
177
|
-
if (contentType) {
|
|
178
|
-
return contentType.split(";")[0].trim();
|
|
179
|
-
}
|
|
180
|
-
switch (responseType) {
|
|
181
|
-
case "arraybuffer":
|
|
182
|
-
case "blob":
|
|
183
|
-
return "application/octet-stream";
|
|
184
|
-
case "text":
|
|
185
|
-
case "":
|
|
186
|
-
return "text/plain";
|
|
187
|
-
case "json":
|
|
188
|
-
return "application/json";
|
|
189
|
-
case "document":
|
|
190
|
-
return "text/html";
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
199
|
const getResponseSize = (request) => {
|
|
194
200
|
if (typeof request.response === "object") {
|
|
195
201
|
return request.response.size;
|
|
@@ -198,7 +204,7 @@ const getResponseSize = (request) => {
|
|
|
198
204
|
};
|
|
199
205
|
const getResponseBody = async (request) => {
|
|
200
206
|
const responseType = request.responseType;
|
|
201
|
-
if (responseType === "text") {
|
|
207
|
+
if (responseType === "" || responseType === "text") {
|
|
202
208
|
return request.responseText;
|
|
203
209
|
}
|
|
204
210
|
if (responseType === "blob") {
|
|
@@ -243,12 +249,13 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
243
249
|
const handleRequestSend = (data, request) => {
|
|
244
250
|
const sendTime = Date.now();
|
|
245
251
|
const requestId = generateRequestId();
|
|
252
|
+
request._rozeniteRequestId = requestId;
|
|
246
253
|
const initiator = getInitiatorFromStack();
|
|
247
254
|
networkRequestsRegistry.addEntry(requestId, request);
|
|
248
255
|
let ttfb = 0;
|
|
249
256
|
pluginClient.send("request-sent", {
|
|
250
257
|
requestId,
|
|
251
|
-
timestamp: sendTime
|
|
258
|
+
timestamp: sendTime,
|
|
252
259
|
request: {
|
|
253
260
|
url: request._url,
|
|
254
261
|
method: request._method,
|
|
@@ -266,7 +273,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
266
273
|
request.addEventListener("load", () => {
|
|
267
274
|
pluginClient.send("response-received", {
|
|
268
275
|
requestId,
|
|
269
|
-
timestamp: Date.now()
|
|
276
|
+
timestamp: Date.now(),
|
|
270
277
|
type: "XHR",
|
|
271
278
|
response: {
|
|
272
279
|
url: request._url,
|
|
@@ -275,14 +282,14 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
275
282
|
headers: request.responseHeaders || {},
|
|
276
283
|
contentType: getContentType(request),
|
|
277
284
|
size: getResponseSize(request),
|
|
278
|
-
responseTime: Date.now()
|
|
285
|
+
responseTime: Date.now()
|
|
279
286
|
}
|
|
280
287
|
});
|
|
281
288
|
});
|
|
282
289
|
request.addEventListener("loadend", () => {
|
|
283
290
|
pluginClient.send("request-completed", {
|
|
284
291
|
requestId,
|
|
285
|
-
timestamp: Date.now()
|
|
292
|
+
timestamp: Date.now(),
|
|
286
293
|
duration: Date.now() - sendTime,
|
|
287
294
|
size: getResponseSize(request),
|
|
288
295
|
ttfb
|
|
@@ -291,7 +298,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
291
298
|
request.addEventListener("error", () => {
|
|
292
299
|
pluginClient.send("request-failed", {
|
|
293
300
|
requestId,
|
|
294
|
-
timestamp: Date.now()
|
|
301
|
+
timestamp: Date.now(),
|
|
295
302
|
type: "XHR",
|
|
296
303
|
error: "Failed",
|
|
297
304
|
canceled: false
|
|
@@ -300,7 +307,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
300
307
|
request.addEventListener("abort", () => {
|
|
301
308
|
pluginClient.send("request-failed", {
|
|
302
309
|
requestId,
|
|
303
|
-
timestamp: Date.now()
|
|
310
|
+
timestamp: Date.now(),
|
|
304
311
|
type: "XHR",
|
|
305
312
|
error: "Aborted",
|
|
306
313
|
canceled: true
|
|
@@ -352,6 +359,333 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
352
359
|
dispose
|
|
353
360
|
};
|
|
354
361
|
};
|
|
362
|
+
const getWebSocketInterceptor = () => {
|
|
363
|
+
if (reactNative.Platform.constants.reactNativeVersion.minor >= 79) {
|
|
364
|
+
return WebSocketInterceptor__default.default;
|
|
365
|
+
} else {
|
|
366
|
+
const WebSocketInterceptorPreRN079 = WebSocketInterceptor__default.default;
|
|
367
|
+
return {
|
|
368
|
+
...WebSocketInterceptorPreRN079,
|
|
369
|
+
setOnMessageCallback: (callback) => {
|
|
370
|
+
WebSocketInterceptorPreRN079.setOnMessageCallback((socketId, data) => {
|
|
371
|
+
callback(data, socketId);
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
setOnCloseCallback: (callback) => {
|
|
375
|
+
WebSocketInterceptorPreRN079.setOnCloseCallback((error, socketId) => {
|
|
376
|
+
callback(socketId, error);
|
|
377
|
+
});
|
|
378
|
+
},
|
|
379
|
+
setOnErrorCallback: (callback) => {
|
|
380
|
+
WebSocketInterceptorPreRN079.setOnErrorCallback((error, socketId) => {
|
|
381
|
+
callback(socketId, error);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
const getWebSocketInspector = () => {
|
|
388
|
+
const eventEmitter = nanoevents.createNanoEvents();
|
|
389
|
+
const socketUrlMap = /* @__PURE__ */ new Map();
|
|
390
|
+
const webSocketInterceptor = getWebSocketInterceptor();
|
|
391
|
+
return {
|
|
392
|
+
enable: () => {
|
|
393
|
+
webSocketInterceptor.setConnectCallback(
|
|
394
|
+
(url, protocols, options, socketId) => {
|
|
395
|
+
socketUrlMap.set(socketId, url);
|
|
396
|
+
const event = {
|
|
397
|
+
type: "websocket-connect",
|
|
398
|
+
url,
|
|
399
|
+
socketId,
|
|
400
|
+
timestamp: Date.now(),
|
|
401
|
+
protocols,
|
|
402
|
+
options
|
|
403
|
+
};
|
|
404
|
+
eventEmitter.emit("websocket-connect", event);
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
webSocketInterceptor.setCloseCallback(
|
|
408
|
+
(code, reason, socketId) => {
|
|
409
|
+
const url = socketUrlMap.get(socketId);
|
|
410
|
+
if (!url) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const event = {
|
|
414
|
+
type: "websocket-close",
|
|
415
|
+
url,
|
|
416
|
+
socketId,
|
|
417
|
+
timestamp: Date.now(),
|
|
418
|
+
code: code || 0,
|
|
419
|
+
reason: reason || void 0
|
|
420
|
+
};
|
|
421
|
+
eventEmitter.emit("websocket-close", event);
|
|
422
|
+
socketUrlMap.delete(socketId);
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
webSocketInterceptor.setOnMessageCallback(
|
|
426
|
+
(data, socketId) => {
|
|
427
|
+
const url = socketUrlMap.get(socketId);
|
|
428
|
+
if (!url) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const event = {
|
|
432
|
+
type: "websocket-message-received",
|
|
433
|
+
url,
|
|
434
|
+
socketId,
|
|
435
|
+
timestamp: Date.now(),
|
|
436
|
+
data,
|
|
437
|
+
messageType: typeof data === "string" ? "text" : "binary"
|
|
438
|
+
};
|
|
439
|
+
eventEmitter.emit("websocket-message-received", event);
|
|
440
|
+
}
|
|
441
|
+
);
|
|
442
|
+
webSocketInterceptor.setOnErrorCallback(
|
|
443
|
+
(error, socketId) => {
|
|
444
|
+
const url = socketUrlMap.get(socketId);
|
|
445
|
+
if (!url) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const event = {
|
|
449
|
+
type: "websocket-error",
|
|
450
|
+
url,
|
|
451
|
+
socketId,
|
|
452
|
+
timestamp: Date.now(),
|
|
453
|
+
error
|
|
454
|
+
};
|
|
455
|
+
eventEmitter.emit("websocket-error", event);
|
|
456
|
+
}
|
|
457
|
+
);
|
|
458
|
+
webSocketInterceptor.setSendCallback((data, socketId) => {
|
|
459
|
+
const url = socketUrlMap.get(socketId);
|
|
460
|
+
if (!url) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const event = {
|
|
464
|
+
type: "websocket-message-sent",
|
|
465
|
+
url,
|
|
466
|
+
socketId,
|
|
467
|
+
timestamp: Date.now(),
|
|
468
|
+
data,
|
|
469
|
+
messageType: typeof data === "string" ? "text" : "binary"
|
|
470
|
+
};
|
|
471
|
+
eventEmitter.emit("websocket-message-sent", event);
|
|
472
|
+
});
|
|
473
|
+
webSocketInterceptor.setOnOpenCallback((socketId) => {
|
|
474
|
+
const url = socketUrlMap.get(socketId);
|
|
475
|
+
if (!url) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const event = {
|
|
479
|
+
type: "websocket-open",
|
|
480
|
+
url,
|
|
481
|
+
socketId,
|
|
482
|
+
timestamp: Date.now()
|
|
483
|
+
};
|
|
484
|
+
eventEmitter.emit("websocket-open", event);
|
|
485
|
+
});
|
|
486
|
+
webSocketInterceptor.setOnCloseCallback(
|
|
487
|
+
(error, socketId) => {
|
|
488
|
+
const url = socketUrlMap.get(socketId);
|
|
489
|
+
if (!url) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const event = {
|
|
493
|
+
type: "websocket-close",
|
|
494
|
+
url,
|
|
495
|
+
socketId,
|
|
496
|
+
timestamp: Date.now(),
|
|
497
|
+
code: error.code,
|
|
498
|
+
reason: error.reason
|
|
499
|
+
};
|
|
500
|
+
eventEmitter.emit("websocket-close", event);
|
|
501
|
+
socketUrlMap.delete(socketId);
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
webSocketInterceptor.enableInterception();
|
|
505
|
+
},
|
|
506
|
+
disable: () => {
|
|
507
|
+
webSocketInterceptor.disableInterception();
|
|
508
|
+
},
|
|
509
|
+
isEnabled: () => webSocketInterceptor.isInterceptorEnabled(),
|
|
510
|
+
dispose: () => {
|
|
511
|
+
eventEmitter.events = {};
|
|
512
|
+
socketUrlMap.clear();
|
|
513
|
+
},
|
|
514
|
+
on: (event, callback) => eventEmitter.on(event, callback)
|
|
515
|
+
};
|
|
516
|
+
};
|
|
517
|
+
let connectCallback;
|
|
518
|
+
let messageCallback;
|
|
519
|
+
let errorCallback;
|
|
520
|
+
let openEventCallback;
|
|
521
|
+
let closeCallback;
|
|
522
|
+
let isInterceptorEnabled = false;
|
|
523
|
+
const eventSourceClass = eventSource.getEventSource();
|
|
524
|
+
const originalOpen = eventSourceClass.prototype.open;
|
|
525
|
+
const SSEInterceptor = {
|
|
526
|
+
/**
|
|
527
|
+
* Invoked when EventSource.open() is called (connection attempt starting).
|
|
528
|
+
*/
|
|
529
|
+
setConnectCallback(callback) {
|
|
530
|
+
connectCallback = callback;
|
|
531
|
+
},
|
|
532
|
+
/**
|
|
533
|
+
* Invoked when a message event is received.
|
|
534
|
+
*/
|
|
535
|
+
setMessageCallback(callback) {
|
|
536
|
+
messageCallback = callback;
|
|
537
|
+
},
|
|
538
|
+
/**
|
|
539
|
+
* Invoked when an error event occurs.
|
|
540
|
+
*/
|
|
541
|
+
setErrorCallback(callback) {
|
|
542
|
+
errorCallback = callback;
|
|
543
|
+
},
|
|
544
|
+
/**
|
|
545
|
+
* Invoked when the connection is successfully opened (open event fired).
|
|
546
|
+
*/
|
|
547
|
+
setOpenEventCallback(callback) {
|
|
548
|
+
openEventCallback = callback;
|
|
549
|
+
},
|
|
550
|
+
/**
|
|
551
|
+
* Invoked when the connection is closed.
|
|
552
|
+
*/
|
|
553
|
+
setCloseCallback(callback) {
|
|
554
|
+
closeCallback = callback;
|
|
555
|
+
},
|
|
556
|
+
isInterceptorEnabled() {
|
|
557
|
+
return isInterceptorEnabled;
|
|
558
|
+
},
|
|
559
|
+
enableInterception() {
|
|
560
|
+
if (isInterceptorEnabled) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
eventSourceClass.prototype.open = function() {
|
|
564
|
+
if (connectCallback) {
|
|
565
|
+
connectCallback(this.url, this);
|
|
566
|
+
}
|
|
567
|
+
this.addEventListener("open", (event) => {
|
|
568
|
+
if (openEventCallback) {
|
|
569
|
+
openEventCallback(event, this);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
this.addEventListener("message", (event) => {
|
|
573
|
+
if (messageCallback) {
|
|
574
|
+
messageCallback(event, this);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
this.addEventListener(
|
|
578
|
+
"error",
|
|
579
|
+
(event) => {
|
|
580
|
+
if (errorCallback) {
|
|
581
|
+
errorCallback(event, this);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
this.addEventListener("close", (event) => {
|
|
586
|
+
if (closeCallback) {
|
|
587
|
+
closeCallback(event, this);
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
return originalOpen.call(this);
|
|
591
|
+
};
|
|
592
|
+
isInterceptorEnabled = true;
|
|
593
|
+
},
|
|
594
|
+
// Unpatch EventSource open method and remove the callbacks.
|
|
595
|
+
disableInterception() {
|
|
596
|
+
if (!isInterceptorEnabled) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
isInterceptorEnabled = false;
|
|
600
|
+
eventSourceClass.prototype.open = originalOpen;
|
|
601
|
+
connectCallback = null;
|
|
602
|
+
messageCallback = null;
|
|
603
|
+
errorCallback = null;
|
|
604
|
+
openEventCallback = null;
|
|
605
|
+
closeCallback = null;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
const getSSEInspector = () => {
|
|
609
|
+
const eventEmitter = nanoevents.createNanoEvents();
|
|
610
|
+
const getRequestId = (eventSource2) => {
|
|
611
|
+
var _a;
|
|
612
|
+
const requestId = (_a = eventSource2._xhr) == null ? void 0 : _a._rozeniteRequestId;
|
|
613
|
+
if (!requestId) {
|
|
614
|
+
throw new Error(
|
|
615
|
+
"No request ID found for EventSource. This should never happen!"
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
return requestId;
|
|
619
|
+
};
|
|
620
|
+
return {
|
|
621
|
+
enable: () => {
|
|
622
|
+
SSEInterceptor.setOpenEventCallback((_, eventSource2) => {
|
|
623
|
+
const sseEventSource = eventSource2;
|
|
624
|
+
const requestId = getRequestId(sseEventSource);
|
|
625
|
+
const sseXhr = sseEventSource._xhr;
|
|
626
|
+
const event = {
|
|
627
|
+
type: "sse-open",
|
|
628
|
+
requestId,
|
|
629
|
+
timestamp: Date.now(),
|
|
630
|
+
response: {
|
|
631
|
+
url: sseXhr._url,
|
|
632
|
+
status: sseXhr.status,
|
|
633
|
+
statusText: sseXhr.statusText,
|
|
634
|
+
headers: sseXhr.responseHeaders || {},
|
|
635
|
+
contentType: getContentType(sseXhr),
|
|
636
|
+
size: 0,
|
|
637
|
+
responseTime: Date.now()
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
eventEmitter.emit("sse-open", event);
|
|
641
|
+
});
|
|
642
|
+
SSEInterceptor.setMessageCallback((messageEvent, eventSource2) => {
|
|
643
|
+
const sseEventSource = eventSource2;
|
|
644
|
+
const requestId = getRequestId(sseEventSource);
|
|
645
|
+
const event = {
|
|
646
|
+
type: "sse-message",
|
|
647
|
+
requestId,
|
|
648
|
+
timestamp: Date.now(),
|
|
649
|
+
data: messageEvent.data || ""
|
|
650
|
+
};
|
|
651
|
+
eventEmitter.emit("sse-message", event);
|
|
652
|
+
});
|
|
653
|
+
SSEInterceptor.setErrorCallback((errorEvent, eventSource2) => {
|
|
654
|
+
const sseEventSource = eventSource2;
|
|
655
|
+
const requestId = getRequestId(sseEventSource);
|
|
656
|
+
const event = {
|
|
657
|
+
type: "sse-error",
|
|
658
|
+
requestId,
|
|
659
|
+
timestamp: Date.now(),
|
|
660
|
+
error: {
|
|
661
|
+
type: errorEvent.type,
|
|
662
|
+
message: errorEvent.type === "timeout" ? "Timeout" : errorEvent.message
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
eventEmitter.emit("sse-error", event);
|
|
666
|
+
});
|
|
667
|
+
SSEInterceptor.setCloseCallback((_, eventSource2) => {
|
|
668
|
+
const sseEventSource = eventSource2;
|
|
669
|
+
const requestId = getRequestId(sseEventSource);
|
|
670
|
+
const event = {
|
|
671
|
+
type: "sse-close",
|
|
672
|
+
requestId,
|
|
673
|
+
timestamp: Date.now()
|
|
674
|
+
};
|
|
675
|
+
eventEmitter.emit("sse-close", event);
|
|
676
|
+
});
|
|
677
|
+
SSEInterceptor.enableInterception();
|
|
678
|
+
},
|
|
679
|
+
disable: () => {
|
|
680
|
+
SSEInterceptor.disableInterception();
|
|
681
|
+
},
|
|
682
|
+
isEnabled: () => SSEInterceptor.isInterceptorEnabled(),
|
|
683
|
+
dispose: () => {
|
|
684
|
+
eventEmitter.events = {};
|
|
685
|
+
},
|
|
686
|
+
on: (event, callback) => eventEmitter.on(event, callback)
|
|
687
|
+
};
|
|
688
|
+
};
|
|
355
689
|
const useNetworkActivityDevTools = () => {
|
|
356
690
|
const client = pluginBridge.useRozeniteDevToolsClient({
|
|
357
691
|
pluginId: "@rozenite/network-activity-plugin"
|
|
@@ -365,6 +699,61 @@ const useNetworkActivityDevTools = () => {
|
|
|
365
699
|
networkInspector.dispose();
|
|
366
700
|
};
|
|
367
701
|
}, [client]);
|
|
702
|
+
react.useEffect(() => {
|
|
703
|
+
if (!client) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const eventsToForward = [
|
|
707
|
+
"websocket-connect",
|
|
708
|
+
"websocket-open",
|
|
709
|
+
"websocket-close",
|
|
710
|
+
"websocket-message-sent",
|
|
711
|
+
"websocket-message-received",
|
|
712
|
+
"websocket-error",
|
|
713
|
+
"websocket-connection-status-changed"
|
|
714
|
+
];
|
|
715
|
+
const websocketInspector = getWebSocketInspector();
|
|
716
|
+
eventsToForward.forEach((event) => {
|
|
717
|
+
websocketInspector.on(event, (event2) => {
|
|
718
|
+
client.send(event2.type, event2);
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
client.onMessage("network-enable", () => {
|
|
722
|
+
websocketInspector.enable();
|
|
723
|
+
});
|
|
724
|
+
client.onMessage("network-disable", () => {
|
|
725
|
+
websocketInspector.disable();
|
|
726
|
+
});
|
|
727
|
+
return () => {
|
|
728
|
+
websocketInspector.dispose();
|
|
729
|
+
};
|
|
730
|
+
}, [client]);
|
|
731
|
+
react.useEffect(() => {
|
|
732
|
+
if (!client) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const eventsToForward = [
|
|
736
|
+
"sse-open",
|
|
737
|
+
"sse-message",
|
|
738
|
+
"sse-error",
|
|
739
|
+
"sse-close"
|
|
740
|
+
];
|
|
741
|
+
const sseInspector = getSSEInspector();
|
|
742
|
+
eventsToForward.forEach((event) => {
|
|
743
|
+
sseInspector.on(event, (event2) => {
|
|
744
|
+
client.send(event2.type, event2);
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
client.onMessage("network-enable", () => {
|
|
748
|
+
sseInspector.enable();
|
|
749
|
+
});
|
|
750
|
+
client.onMessage("network-disable", () => {
|
|
751
|
+
sseInspector.disable();
|
|
752
|
+
});
|
|
753
|
+
return () => {
|
|
754
|
+
sseInspector.dispose();
|
|
755
|
+
};
|
|
756
|
+
}, [client]);
|
|
368
757
|
return client;
|
|
369
758
|
};
|
|
370
759
|
exports.useNetworkActivityDevTools = useNetworkActivityDevTools;
|