@rozenite/network-activity-plugin 1.0.0-alpha.1 → 1.0.0-alpha.10

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 (134) hide show
  1. package/README.md +3 -5
  2. package/dist/{panel.html → App.html} +3 -3
  3. package/dist/assets/App-CA1Fbh0I.js +25364 -0
  4. package/dist/assets/App-DoHQsY5s.css +1276 -0
  5. package/dist/event-source.cjs +22 -0
  6. package/dist/event-source.js +23 -0
  7. package/dist/react-native.cjs +8 -1
  8. package/dist/react-native.d.ts +1 -5
  9. package/dist/react-native.js +6 -171
  10. package/dist/rozenite.config.d.ts +7 -0
  11. package/dist/rozenite.json +1 -1
  12. package/dist/src/react-native/http/network-inspector.d.ts +8 -0
  13. package/dist/src/react-native/http/network-requests-registry.d.ts +6 -0
  14. package/dist/src/react-native/http/xhr-interceptor.d.ts +38 -0
  15. package/dist/src/react-native/sse/event-source.d.ts +2 -0
  16. package/dist/src/react-native/sse/sse-inspector.d.ts +9 -0
  17. package/dist/src/react-native/sse/sse-interceptor.d.ts +36 -0
  18. package/dist/src/react-native/sse/types.d.ts +6 -0
  19. package/dist/src/react-native/useNetworkActivityDevTools.d.ts +2 -0
  20. package/dist/src/react-native/utils.d.ts +6 -0
  21. package/dist/src/react-native/websocket/websocket-inspector.d.ts +9 -0
  22. package/dist/src/react-native/websocket/websocket-interceptor.d.ts +74 -0
  23. package/dist/src/shared/client.d.ts +68 -0
  24. package/dist/src/shared/sse-events.d.ts +35 -0
  25. package/dist/src/shared/websocket-events.d.ts +60 -0
  26. package/dist/src/ui/App.d.ts +1 -0
  27. package/dist/src/ui/components/Badge.d.ts +9 -0
  28. package/dist/src/ui/components/Button.d.ts +11 -0
  29. package/dist/src/ui/components/Input.d.ts +3 -0
  30. package/dist/src/ui/components/JsonTree.d.ts +5 -0
  31. package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +7 -0
  32. package/dist/src/ui/components/RequestList.d.ts +25 -0
  33. package/dist/src/ui/components/ScrollArea.d.ts +4 -0
  34. package/dist/src/ui/components/Separator.d.ts +3 -0
  35. package/dist/src/ui/components/SidePanel.d.ts +1 -0
  36. package/dist/src/ui/components/Toolbar.d.ts +1 -0
  37. package/dist/src/ui/hooks/useCopyToClipboard.d.ts +4 -0
  38. package/dist/src/ui/state/derived.d.ts +5 -0
  39. package/dist/src/ui/state/hooks.d.ts +17 -0
  40. package/dist/src/ui/state/model.d.ts +98 -0
  41. package/dist/src/ui/state/store.d.ts +24 -0
  42. package/dist/src/ui/tabs/CookiesTab.d.ts +5 -0
  43. package/dist/src/ui/tabs/HeadersTab.d.ts +5 -0
  44. package/dist/src/ui/tabs/MessagesTab.d.ts +5 -0
  45. package/dist/src/ui/tabs/RequestTab.d.ts +5 -0
  46. package/dist/src/ui/tabs/ResponseTab.d.ts +6 -0
  47. package/dist/src/ui/tabs/SSEMessagesTab.d.ts +5 -0
  48. package/dist/src/ui/tabs/TimingTab.d.ts +5 -0
  49. package/dist/src/ui/types.d.ts +26 -0
  50. package/dist/src/ui/utils/assert.d.ts +1 -0
  51. package/dist/src/ui/utils/cn.d.ts +2 -0
  52. package/dist/src/ui/utils/copyToClipboard.d.ts +1 -0
  53. package/dist/src/ui/utils/getHttpHeaderValue.d.ts +2 -0
  54. package/dist/src/ui/utils/getId.d.ts +1 -0
  55. package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
  56. package/dist/src/ui/views/InspectorView.d.ts +5 -0
  57. package/dist/src/ui/views/LoadingView.d.ts +1 -0
  58. package/dist/useNetworkActivityDevTools.cjs +759 -0
  59. package/dist/useNetworkActivityDevTools.js +757 -0
  60. package/package.json +31 -10
  61. package/postcss.config.js +6 -0
  62. package/project.json +12 -0
  63. package/react-native.ts +2 -1
  64. package/rozenite.config.ts +2 -2
  65. package/src/css-modules.d.ts +1 -1
  66. package/src/react-native/http/network-inspector.ts +226 -0
  67. package/src/react-native/http/network-requests-registry.ts +52 -0
  68. package/src/react-native/http/xhr-interceptor.ts +211 -0
  69. package/src/react-native/http/xml-request.d.ts +34 -0
  70. package/src/react-native/sse/event-source.ts +25 -0
  71. package/src/react-native/sse/sse-inspector.ts +117 -0
  72. package/src/react-native/sse/sse-interceptor.ts +162 -0
  73. package/src/react-native/sse/types.ts +9 -0
  74. package/src/react-native/useNetworkActivityDevTools.ts +73 -210
  75. package/src/react-native/utils.ts +43 -0
  76. package/src/react-native/websocket/websocket-inspector.ts +180 -0
  77. package/src/react-native/websocket/websocket-interceptor.d.ts +4 -0
  78. package/src/react-native/websocket/websocket-interceptor.ts +166 -0
  79. package/src/shared/client.ts +86 -0
  80. package/src/shared/sse-events.ts +44 -0
  81. package/src/shared/websocket-events.ts +79 -0
  82. package/src/ui/App.tsx +19 -0
  83. package/src/ui/components/Badge.tsx +36 -0
  84. package/src/ui/components/Button.tsx +56 -0
  85. package/src/ui/components/Input.tsx +22 -0
  86. package/src/ui/components/JsonTree.tsx +50 -0
  87. package/src/ui/components/JsonTreeCopyableItem.tsx +33 -0
  88. package/src/ui/components/RequestList.tsx +295 -0
  89. package/src/ui/components/ScrollArea.tsx +48 -0
  90. package/src/ui/components/Separator.tsx +31 -0
  91. package/src/ui/components/SidePanel.tsx +323 -0
  92. package/src/ui/components/Tabs.tsx +55 -0
  93. package/src/ui/components/Toolbar.tsx +45 -0
  94. package/src/ui/globals.css +90 -0
  95. package/src/ui/hooks/useCopyToClipboard.ts +28 -0
  96. package/src/ui/state/derived.ts +112 -0
  97. package/src/ui/state/hooks.ts +44 -0
  98. package/src/ui/state/model.ts +129 -0
  99. package/src/ui/state/store.ts +559 -0
  100. package/src/ui/tabs/CookiesTab.tsx +279 -0
  101. package/src/ui/tabs/HeadersTab.tsx +110 -0
  102. package/src/ui/tabs/MessagesTab.tsx +276 -0
  103. package/src/ui/tabs/RequestTab.tsx +69 -0
  104. package/src/ui/tabs/ResponseTab.tsx +138 -0
  105. package/src/ui/tabs/SSEMessagesTab.tsx +213 -0
  106. package/src/ui/tabs/TimingTab.tsx +60 -0
  107. package/src/ui/types.ts +34 -0
  108. package/src/ui/utils/assert.ts +5 -0
  109. package/src/ui/utils/cn.ts +6 -0
  110. package/src/ui/utils/copyToClipboard.ts +3 -0
  111. package/src/ui/utils/getHttpHeaderValue.ts +14 -0
  112. package/src/ui/utils/getId.ts +10 -0
  113. package/src/ui/utils/getStatusColor.ts +15 -0
  114. package/src/ui/views/InspectorView.tsx +53 -0
  115. package/src/ui/views/LoadingView.tsx +19 -0
  116. package/tailwind.config.ts +96 -0
  117. package/tsconfig.json +13 -6
  118. package/tsconfig.tsbuildinfo +1 -0
  119. package/vite.config.ts +13 -1
  120. package/dist/assets/panel-C5YgUUj5.js +0 -54
  121. package/dist/assets/panel-NCVczPb1.css +0 -1
  122. package/src/types/network.ts +0 -153
  123. package/src/ui/components.module.css +0 -158
  124. package/src/ui/components.tsx +0 -219
  125. package/src/ui/network-details.module.css +0 -57
  126. package/src/ui/network-details.tsx +0 -134
  127. package/src/ui/network-list.module.css +0 -122
  128. package/src/ui/network-list.tsx +0 -145
  129. package/src/ui/network-toolbar.module.css +0 -9
  130. package/src/ui/network-toolbar.tsx +0 -40
  131. package/src/ui/panel.module.css +0 -61
  132. package/src/ui/panel.tsx +0 -201
  133. package/src/ui/tanstack-query.tsx +0 -197
  134. package/src/ui/utils.ts +0 -89
@@ -0,0 +1,759 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const react = require("react");
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);
11
+ function getHttpHeaderValue(headers, name) {
12
+ const lowerName = name.toLowerCase();
13
+ for (const key in headers) {
14
+ if (key.toLowerCase() === lowerName) {
15
+ return headers[key];
16
+ }
17
+ }
18
+ return void 0;
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
+ };
40
+ const REQUEST_TTL = 1e3 * 60 * 5;
41
+ const getNetworkRequestsRegistry = () => {
42
+ const registry = /* @__PURE__ */ new Map();
43
+ const trimRegistry = () => {
44
+ const now = Date.now();
45
+ registry.forEach((entry) => {
46
+ if (now - entry.sentAt < REQUEST_TTL) {
47
+ return;
48
+ }
49
+ registry.delete(entry.id);
50
+ });
51
+ };
52
+ const addEntry = (id, request) => {
53
+ trimRegistry();
54
+ registry.set(id, {
55
+ id,
56
+ request,
57
+ sentAt: Date.now()
58
+ });
59
+ };
60
+ const getEntry = (id) => {
61
+ var _a;
62
+ return ((_a = registry.get(id)) == null ? void 0 : _a.request) ?? null;
63
+ };
64
+ const clear = () => {
65
+ registry.clear();
66
+ };
67
+ return {
68
+ addEntry,
69
+ getEntry,
70
+ clear
71
+ };
72
+ };
73
+ const originalXHROpen = XMLHttpRequest.prototype.open;
74
+ const originalXHRSend = XMLHttpRequest.prototype.send;
75
+ const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
76
+ let openCallback;
77
+ let sendCallback;
78
+ let requestHeaderCallback;
79
+ let headerReceivedCallback;
80
+ let responseCallback;
81
+ let isInterceptorEnabled$1 = false;
82
+ const XHRInterceptor = {
83
+ /**
84
+ * Invoked before XMLHttpRequest.open(...) is called.
85
+ */
86
+ setOpenCallback(callback) {
87
+ openCallback = callback;
88
+ },
89
+ /**
90
+ * Invoked before XMLHttpRequest.send(...) is called.
91
+ */
92
+ setSendCallback(callback) {
93
+ sendCallback = callback;
94
+ },
95
+ /**
96
+ * Invoked after xhr's readyState becomes xhr.HEADERS_RECEIVED.
97
+ */
98
+ setHeaderReceivedCallback(callback) {
99
+ headerReceivedCallback = callback;
100
+ },
101
+ /**
102
+ * Invoked after xhr's readyState becomes xhr.DONE.
103
+ */
104
+ setResponseCallback(callback) {
105
+ responseCallback = callback;
106
+ },
107
+ /**
108
+ * Invoked before XMLHttpRequest.setRequestHeader(...) is called.
109
+ */
110
+ setRequestHeaderCallback(callback) {
111
+ requestHeaderCallback = callback;
112
+ },
113
+ isInterceptorEnabled() {
114
+ return isInterceptorEnabled$1;
115
+ },
116
+ enableInterception() {
117
+ if (isInterceptorEnabled$1) {
118
+ return;
119
+ }
120
+ XMLHttpRequest.prototype.open = function(method, url) {
121
+ if (openCallback) {
122
+ openCallback(method, url, this);
123
+ }
124
+ originalXHROpen.apply(this, arguments);
125
+ };
126
+ XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
127
+ if (requestHeaderCallback) {
128
+ requestHeaderCallback(header, value, this);
129
+ }
130
+ originalXHRSetRequestHeader.apply(this, arguments);
131
+ };
132
+ XMLHttpRequest.prototype.send = function(data) {
133
+ if (sendCallback) {
134
+ sendCallback(data, this);
135
+ }
136
+ if (this.addEventListener) {
137
+ this.addEventListener(
138
+ "readystatechange",
139
+ () => {
140
+ if (!isInterceptorEnabled$1) {
141
+ return;
142
+ }
143
+ if (this.readyState === this.HEADERS_RECEIVED) {
144
+ const contentTypeString = this.getResponseHeader("Content-Type");
145
+ const contentLengthString = this.getResponseHeader("Content-Length");
146
+ let responseContentType, responseSize;
147
+ if (contentTypeString) {
148
+ responseContentType = contentTypeString.split(";")[0];
149
+ }
150
+ if (contentLengthString) {
151
+ responseSize = parseInt(contentLengthString, 10);
152
+ }
153
+ if (headerReceivedCallback) {
154
+ headerReceivedCallback(
155
+ responseContentType,
156
+ responseSize,
157
+ this.getAllResponseHeaders(),
158
+ this
159
+ );
160
+ }
161
+ }
162
+ if (this.readyState === this.DONE) {
163
+ if (responseCallback) {
164
+ responseCallback(
165
+ this.status,
166
+ this.timeout,
167
+ this.response,
168
+ this.responseURL,
169
+ this.responseType,
170
+ this
171
+ );
172
+ }
173
+ }
174
+ },
175
+ false
176
+ );
177
+ }
178
+ originalXHRSend.apply(this, arguments);
179
+ };
180
+ isInterceptorEnabled$1 = true;
181
+ },
182
+ // Unpatch XMLHttpRequest methods and remove the callbacks.
183
+ disableInterception() {
184
+ if (!isInterceptorEnabled$1) {
185
+ return;
186
+ }
187
+ isInterceptorEnabled$1 = false;
188
+ XMLHttpRequest.prototype.send = originalXHRSend;
189
+ XMLHttpRequest.prototype.open = originalXHROpen;
190
+ XMLHttpRequest.prototype.setRequestHeader = originalXHRSetRequestHeader;
191
+ responseCallback = null;
192
+ openCallback = null;
193
+ sendCallback = null;
194
+ headerReceivedCallback = null;
195
+ requestHeaderCallback = null;
196
+ }
197
+ };
198
+ const networkRequestsRegistry = getNetworkRequestsRegistry();
199
+ const getResponseSize = (request) => {
200
+ if (typeof request.response === "object") {
201
+ return request.response.size;
202
+ }
203
+ return request.response.length || 0;
204
+ };
205
+ const getResponseBody = async (request) => {
206
+ const responseType = request.responseType;
207
+ if (responseType === "" || responseType === "text") {
208
+ return request.responseText;
209
+ }
210
+ if (responseType === "blob") {
211
+ const contentType = request.getResponseHeader("Content-Type") || "";
212
+ if (contentType.startsWith("text/") || contentType.startsWith("application/json")) {
213
+ return new Promise((resolve) => {
214
+ const reader = new FileReader();
215
+ reader.onload = () => {
216
+ resolve(reader.result);
217
+ };
218
+ reader.readAsText(request.response);
219
+ });
220
+ }
221
+ }
222
+ return null;
223
+ };
224
+ const getInitiatorFromStack = () => {
225
+ try {
226
+ const stack = new Error().stack;
227
+ if (!stack) {
228
+ return { type: "other" };
229
+ }
230
+ const line = stack.split("\n")[9];
231
+ const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
232
+ if (match) {
233
+ return {
234
+ type: "script",
235
+ url: match[2],
236
+ lineNumber: parseInt(match[3]),
237
+ columnNumber: parseInt(match[4])
238
+ };
239
+ }
240
+ } catch {
241
+ }
242
+ return { type: "other" };
243
+ };
244
+ const READY_STATE_HEADERS_RECEIVED = 2;
245
+ const getNetworkInspector = (pluginClient) => {
246
+ const generateRequestId = () => {
247
+ return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
248
+ };
249
+ const handleRequestSend = (data, request) => {
250
+ const sendTime = Date.now();
251
+ const requestId = generateRequestId();
252
+ request._rozeniteRequestId = requestId;
253
+ const initiator = getInitiatorFromStack();
254
+ networkRequestsRegistry.addEntry(requestId, request);
255
+ let ttfb = 0;
256
+ pluginClient.send("request-sent", {
257
+ requestId,
258
+ timestamp: sendTime,
259
+ request: {
260
+ url: request._url,
261
+ method: request._method,
262
+ headers: request._headers,
263
+ postData: data
264
+ },
265
+ type: "XHR",
266
+ initiator
267
+ });
268
+ request.addEventListener("readystatechange", () => {
269
+ if (request.readyState === READY_STATE_HEADERS_RECEIVED) {
270
+ ttfb = Date.now() - sendTime;
271
+ }
272
+ });
273
+ request.addEventListener("load", () => {
274
+ pluginClient.send("response-received", {
275
+ requestId,
276
+ timestamp: Date.now(),
277
+ type: "XHR",
278
+ response: {
279
+ url: request._url,
280
+ status: request.status,
281
+ statusText: request.statusText,
282
+ headers: request.responseHeaders || {},
283
+ contentType: getContentType(request),
284
+ size: getResponseSize(request),
285
+ responseTime: Date.now()
286
+ }
287
+ });
288
+ });
289
+ request.addEventListener("loadend", () => {
290
+ pluginClient.send("request-completed", {
291
+ requestId,
292
+ timestamp: Date.now(),
293
+ duration: Date.now() - sendTime,
294
+ size: getResponseSize(request),
295
+ ttfb
296
+ });
297
+ });
298
+ request.addEventListener("error", () => {
299
+ pluginClient.send("request-failed", {
300
+ requestId,
301
+ timestamp: Date.now(),
302
+ type: "XHR",
303
+ error: "Failed",
304
+ canceled: false
305
+ });
306
+ });
307
+ request.addEventListener("abort", () => {
308
+ pluginClient.send("request-failed", {
309
+ requestId,
310
+ timestamp: Date.now(),
311
+ type: "XHR",
312
+ error: "Aborted",
313
+ canceled: true
314
+ });
315
+ });
316
+ };
317
+ const enable = () => {
318
+ XHRInterceptor.disableInterception();
319
+ XHRInterceptor.setSendCallback(handleRequestSend);
320
+ XHRInterceptor.enableInterception();
321
+ };
322
+ const disable = () => {
323
+ XHRInterceptor.disableInterception();
324
+ networkRequestsRegistry.clear();
325
+ };
326
+ const isEnabled = () => {
327
+ return XHRInterceptor.isInterceptorEnabled();
328
+ };
329
+ const enableSubscription = pluginClient.onMessage("network-enable", () => {
330
+ enable();
331
+ });
332
+ const disableSubscription = pluginClient.onMessage("network-disable", () => {
333
+ disable();
334
+ });
335
+ const handleBodySubscription = pluginClient.onMessage(
336
+ "get-response-body",
337
+ async ({ requestId }) => {
338
+ const request = networkRequestsRegistry.getEntry(requestId);
339
+ if (!request) {
340
+ return;
341
+ }
342
+ const body = await getResponseBody(request);
343
+ pluginClient.send("response-body", {
344
+ requestId,
345
+ body
346
+ });
347
+ }
348
+ );
349
+ const dispose = () => {
350
+ disable();
351
+ enableSubscription.remove();
352
+ disableSubscription.remove();
353
+ handleBodySubscription.remove();
354
+ };
355
+ return {
356
+ enable,
357
+ disable,
358
+ isEnabled,
359
+ dispose
360
+ };
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
+ };
689
+ const useNetworkActivityDevTools = () => {
690
+ const client = pluginBridge.useRozeniteDevToolsClient({
691
+ pluginId: "@rozenite/network-activity-plugin"
692
+ });
693
+ react.useEffect(() => {
694
+ if (!client) {
695
+ return;
696
+ }
697
+ const networkInspector = getNetworkInspector(client);
698
+ return () => {
699
+ networkInspector.dispose();
700
+ };
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]);
757
+ return client;
758
+ };
759
+ exports.useNetworkActivityDevTools = useNetworkActivityDevTools;