@rozenite/network-activity-plugin 1.1.0 → 1.3.0

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 (59) hide show
  1. package/.turbo/turbo-build.log +16 -0
  2. package/.turbo/turbo-lint.log +5 -0
  3. package/.turbo/turbo-typecheck.log +5 -0
  4. package/CHANGELOG.md +10 -0
  5. package/README.md +9 -0
  6. package/dist/App.html +1 -1
  7. package/dist/assets/{App-Kyi7zHUX.js → App-CGt4qucR.js} +12139 -6795
  8. package/dist/boot-recording.cjs +1087 -0
  9. package/dist/boot-recording.js +1086 -0
  10. package/dist/react-native.cjs +3 -0
  11. package/dist/react-native.d.ts +3 -0
  12. package/dist/react-native.js +5 -1
  13. package/dist/rozenite.json +1 -1
  14. package/dist/src/react-native/boot-recording.d.ts +41 -0
  15. package/dist/src/react-native/config.d.ts +7 -4
  16. package/dist/src/react-native/events-listener.d.ts +44 -0
  17. package/dist/src/react-native/http/http-inspector.d.ts +10 -0
  18. package/dist/src/react-native/http/http-utils.d.ts +15 -0
  19. package/dist/src/react-native/inspector.d.ts +7 -0
  20. package/dist/src/react-native/network-inspector.d.ts +16 -0
  21. package/dist/src/react-native/sse/sse-inspector.d.ts +4 -7
  22. package/dist/src/react-native/useHttpInspector.d.ts +3 -0
  23. package/dist/src/react-native/useSSEInspector.d.ts +3 -0
  24. package/dist/src/react-native/useWebSocketInspector.d.ts +3 -0
  25. package/dist/src/react-native/websocket/websocket-inspector.d.ts +4 -7
  26. package/dist/src/react-native/websocket/websocket-interceptor.d.ts +0 -1
  27. package/dist/src/shared/client.d.ts +3 -105
  28. package/dist/src/shared/http-events.d.ts +106 -0
  29. package/dist/src/shared/sse-events.d.ts +1 -1
  30. package/dist/src/ui/state/hooks.d.ts +3 -3
  31. package/dist/useNetworkActivityDevTools.cjs +116 -1017
  32. package/dist/useNetworkActivityDevTools.js +115 -1014
  33. package/package.json +16 -11
  34. package/react-native.ts +9 -0
  35. package/src/react-native/boot-recording.ts +90 -0
  36. package/src/react-native/config.ts +9 -4
  37. package/src/react-native/events-listener.ts +102 -0
  38. package/src/react-native/http/http-inspector.ts +174 -0
  39. package/src/react-native/http/http-utils.ts +216 -0
  40. package/src/react-native/inspector.ts +10 -0
  41. package/src/react-native/network-inspector.ts +78 -0
  42. package/src/react-native/sse/sse-inspector.ts +12 -10
  43. package/src/react-native/useHttpInspector.ts +59 -0
  44. package/src/react-native/useNetworkActivityDevTools.ts +60 -115
  45. package/src/react-native/useSSEInspector.ts +35 -0
  46. package/src/react-native/useWebSocketInspector.ts +35 -0
  47. package/src/react-native/websocket/websocket-inspector.ts +18 -10
  48. package/src/shared/client.ts +4 -140
  49. package/src/shared/http-events.ts +140 -0
  50. package/src/shared/sse-events.ts +1 -1
  51. package/src/ui/components/RequestList.tsx +9 -5
  52. package/src/ui/hooks/useCopyToClipboard.ts +9 -3
  53. package/src/ui/state/derived.ts +7 -3
  54. package/src/ui/state/store.ts +4 -3
  55. package/dist/src/react-native/http/network-inspector.d.ts +0 -8
  56. package/project.json +0 -12
  57. package/src/react-native/http/network-inspector.ts +0 -408
  58. package/tsconfig.tsbuildinfo +0 -1
  59. /package/src/react-native/websocket/{websocket-interceptor.d.ts → websocket-interceptor-types.d.ts} +0 -0
@@ -2,989 +2,137 @@
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);
11
- function safeStringify(data) {
12
- try {
13
- return typeof data === "string" ? data : JSON.stringify(data);
14
- } catch {
15
- return String(data);
16
- }
17
- }
18
- function getHttpHeader(headers, name) {
19
- const lowerName = name.toLowerCase();
20
- for (const key in headers) {
21
- if (key.toLowerCase() === lowerName) {
22
- return { value: headers[key], originalKey: key };
23
- }
24
- }
25
- return void 0;
26
- }
27
- function getContentTypeMime(headers) {
28
- const contentType = getHttpHeader(headers, "content-type");
29
- if (!contentType) {
30
- return void 0;
31
- }
32
- const { value } = contentType;
33
- const actualValue = Array.isArray(value) ? value[0] : value;
34
- return actualValue.split(";")[0].trim();
35
- }
36
- const getContentType = (request) => {
37
- const responseHeaders = request.responseHeaders;
38
- const responseType = request.responseType;
39
- const contentType = getContentTypeMime(responseHeaders || {});
40
- if (contentType) {
41
- return contentType;
42
- }
43
- switch (responseType) {
44
- case "arraybuffer":
45
- case "blob":
46
- return "application/octet-stream";
47
- case "text":
48
- case "":
49
- return "text/plain";
50
- case "json":
51
- return "application/json";
52
- case "document":
53
- return "text/html";
54
- }
55
- };
56
- const REQUEST_TTL = 1e3 * 60 * 5;
57
- const getNetworkRequestsRegistry = () => {
58
- const registry = /* @__PURE__ */ new Map();
59
- const trimRegistry = () => {
60
- const now = Date.now();
61
- registry.forEach((entry) => {
62
- if (now - entry.sentAt < REQUEST_TTL) {
63
- return;
64
- }
65
- registry.delete(entry.id);
66
- });
67
- };
68
- const addEntry = (id, request) => {
69
- trimRegistry();
70
- registry.set(id, {
71
- id,
72
- request,
73
- sentAt: Date.now()
74
- });
75
- };
76
- const getEntry = (id) => {
77
- var _a;
78
- return ((_a = registry.get(id)) == null ? void 0 : _a.request) ?? null;
79
- };
80
- const clear = () => {
81
- registry.clear();
82
- };
83
- return {
84
- addEntry,
85
- getEntry,
86
- clear
87
- };
88
- };
89
- function getBlobName(blob) {
90
- if (typeof (blob == null ? void 0 : blob.name) === "string") {
91
- return blob.name;
92
- }
93
- if ((blob == null ? void 0 : blob.data) && typeof blob.data.name === "string") {
94
- return blob.data.name;
95
- }
96
- return void 0;
97
- }
98
- function getFormDataEntries(formData) {
99
- if (!formData || typeof formData !== "object") {
100
- return [];
101
- }
102
- if (typeof formData.entries === "function") {
103
- return formData.entries();
104
- }
105
- if (Array.isArray(formData._parts)) {
106
- return formData._parts;
107
- }
108
- return [];
109
- }
110
- const XMLHttpRequest = global.XMLHttpRequest || window.XMLHttpRequest;
111
- const originalXHROpen = XMLHttpRequest.prototype.open;
112
- const originalXHRSend = XMLHttpRequest.prototype.send;
113
- const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
114
- let openCallback;
115
- let sendCallback;
116
- let requestHeaderCallback;
117
- let headerReceivedCallback;
118
- let responseCallback;
119
- let overrideCallback;
120
- let isInterceptorEnabled$1 = false;
121
- const XHRInterceptor = {
122
- /**
123
- * Invoked before XMLHttpRequest.open(...) is called.
124
- */
125
- setOpenCallback(callback) {
126
- openCallback = callback;
127
- },
128
- /**
129
- * Invoked before XMLHttpRequest.send(...) is called.
130
- */
131
- setSendCallback(callback) {
132
- sendCallback = callback;
133
- },
134
- /**
135
- * Invoked after xhr's readyState becomes xhr.HEADERS_RECEIVED.
136
- */
137
- setHeaderReceivedCallback(callback) {
138
- headerReceivedCallback = callback;
139
- },
140
- /**
141
- * Invoked after xhr's readyState becomes xhr.DONE.
142
- */
143
- setResponseCallback(callback) {
144
- responseCallback = callback;
145
- },
146
- /**
147
- * Invoked before XMLHttpRequest.setRequestHeader(...) is called.
148
- */
149
- setRequestHeaderCallback(callback) {
150
- requestHeaderCallback = callback;
151
- },
152
- /**
153
- * Invoked before XMLHttpRequest.send(...) is called.
154
- */
155
- setOverrideCallback(callback) {
156
- overrideCallback = callback;
157
- },
158
- isInterceptorEnabled() {
159
- return isInterceptorEnabled$1;
160
- },
161
- enableInterception() {
162
- if (isInterceptorEnabled$1) {
163
- return;
164
- }
165
- XMLHttpRequest.prototype.open = function(method, url) {
166
- if (openCallback) {
167
- openCallback(method, url, this);
168
- }
169
- originalXHROpen.apply(this, arguments);
170
- };
171
- XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
172
- if (requestHeaderCallback) {
173
- requestHeaderCallback(header, value, this);
174
- }
175
- originalXHRSetRequestHeader.apply(this, arguments);
176
- };
177
- XMLHttpRequest.prototype.send = function(data) {
178
- if (sendCallback) {
179
- sendCallback(data, this);
180
- }
181
- if (overrideCallback) {
182
- overrideCallback(this);
183
- }
184
- if (this.addEventListener) {
185
- this.addEventListener(
186
- "readystatechange",
187
- () => {
188
- if (!isInterceptorEnabled$1) {
189
- return;
190
- }
191
- if (this.readyState === this.HEADERS_RECEIVED) {
192
- const contentTypeString = this.getResponseHeader("Content-Type");
193
- const contentLengthString = this.getResponseHeader("Content-Length");
194
- let responseContentType, responseSize;
195
- if (contentTypeString) {
196
- responseContentType = contentTypeString.split(";")[0];
197
- }
198
- if (contentLengthString) {
199
- responseSize = parseInt(contentLengthString, 10);
200
- }
201
- if (headerReceivedCallback) {
202
- headerReceivedCallback(
203
- responseContentType,
204
- responseSize,
205
- this.getAllResponseHeaders(),
206
- this
207
- );
208
- }
209
- }
210
- if (this.readyState === this.DONE) {
211
- if (responseCallback) {
212
- responseCallback(
213
- this.status,
214
- this.timeout,
215
- this.response,
216
- this.responseURL,
217
- this.responseType,
218
- this
219
- );
220
- }
221
- }
222
- },
223
- false
224
- );
225
- }
226
- originalXHRSend.apply(this, arguments);
227
- };
228
- isInterceptorEnabled$1 = true;
229
- },
230
- // Unpatch XMLHttpRequest methods and remove the callbacks.
231
- disableInterception() {
232
- if (!isInterceptorEnabled$1) {
233
- return;
234
- }
235
- isInterceptorEnabled$1 = false;
236
- XMLHttpRequest.prototype.send = originalXHRSend;
237
- XMLHttpRequest.prototype.open = originalXHROpen;
238
- XMLHttpRequest.prototype.setRequestHeader = originalXHRSetRequestHeader;
239
- responseCallback = null;
240
- openCallback = null;
241
- sendCallback = null;
242
- headerReceivedCallback = null;
243
- requestHeaderCallback = null;
244
- overrideCallback = null;
245
- }
246
- };
247
- const getStringSizeInBytes = (value) => {
248
- return new TextEncoder().encode(value).length;
249
- };
250
- const splitSetCookieHeaderByComma = (header) => {
251
- const regex = /(?:^|,\s)([^=;,]+=[^;]+(?:;[^,]*)*)/g;
252
- const matches = [];
253
- let match;
254
- while ((match = regex.exec(header)) !== null) {
255
- matches.push(match[1].trim());
256
- }
257
- return matches;
258
- };
259
- const applyReactNativeResponseHeadersLogic = (headers) => {
260
- const parsedHeaders = { ...headers };
261
- const setCookieHeader = getHttpHeader(headers, "set-cookie");
262
- if (setCookieHeader) {
263
- const { value, originalKey } = setCookieHeader;
264
- const cookies = splitSetCookieHeaderByComma(value);
265
- parsedHeaders[originalKey] = cookies.length > 0 ? cookies : value;
266
- }
267
- return parsedHeaders;
268
- };
269
- const isBlob = (value) => value instanceof Blob;
270
- const isArrayBuffer = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
271
- const isFormData = (value) => value instanceof FormData;
272
- const isNullOrUndefined = (value) => value === null || value === void 0;
273
- const createOverridesRegistry = () => {
274
- let overrides = /* @__PURE__ */ new Map();
275
- const setOverrides = (newOverrides) => {
276
- overrides = new Map(newOverrides);
277
- };
278
- const getOverrideForUrl = (url) => {
279
- return overrides.get(url);
280
- };
281
- return {
282
- setOverrides,
283
- getOverrideForUrl
284
- };
285
- };
286
- let registryInstance = null;
287
- const getOverridesRegistry = () => {
288
- if (!registryInstance) {
289
- registryInstance = createOverridesRegistry();
290
- }
291
- return registryInstance;
292
- };
293
- const networkRequestsRegistry = getNetworkRequestsRegistry();
294
- const overridesRegistry$1 = getOverridesRegistry();
295
- const getBinaryPostData = (body) => ({
296
- type: "binary",
297
- value: {
298
- size: body.size,
299
- type: body.type,
300
- name: getBlobName(body)
301
- }
302
- });
303
- const getArrayBufferPostData = (body) => ({
304
- type: "binary",
305
- value: {
306
- size: body.byteLength
307
- }
308
- });
309
- const getTextPostData = (body) => ({
310
- type: "text",
311
- value: safeStringify(body)
312
- });
313
- const getFormDataPostData = (body) => ({
314
- type: "form-data",
315
- value: getFormDataEntries(body).reduce(
316
- (acc, [key, value]) => {
317
- if (isBlob(value)) {
318
- acc[key] = getBinaryPostData(value);
319
- } else if (isArrayBuffer(value)) {
320
- acc[key] = getArrayBufferPostData(value);
321
- } else {
322
- acc[key] = getTextPostData(value);
323
- }
324
- return acc;
325
- },
326
- {}
327
- )
328
- });
329
- const getRequestBody = (body) => {
330
- if (isNullOrUndefined(body)) {
331
- return body;
332
- }
333
- if (isBlob(body)) {
334
- return getBinaryPostData(body);
335
- }
336
- if (isArrayBuffer(body)) {
337
- return getArrayBufferPostData(body);
338
- }
339
- if (isFormData(body)) {
340
- return getFormDataPostData(body);
341
- }
342
- return getTextPostData(body);
343
- };
344
- const getResponseSize = (request) => {
345
- try {
346
- const { responseType, response } = request;
347
- if (response === null) {
348
- return 0;
349
- }
350
- if (responseType === "" || responseType === "text") {
351
- return getStringSizeInBytes(request.responseText);
352
- }
353
- if (responseType === "json") {
354
- return getStringSizeInBytes(safeStringify(response));
355
- }
356
- if (responseType === "blob") {
357
- return response.size;
358
- }
359
- if (responseType === "arraybuffer") {
360
- return response.byteLength;
361
- }
362
- return 0;
363
- } catch {
364
- return null;
365
- }
366
- };
367
- const getResponseBody = async (request) => {
368
- const responseType = request.responseType;
369
- if (responseType === "" || responseType === "text") {
370
- return request.responseText;
371
- }
372
- if (responseType === "blob") {
373
- const contentType = request.getResponseHeader("Content-Type") || "";
374
- if (contentType.startsWith("text/") || contentType.startsWith("application/json")) {
375
- return new Promise((resolve) => {
376
- const reader = new FileReader();
377
- reader.onload = () => {
378
- resolve(reader.result);
379
- };
380
- reader.readAsText(request.response);
381
- });
382
- }
383
- }
384
- if (responseType === "json") {
385
- return safeStringify(request.response);
386
- }
387
- return null;
388
- };
389
- const getInitiatorFromStack = () => {
390
- try {
391
- const stack = new Error().stack;
392
- if (!stack) {
393
- return { type: "other" };
394
- }
395
- const line = stack.split("\n")[9];
396
- const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
397
- if (match) {
398
- return {
399
- type: "script",
400
- url: match[2],
401
- lineNumber: parseInt(match[3]),
402
- columnNumber: parseInt(match[4])
403
- };
404
- }
405
- } catch {
406
- }
407
- return { type: "other" };
408
- };
409
- const READY_STATE_HEADERS_RECEIVED = 2;
410
- const getNetworkInspector = (pluginClient) => {
411
- const generateRequestId = () => {
412
- return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
413
- };
414
- const handleRequestSend = (data, request) => {
415
- const sendTime = Date.now();
416
- const requestId = generateRequestId();
417
- request._rozeniteRequestId = requestId;
418
- const initiator = getInitiatorFromStack();
419
- networkRequestsRegistry.addEntry(requestId, request);
420
- let ttfb = 0;
421
- pluginClient.send("request-sent", {
422
- requestId,
423
- timestamp: sendTime,
424
- request: {
425
- url: request._url,
426
- method: request._method,
427
- headers: request._headers,
428
- postData: getRequestBody(data)
429
- },
430
- type: "XHR",
431
- initiator
432
- });
433
- request.addEventListener("progress", (event) => {
434
- pluginClient.send("request-progress", {
435
- requestId,
436
- timestamp: Date.now(),
437
- loaded: event.loaded,
438
- total: event.total,
439
- lengthComputable: event.lengthComputable
440
- });
441
- });
442
- request.addEventListener("readystatechange", () => {
443
- if (request.readyState === READY_STATE_HEADERS_RECEIVED) {
444
- ttfb = Date.now() - sendTime;
445
- }
446
- });
447
- request.addEventListener("load", () => {
448
- pluginClient.send("response-received", {
449
- requestId,
450
- timestamp: Date.now(),
451
- type: "XHR",
452
- response: {
453
- url: request._url,
454
- status: request.status,
455
- statusText: request.statusText,
456
- headers: applyReactNativeResponseHeadersLogic(
457
- request.responseHeaders || {}
458
- ),
459
- contentType: getContentType(request),
460
- size: getResponseSize(request),
461
- responseTime: Date.now()
462
- }
463
- });
464
- });
465
- request.addEventListener("loadend", () => {
466
- pluginClient.send("request-completed", {
467
- requestId,
468
- timestamp: Date.now(),
469
- duration: Date.now() - sendTime,
470
- size: getResponseSize(request),
471
- ttfb
472
- });
473
- });
474
- request.addEventListener("error", () => {
475
- pluginClient.send("request-failed", {
476
- requestId,
477
- timestamp: Date.now(),
478
- type: "XHR",
479
- error: "Failed",
480
- canceled: false
481
- });
482
- });
483
- request.addEventListener("abort", () => {
484
- pluginClient.send("request-failed", {
485
- requestId,
486
- timestamp: Date.now(),
487
- type: "XHR",
488
- error: "Aborted",
489
- canceled: true
490
- });
491
- });
492
- request.addEventListener("timeout", () => {
493
- pluginClient.send("request-failed", {
494
- requestId,
495
- timestamp: Date.now(),
496
- type: "XHR",
497
- error: "Timeout",
498
- canceled: false
499
- });
500
- });
501
- };
502
- const handleRequestOverride = (request) => {
503
- const override = overridesRegistry$1.getOverrideForUrl(
504
- request._url
505
- );
506
- if (!override) {
5
+ const bootRecording = require("./boot-recording.cjs");
6
+ const overridesRegistry = bootRecording.getOverridesRegistry();
7
+ const useHttpInspector = (client, httpInspector, isEnabled, isRecordingEnabled) => {
8
+ react.useEffect(() => {
9
+ if (!client || !isEnabled) {
507
10
  return;
508
11
  }
509
- request.addEventListener("readystatechange", () => {
510
- if (override.body !== void 0) {
511
- Object.defineProperty(request, "responseType", {
512
- writable: true
513
- });
514
- Object.defineProperty(request, "response", {
515
- writable: true
516
- });
517
- Object.defineProperty(request, "responseText", {
518
- writable: true
519
- });
520
- const contentType = getContentType(request);
521
- if (contentType === "application/json") {
522
- request.responseType = "json";
523
- } else if (contentType === "text/plain") {
524
- request.responseType = "text";
12
+ const networkRequestsRegistry = httpInspector.getNetworkRequestsRegistry();
13
+ const subscriptions = [
14
+ client.onMessage("network-enable", () => {
15
+ httpInspector.enable();
16
+ }),
17
+ client.onMessage("network-disable", () => {
18
+ httpInspector.disable();
19
+ }),
20
+ client.onMessage("set-overrides", (data) => {
21
+ overridesRegistry.setOverrides(data.overrides);
22
+ }),
23
+ client.onMessage("get-response-body", async ({ requestId }) => {
24
+ const request = networkRequestsRegistry.getEntry(requestId);
25
+ if (!request) {
26
+ return;
525
27
  }
526
- request.response = override.body;
527
- request.responseText = override.body;
528
- }
529
- if (override.status !== void 0) {
530
- Object.defineProperty(request, "status", {
531
- writable: true
28
+ const body = await bootRecording.getResponseBody(request);
29
+ client.send("response-body", {
30
+ requestId,
31
+ body
532
32
  });
533
- request.status = override.status;
534
- }
535
- });
536
- };
537
- const enable = () => {
538
- XHRInterceptor.disableInterception();
539
- XHRInterceptor.setSendCallback(handleRequestSend);
540
- XHRInterceptor.setOverrideCallback(handleRequestOverride);
541
- XHRInterceptor.enableInterception();
542
- };
543
- const disable = () => {
544
- XHRInterceptor.disableInterception();
545
- networkRequestsRegistry.clear();
546
- };
547
- const isEnabled = () => {
548
- return XHRInterceptor.isInterceptorEnabled();
549
- };
550
- const enableSubscription = pluginClient.onMessage("network-enable", () => {
551
- enable();
552
- });
553
- const disableSubscription = pluginClient.onMessage("network-disable", () => {
554
- disable();
555
- });
556
- const handleBodySubscription = pluginClient.onMessage(
557
- "get-response-body",
558
- async ({ requestId }) => {
559
- const request = networkRequestsRegistry.getEntry(requestId);
560
- if (!request) {
561
- return;
562
- }
563
- const body = await getResponseBody(request);
564
- pluginClient.send("response-body", {
565
- requestId,
566
- body
567
- });
33
+ })
34
+ ];
35
+ if (isRecordingEnabled) {
36
+ httpInspector.enable();
568
37
  }
569
- );
570
- const dispose = () => {
571
- disable();
572
- enableSubscription.remove();
573
- disableSubscription.remove();
574
- handleBodySubscription.remove();
575
- };
576
- return {
577
- enable,
578
- disable,
579
- isEnabled,
580
- dispose
581
- };
582
- };
583
- const getWebSocketInterceptor = () => {
584
- if (reactNative.Platform.constants.reactNativeVersion.minor >= 79) {
585
- return WebSocketInterceptor__default.default;
586
- } else {
587
- const WebSocketInterceptorPreRN079 = WebSocketInterceptor__default.default;
588
- return {
589
- ...WebSocketInterceptorPreRN079,
590
- setOnMessageCallback: (callback) => {
591
- WebSocketInterceptorPreRN079.setOnMessageCallback((socketId, data) => {
592
- callback(data, socketId);
593
- });
594
- },
595
- setOnCloseCallback: (callback) => {
596
- WebSocketInterceptorPreRN079.setOnCloseCallback((error, socketId) => {
597
- callback(socketId, error);
598
- });
599
- },
600
- setOnErrorCallback: (callback) => {
601
- WebSocketInterceptorPreRN079.setOnErrorCallback((error, socketId) => {
602
- callback(socketId, error);
603
- });
604
- }
38
+ return () => {
39
+ subscriptions.forEach((subscription) => subscription.remove());
40
+ httpInspector.dispose();
605
41
  };
606
- }
42
+ }, [client, httpInspector, isEnabled, isRecordingEnabled]);
607
43
  };
608
- const getWebSocketInspector = () => {
609
- const eventEmitter = nanoevents.createNanoEvents();
610
- const socketUrlMap = /* @__PURE__ */ new Map();
611
- const webSocketInterceptor = getWebSocketInterceptor();
612
- return {
613
- enable: () => {
614
- webSocketInterceptor.setConnectCallback(
615
- (url, protocols, options, socketId) => {
616
- socketUrlMap.set(socketId, url);
617
- const event = {
618
- type: "websocket-connect",
619
- url,
620
- socketId,
621
- timestamp: Date.now(),
622
- protocols,
623
- options
624
- };
625
- eventEmitter.emit("websocket-connect", event);
626
- }
627
- );
628
- webSocketInterceptor.setCloseCallback(
629
- (code, reason, socketId) => {
630
- const url = socketUrlMap.get(socketId);
631
- if (!url) {
632
- return;
633
- }
634
- const event = {
635
- type: "websocket-close",
636
- url,
637
- socketId,
638
- timestamp: Date.now(),
639
- code: code || 0,
640
- reason: reason || void 0
641
- };
642
- eventEmitter.emit("websocket-close", event);
643
- socketUrlMap.delete(socketId);
644
- }
645
- );
646
- webSocketInterceptor.setOnMessageCallback(
647
- (data, socketId) => {
648
- const url = socketUrlMap.get(socketId);
649
- if (!url) {
650
- return;
651
- }
652
- const event = {
653
- type: "websocket-message-received",
654
- url,
655
- socketId,
656
- timestamp: Date.now(),
657
- data,
658
- messageType: typeof data === "string" ? "text" : "binary"
659
- };
660
- eventEmitter.emit("websocket-message-received", event);
661
- }
662
- );
663
- webSocketInterceptor.setOnErrorCallback(
664
- (error, socketId) => {
665
- const url = socketUrlMap.get(socketId);
666
- if (!url) {
667
- return;
668
- }
669
- const event = {
670
- type: "websocket-error",
671
- url,
672
- socketId,
673
- timestamp: Date.now(),
674
- error
675
- };
676
- eventEmitter.emit("websocket-error", event);
677
- }
678
- );
679
- webSocketInterceptor.setSendCallback((data, socketId) => {
680
- const url = socketUrlMap.get(socketId);
681
- if (!url) {
682
- return;
683
- }
684
- const event = {
685
- type: "websocket-message-sent",
686
- url,
687
- socketId,
688
- timestamp: Date.now(),
689
- data,
690
- messageType: typeof data === "string" ? "text" : "binary"
691
- };
692
- eventEmitter.emit("websocket-message-sent", event);
693
- });
694
- webSocketInterceptor.setOnOpenCallback((socketId) => {
695
- const url = socketUrlMap.get(socketId);
696
- if (!url) {
697
- return;
698
- }
699
- const event = {
700
- type: "websocket-open",
701
- url,
702
- socketId,
703
- timestamp: Date.now()
704
- };
705
- eventEmitter.emit("websocket-open", event);
706
- });
707
- webSocketInterceptor.setOnCloseCallback(
708
- (error, socketId) => {
709
- const url = socketUrlMap.get(socketId);
710
- if (!url) {
711
- return;
712
- }
713
- const event = {
714
- type: "websocket-close",
715
- url,
716
- socketId,
717
- timestamp: Date.now(),
718
- code: error.code,
719
- reason: error.reason
720
- };
721
- eventEmitter.emit("websocket-close", event);
722
- socketUrlMap.delete(socketId);
723
- }
724
- );
725
- webSocketInterceptor.enableInterception();
726
- },
727
- disable: () => {
728
- webSocketInterceptor.disableInterception();
729
- },
730
- isEnabled: () => webSocketInterceptor.isInterceptorEnabled(),
731
- dispose: () => {
732
- eventEmitter.events = {};
733
- socketUrlMap.clear();
734
- },
735
- on: (event, callback) => eventEmitter.on(event, callback)
736
- };
737
- };
738
- let connectCallback;
739
- let messageCallback;
740
- let errorCallback;
741
- let openEventCallback;
742
- let closeCallback;
743
- let isInterceptorEnabled = false;
744
- const eventSourceClass = eventSource.getEventSource();
745
- const originalOpen = eventSourceClass.prototype.open;
746
- const originalDispatch = eventSourceClass.prototype.dispatch;
747
- const BUILT_IN_EVENT_TYPES = /* @__PURE__ */ new Set(["open", "error", "close", "done"]);
748
- const SSEInterceptor = {
749
- /**
750
- * Invoked when EventSource.open() is called (connection attempt starting).
751
- */
752
- setConnectCallback(callback) {
753
- connectCallback = callback;
754
- },
755
- /**
756
- * Invoked when a message event is received.
757
- */
758
- setMessageCallback(callback) {
759
- messageCallback = callback;
760
- },
761
- /**
762
- * Invoked when an error event occurs.
763
- */
764
- setErrorCallback(callback) {
765
- errorCallback = callback;
766
- },
767
- /**
768
- * Invoked when the connection is successfully opened (open event fired).
769
- */
770
- setOpenEventCallback(callback) {
771
- openEventCallback = callback;
772
- },
773
- /**
774
- * Invoked when the connection is closed.
775
- */
776
- setCloseCallback(callback) {
777
- closeCallback = callback;
778
- },
779
- isInterceptorEnabled() {
780
- return isInterceptorEnabled;
781
- },
782
- enableInterception() {
783
- if (isInterceptorEnabled) {
44
+ const useWebSocketInspector = (client, websocketInspector, isEnabled, isRecordingEnabled) => {
45
+ react.useEffect(() => {
46
+ if (!client || !isEnabled) {
784
47
  return;
785
48
  }
786
- eventSourceClass.prototype.open = function() {
787
- if (connectCallback) {
788
- connectCallback(this.url, this);
789
- }
790
- this.addEventListener("open", (event) => {
791
- if (openEventCallback) {
792
- openEventCallback(event, this);
793
- }
794
- });
795
- this.addEventListener(
796
- "error",
797
- (event) => {
798
- if (errorCallback) {
799
- errorCallback(event, this);
800
- }
801
- }
802
- );
803
- this.addEventListener("close", (event) => {
804
- if (closeCallback) {
805
- closeCallback(event, this);
806
- }
807
- });
808
- return originalOpen.call(this);
809
- };
810
- eventSourceClass.prototype.dispatch = function(eventType, data) {
811
- if (!BUILT_IN_EVENT_TYPES.has(eventType)) {
812
- if (messageCallback) {
813
- messageCallback(data, this);
814
- }
815
- }
816
- return originalDispatch.call(this, eventType, data);
49
+ const subscriptions = [
50
+ client.onMessage("network-enable", () => {
51
+ websocketInspector.enable();
52
+ }),
53
+ client.onMessage("network-disable", () => {
54
+ websocketInspector.disable();
55
+ })
56
+ ];
57
+ if (isRecordingEnabled) {
58
+ websocketInspector.enable();
59
+ }
60
+ return () => {
61
+ subscriptions.forEach((subscription) => subscription.remove());
62
+ websocketInspector.dispose();
817
63
  };
818
- isInterceptorEnabled = true;
819
- },
820
- // Unpatch EventSource open method and remove the callbacks.
821
- disableInterception() {
822
- if (!isInterceptorEnabled) {
64
+ }, [client, websocketInspector, isEnabled, isRecordingEnabled]);
65
+ };
66
+ const useSSEInspector = (client, sseInspector, isEnabled, isRecordingEnabled) => {
67
+ react.useEffect(() => {
68
+ if (!client || !isEnabled) {
823
69
  return;
824
70
  }
825
- isInterceptorEnabled = false;
826
- eventSourceClass.prototype.open = originalOpen;
827
- eventSourceClass.prototype.dispatch = originalDispatch;
828
- connectCallback = null;
829
- messageCallback = null;
830
- errorCallback = null;
831
- openEventCallback = null;
832
- closeCallback = null;
833
- }
834
- };
835
- const getSSEInspector = () => {
836
- const eventEmitter = nanoevents.createNanoEvents();
837
- const getRequestId = (eventSource2) => {
838
- var _a;
839
- const requestId = (_a = eventSource2._xhr) == null ? void 0 : _a._rozeniteRequestId;
840
- if (!requestId) {
841
- return null;
71
+ const subscriptions = [
72
+ client.onMessage("network-enable", () => {
73
+ sseInspector.enable();
74
+ }),
75
+ client.onMessage("network-disable", () => {
76
+ sseInspector.disable();
77
+ })
78
+ ];
79
+ if (isRecordingEnabled) {
80
+ sseInspector.enable();
842
81
  }
843
- return requestId;
844
- };
845
- return {
846
- enable: () => {
847
- SSEInterceptor.setOpenEventCallback((_, eventSource2) => {
848
- const sseEventSource = eventSource2;
849
- const requestId = getRequestId(sseEventSource);
850
- if (!requestId) {
851
- return;
852
- }
853
- const sseXhr = sseEventSource._xhr;
854
- const event = {
855
- type: "sse-open",
856
- requestId,
857
- timestamp: Date.now(),
858
- response: {
859
- url: sseXhr._url,
860
- status: sseXhr.status,
861
- statusText: sseXhr.statusText,
862
- headers: sseXhr.responseHeaders || {},
863
- contentType: getContentType(sseXhr),
864
- size: 0,
865
- responseTime: Date.now()
866
- }
867
- };
868
- eventEmitter.emit("sse-open", event);
869
- });
870
- SSEInterceptor.setMessageCallback((messageEvent, eventSource2) => {
871
- const sseEventSource = eventSource2;
872
- const requestId = getRequestId(sseEventSource);
873
- if (!requestId) {
874
- return;
875
- }
876
- const event = {
877
- type: "sse-message",
878
- requestId,
879
- timestamp: Date.now(),
880
- payload: {
881
- type: messageEvent.type,
882
- data: messageEvent.data || ""
883
- }
884
- };
885
- eventEmitter.emit("sse-message", event);
886
- });
887
- SSEInterceptor.setErrorCallback((errorEvent, eventSource2) => {
888
- const sseEventSource = eventSource2;
889
- const requestId = getRequestId(sseEventSource);
890
- if (!requestId) {
891
- return;
892
- }
893
- const event = {
894
- type: "sse-error",
895
- requestId,
896
- timestamp: Date.now(),
897
- error: {
898
- type: errorEvent.type,
899
- message: errorEvent.type === "timeout" ? "Timeout" : errorEvent.message
900
- }
901
- };
902
- eventEmitter.emit("sse-error", event);
903
- });
904
- SSEInterceptor.setCloseCallback((_, eventSource2) => {
905
- const sseEventSource = eventSource2;
906
- const requestId = getRequestId(sseEventSource);
907
- if (!requestId) {
908
- return;
909
- }
910
- const event = {
911
- type: "sse-close",
912
- requestId,
913
- timestamp: Date.now()
914
- };
915
- eventEmitter.emit("sse-close", event);
916
- });
917
- SSEInterceptor.enableInterception();
918
- },
919
- disable: () => {
920
- SSEInterceptor.disableInterception();
921
- },
922
- isEnabled: () => SSEInterceptor.isInterceptorEnabled(),
923
- dispose: () => {
924
- SSEInterceptor.disableInterception();
925
- eventEmitter.events = {};
926
- },
927
- on: (event, callback) => eventEmitter.on(event, callback)
928
- };
929
- };
930
- const DEFAULT_CONFIG = {
931
- inspectors: {
932
- http: true,
933
- websocket: true,
934
- sse: true
935
- },
936
- clientUISettings: {
937
- showUrlAsName: false
938
- }
939
- };
940
- const validateConfig = (config) => {
941
- const inspectors = config.inspectors;
942
- if (!inspectors) {
943
- return;
944
- }
945
- if (inspectors.sse && !inspectors.http) {
946
- throw new Error("SSE inspector requires HTTP inspector to be enabled.");
947
- }
82
+ return () => {
83
+ subscriptions.forEach((subscription) => subscription.remove());
84
+ sseInspector.dispose();
85
+ };
86
+ }, [client, sseInspector, isEnabled, isRecordingEnabled]);
948
87
  };
949
- const overridesRegistry = getOverridesRegistry();
950
- const useNetworkActivityDevTools = (config = DEFAULT_CONFIG) => {
951
- var _a, _b, _c, _d;
88
+ const inspectorsConfig = bootRecording.createNetworkInspectorsConfiguration();
89
+ const useNetworkActivityDevTools = (config = bootRecording.DEFAULT_CONFIG) => {
952
90
  const isRecordingEnabledRef = react.useRef(false);
953
91
  const client = pluginBridge.useRozeniteDevToolsClient({
954
92
  pluginId: "@rozenite/network-activity-plugin"
955
93
  });
956
- const isHttpInspectorEnabled = ((_a = config.inspectors) == null ? void 0 : _a.http) ?? true;
957
- const isWebSocketInspectorEnabled = ((_b = config.inspectors) == null ? void 0 : _b.websocket) ?? true;
958
- const isSSEInspectorEnabled = ((_c = config.inspectors) == null ? void 0 : _c.sse) ?? true;
959
- const showUrlAsName = (_d = config.clientUISettings) == null ? void 0 : _d.showUrlAsName;
94
+ const isHttpInspectorEnabled = config.inspectors?.http ?? true;
95
+ const isWebSocketInspectorEnabled = config.inspectors?.websocket ?? true;
96
+ const isSSEInspectorEnabled = config.inspectors?.sse ?? true;
97
+ const showUrlAsName = config.clientUISettings?.showUrlAsName;
98
+ const { eventsListener, networkInspector } = inspectorsConfig;
960
99
  react.useEffect(() => {
961
100
  if (!client) {
962
101
  return;
963
102
  }
964
- validateConfig(config);
103
+ bootRecording.validateConfig(config);
965
104
  }, [config]);
966
105
  react.useEffect(() => {
967
106
  if (!client) {
968
107
  return;
969
108
  }
970
109
  const sendClientUISettings = () => {
971
- var _a2;
972
110
  client.send("client-ui-settings", {
973
111
  settings: {
974
- showUrlAsName: showUrlAsName ?? ((_a2 = DEFAULT_CONFIG.clientUISettings) == null ? void 0 : _a2.showUrlAsName)
112
+ showUrlAsName: showUrlAsName ?? bootRecording.DEFAULT_CONFIG.clientUISettings?.showUrlAsName
975
113
  }
976
114
  });
977
115
  };
978
116
  const subscriptions = [
979
117
  client.onMessage("network-enable", () => {
980
118
  isRecordingEnabledRef.current = true;
119
+ eventsListener.connect(client.send, (message) => {
120
+ const type = message.type;
121
+ if (bootRecording.isHttpEvent(type)) {
122
+ return isHttpInspectorEnabled;
123
+ }
124
+ if (bootRecording.isWebSocketEvent(type)) {
125
+ return isWebSocketInspectorEnabled;
126
+ }
127
+ if (bootRecording.isSSEEvent(type)) {
128
+ return isSSEInspectorEnabled;
129
+ }
130
+ return true;
131
+ });
981
132
  }),
982
133
  client.onMessage("network-disable", () => {
983
134
  isRecordingEnabledRef.current = false;
984
135
  }),
985
- client.onMessage("set-overrides", (data) => {
986
- overridesRegistry.setOverrides(data.overrides);
987
- }),
988
136
  client.onMessage("get-client-ui-settings", () => {
989
137
  sendClientUISettings();
990
138
  })
@@ -993,80 +141,31 @@ const useNetworkActivityDevTools = (config = DEFAULT_CONFIG) => {
993
141
  return () => {
994
142
  subscriptions.forEach((subscription) => subscription.remove());
995
143
  };
996
- }, [client, showUrlAsName]);
997
- react.useEffect(() => {
998
- if (!client || !isHttpInspectorEnabled) {
999
- return;
1000
- }
1001
- const networkInspector = getNetworkInspector(client);
1002
- if (isRecordingEnabledRef.current) {
1003
- networkInspector.enable();
1004
- }
1005
- return () => {
1006
- networkInspector.dispose();
1007
- };
1008
- }, [client, isHttpInspectorEnabled]);
1009
- react.useEffect(() => {
1010
- if (!client || !isWebSocketInspectorEnabled) {
1011
- return;
1012
- }
1013
- const eventsToForward = [
1014
- "websocket-connect",
1015
- "websocket-open",
1016
- "websocket-close",
1017
- "websocket-message-sent",
1018
- "websocket-message-received",
1019
- "websocket-error",
1020
- "websocket-connection-status-changed"
1021
- ];
1022
- const websocketInspector = getWebSocketInspector();
1023
- eventsToForward.forEach((event) => {
1024
- websocketInspector.on(event, (event2) => {
1025
- client.send(event2.type, event2);
1026
- });
1027
- });
1028
- client.onMessage("network-enable", () => {
1029
- websocketInspector.enable();
1030
- });
1031
- client.onMessage("network-disable", () => {
1032
- websocketInspector.disable();
1033
- });
1034
- if (isRecordingEnabledRef.current) {
1035
- websocketInspector.enable();
1036
- }
1037
- return () => {
1038
- websocketInspector.dispose();
1039
- };
1040
- }, [client, isWebSocketInspectorEnabled]);
1041
- react.useEffect(() => {
1042
- if (!client || !isSSEInspectorEnabled) {
1043
- return;
1044
- }
1045
- const eventsToForward = [
1046
- "sse-open",
1047
- "sse-message",
1048
- "sse-error",
1049
- "sse-close"
1050
- ];
1051
- const sseInspector = getSSEInspector();
1052
- eventsToForward.forEach((event) => {
1053
- sseInspector.on(event, (event2) => {
1054
- client.send(event2.type, event2);
1055
- });
1056
- });
1057
- client.onMessage("network-enable", () => {
1058
- sseInspector.enable();
1059
- });
1060
- client.onMessage("network-disable", () => {
1061
- sseInspector.disable();
1062
- });
1063
- if (isRecordingEnabledRef.current) {
1064
- sseInspector.enable();
1065
- }
1066
- return () => {
1067
- sseInspector.dispose();
1068
- };
1069
- }, [client, isSSEInspectorEnabled]);
144
+ }, [
145
+ client,
146
+ showUrlAsName,
147
+ isHttpInspectorEnabled,
148
+ isWebSocketInspectorEnabled,
149
+ isSSEInspectorEnabled
150
+ ]);
151
+ useHttpInspector(
152
+ client,
153
+ networkInspector.http,
154
+ isHttpInspectorEnabled,
155
+ isRecordingEnabledRef.current
156
+ );
157
+ useWebSocketInspector(
158
+ client,
159
+ networkInspector.websocket,
160
+ isWebSocketInspectorEnabled,
161
+ isRecordingEnabledRef.current
162
+ );
163
+ useSSEInspector(
164
+ client,
165
+ networkInspector.sse,
166
+ isSSEInspectorEnabled,
167
+ isRecordingEnabledRef.current
168
+ );
1070
169
  return client;
1071
170
  };
1072
171
  exports.useNetworkActivityDevTools = useNetworkActivityDevTools;