@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.
Files changed (96) hide show
  1. package/dist/App.html +2 -2
  2. package/dist/assets/{App-CIflVb88.js → App-CA1Fbh0I.js} +12009 -10809
  3. package/dist/assets/{App-Czu6Vt2P.css → App-DoHQsY5s.css} +43 -0
  4. package/dist/event-source.cjs +22 -0
  5. package/dist/event-source.js +23 -0
  6. package/dist/rozenite.json +1 -1
  7. package/dist/src/react-native/{network-inspector.d.ts → http/network-inspector.d.ts} +1 -1
  8. package/dist/src/react-native/sse/event-source.d.ts +2 -0
  9. package/dist/src/react-native/sse/sse-inspector.d.ts +9 -0
  10. package/dist/src/react-native/sse/sse-interceptor.d.ts +36 -0
  11. package/dist/src/react-native/sse/types.d.ts +6 -0
  12. package/dist/src/react-native/utils.d.ts +6 -0
  13. package/dist/src/react-native/websocket/websocket-inspector.d.ts +9 -0
  14. package/dist/src/react-native/websocket/websocket-interceptor.d.ts +74 -0
  15. package/dist/src/shared/client.d.ts +8 -4
  16. package/dist/src/shared/sse-events.d.ts +35 -0
  17. package/dist/src/shared/websocket-events.d.ts +60 -0
  18. package/dist/src/ui/components/Badge.d.ts +1 -1
  19. package/dist/src/ui/components/Button.d.ts +1 -1
  20. package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +7 -0
  21. package/dist/src/ui/components/RequestList.d.ts +6 -26
  22. package/dist/src/ui/components/SidePanel.d.ts +1 -0
  23. package/dist/src/ui/components/Toolbar.d.ts +1 -0
  24. package/dist/src/ui/hooks/useCopyToClipboard.d.ts +4 -0
  25. package/dist/src/ui/state/derived.d.ts +5 -0
  26. package/dist/src/ui/state/hooks.d.ts +17 -0
  27. package/dist/src/ui/state/model.d.ts +98 -0
  28. package/dist/src/ui/state/store.d.ts +24 -0
  29. package/dist/src/ui/tabs/CookiesTab.d.ts +3 -6
  30. package/dist/src/ui/tabs/HeadersTab.d.ts +3 -15
  31. package/dist/src/ui/tabs/MessagesTab.d.ts +5 -0
  32. package/dist/src/ui/tabs/RequestTab.d.ts +2 -7
  33. package/dist/src/ui/tabs/ResponseTab.d.ts +2 -8
  34. package/dist/src/ui/tabs/SSEMessagesTab.d.ts +5 -0
  35. package/dist/src/ui/tabs/TimingTab.d.ts +3 -5
  36. package/dist/src/ui/types.d.ts +6 -3
  37. package/dist/src/ui/utils/assert.d.ts +1 -0
  38. package/dist/src/ui/utils/copyToClipboard.d.ts +1 -0
  39. package/dist/src/ui/utils/getHttpHeaderValue.d.ts +2 -0
  40. package/dist/src/ui/utils/getId.d.ts +1 -0
  41. package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
  42. package/dist/useNetworkActivityDevTools.cjs +433 -34
  43. package/dist/useNetworkActivityDevTools.js +431 -34
  44. package/package.json +19 -8
  45. package/src/react-native/{network-inspector.ts → http/network-inspector.ts} +14 -32
  46. package/src/react-native/{xml-request.d.ts → http/xml-request.d.ts} +1 -0
  47. package/src/react-native/sse/event-source.ts +25 -0
  48. package/src/react-native/sse/sse-inspector.ts +117 -0
  49. package/src/react-native/sse/sse-interceptor.ts +162 -0
  50. package/src/react-native/sse/types.ts +9 -0
  51. package/src/react-native/useNetworkActivityDevTools.ts +75 -1
  52. package/src/react-native/utils.ts +43 -0
  53. package/src/react-native/websocket/websocket-inspector.ts +180 -0
  54. package/src/react-native/websocket/websocket-interceptor.d.ts +4 -0
  55. package/src/react-native/websocket/websocket-interceptor.ts +166 -0
  56. package/src/shared/client.ts +10 -4
  57. package/src/shared/sse-events.ts +44 -0
  58. package/src/shared/websocket-events.ts +79 -0
  59. package/src/ui/components/Badge.tsx +1 -1
  60. package/src/ui/components/Button.tsx +1 -1
  61. package/src/ui/components/Input.tsx +1 -1
  62. package/src/ui/components/JsonTree.tsx +13 -0
  63. package/src/ui/components/JsonTreeCopyableItem.tsx +33 -0
  64. package/src/ui/components/RequestList.tsx +42 -123
  65. package/src/ui/components/ScrollArea.tsx +1 -1
  66. package/src/ui/components/Separator.tsx +1 -1
  67. package/src/ui/components/SidePanel.tsx +323 -0
  68. package/src/ui/components/Tabs.tsx +2 -2
  69. package/src/ui/components/Toolbar.tsx +45 -0
  70. package/src/ui/hooks/useCopyToClipboard.ts +28 -0
  71. package/src/ui/state/derived.ts +112 -0
  72. package/src/ui/state/hooks.ts +44 -0
  73. package/src/ui/state/model.ts +129 -0
  74. package/src/ui/state/store.ts +559 -0
  75. package/src/ui/tabs/CookiesTab.tsx +168 -179
  76. package/src/ui/tabs/HeadersTab.tsx +24 -31
  77. package/src/ui/tabs/MessagesTab.tsx +276 -0
  78. package/src/ui/tabs/RequestTab.tsx +28 -31
  79. package/src/ui/tabs/ResponseTab.tsx +10 -12
  80. package/src/ui/tabs/SSEMessagesTab.tsx +213 -0
  81. package/src/ui/tabs/TimingTab.tsx +33 -44
  82. package/src/ui/types.ts +6 -2
  83. package/src/ui/utils/assert.ts +5 -0
  84. package/src/ui/utils/copyToClipboard.ts +3 -0
  85. package/src/ui/utils/getHttpHeaderValue.ts +14 -0
  86. package/src/ui/utils/getId.ts +10 -0
  87. package/src/ui/utils/getStatusColor.ts +15 -0
  88. package/src/ui/views/InspectorView.tsx +24 -320
  89. package/tailwind.config.ts +3 -0
  90. package/vite.config.ts +12 -0
  91. /package/dist/src/react-native/{network-requests-registry.d.ts → http/network-requests-registry.d.ts} +0 -0
  92. /package/dist/src/react-native/{xhr-interceptor.d.ts → http/xhr-interceptor.d.ts} +0 -0
  93. /package/dist/src/ui/{utils.d.ts → utils/cn.d.ts} +0 -0
  94. /package/src/react-native/{network-requests-registry.ts → http/network-requests-registry.ts} +0 -0
  95. /package/src/react-native/{xhr-interceptor.ts → http/xhr-interceptor.ts} +0 -0
  96. /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 / 1e3,
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() / 1e3,
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() / 1e3
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() / 1e3,
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() / 1e3,
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() / 1e3,
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.7",
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
- "@rozenite/plugin-bridge": "1.0.0-alpha.7"
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
- "@floating-ui/react": "^0.26.0",
31
- "@tanstack/react-virtual": "^3.0.0",
32
- "lucide-react": "^0.263.1",
33
- "@rozenite/vite-plugin": "1.0.0-alpha.7",
34
- "rozenite": "1.0.0-alpha.7"
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": {