@rozenite/network-activity-plugin 1.1.0 → 1.2.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 (50) hide show
  1. package/README.md +9 -0
  2. package/dist/App.html +1 -1
  3. package/dist/assets/{App-Kyi7zHUX.js → App-o_iVtD-5.js} +10 -4
  4. package/dist/boot-recording.cjs +1092 -0
  5. package/dist/boot-recording.js +1091 -0
  6. package/dist/react-native.cjs +3 -0
  7. package/dist/react-native.d.ts +3 -0
  8. package/dist/react-native.js +5 -1
  9. package/dist/rozenite.json +1 -1
  10. package/dist/src/react-native/boot-recording.d.ts +41 -0
  11. package/dist/src/react-native/config.d.ts +7 -4
  12. package/dist/src/react-native/events-listener.d.ts +44 -0
  13. package/dist/src/react-native/http/http-inspector.d.ts +10 -0
  14. package/dist/src/react-native/http/http-utils.d.ts +15 -0
  15. package/dist/src/react-native/inspector.d.ts +7 -0
  16. package/dist/src/react-native/network-inspector.d.ts +16 -0
  17. package/dist/src/react-native/sse/sse-inspector.d.ts +4 -7
  18. package/dist/src/react-native/useHttpInspector.d.ts +3 -0
  19. package/dist/src/react-native/useSSEInspector.d.ts +3 -0
  20. package/dist/src/react-native/useWebSocketInspector.d.ts +3 -0
  21. package/dist/src/react-native/websocket/websocket-inspector.d.ts +4 -7
  22. package/dist/src/shared/client.d.ts +3 -105
  23. package/dist/src/shared/http-events.d.ts +106 -0
  24. package/dist/src/shared/sse-events.d.ts +1 -1
  25. package/dist/src/ui/state/hooks.d.ts +3 -3
  26. package/dist/useNetworkActivityDevTools.cjs +112 -1011
  27. package/dist/useNetworkActivityDevTools.js +110 -1007
  28. package/package.json +4 -4
  29. package/react-native.ts +8 -0
  30. package/src/react-native/boot-recording.ts +90 -0
  31. package/src/react-native/config.ts +9 -4
  32. package/src/react-native/events-listener.ts +102 -0
  33. package/src/react-native/http/http-inspector.ts +174 -0
  34. package/src/react-native/http/http-utils.ts +217 -0
  35. package/src/react-native/inspector.ts +10 -0
  36. package/src/react-native/network-inspector.ts +78 -0
  37. package/src/react-native/sse/sse-inspector.ts +12 -10
  38. package/src/react-native/useHttpInspector.ts +59 -0
  39. package/src/react-native/useNetworkActivityDevTools.ts +60 -115
  40. package/src/react-native/useSSEInspector.ts +35 -0
  41. package/src/react-native/useWebSocketInspector.ts +35 -0
  42. package/src/react-native/websocket/websocket-inspector.ts +18 -10
  43. package/src/shared/client.ts +4 -140
  44. package/src/shared/http-events.ts +140 -0
  45. package/src/shared/sse-events.ts +1 -1
  46. package/src/ui/components/RequestList.tsx +9 -5
  47. package/src/ui/state/derived.ts +7 -3
  48. package/src/ui/state/store.ts +4 -3
  49. package/dist/src/react-native/http/network-inspector.d.ts +0 -8
  50. package/src/react-native/http/network-inspector.ts +0 -408
@@ -0,0 +1,140 @@
1
+ export type HttpHeaders = Record<string, string | string[]>;
2
+ export type XHRHeaders = NonNullable<XMLHttpRequest['responseHeaders']>;
3
+
4
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
5
+
6
+ export type RequestId = string;
7
+ export type Timestamp = number;
8
+
9
+ export type XHRPostData =
10
+ | string
11
+ | Blob
12
+ | FormData
13
+ | ArrayBuffer
14
+ | ArrayBufferView
15
+ | unknown
16
+ | null
17
+ | undefined;
18
+
19
+ export type RequestTextPostData = {
20
+ type: 'text';
21
+ value: string;
22
+ };
23
+
24
+ export type RequestBinaryPostData = {
25
+ type: 'binary';
26
+ value: {
27
+ size: number;
28
+ type?: string;
29
+ name?: string;
30
+ };
31
+ };
32
+
33
+ export type RequestFormDataPostData = {
34
+ type: 'form-data';
35
+ value: Record<string, RequestTextPostData | RequestBinaryPostData>;
36
+ };
37
+
38
+ export type RequestPostData =
39
+ | RequestTextPostData
40
+ | RequestFormDataPostData
41
+ | RequestBinaryPostData
42
+ | null
43
+ | undefined;
44
+
45
+ export type Cookie = {
46
+ name: string;
47
+ value: string;
48
+ domain?: string;
49
+ path?: string;
50
+ expires?: string;
51
+ maxAge?: string;
52
+ secure?: boolean;
53
+ httpOnly?: boolean;
54
+ sameSite?: string;
55
+ };
56
+
57
+ export type Request = {
58
+ url: string;
59
+ method: HttpMethod;
60
+ headers: HttpHeaders;
61
+ postData?: RequestPostData;
62
+ };
63
+
64
+ export type Response = {
65
+ url: string;
66
+ status: number;
67
+ statusText: string;
68
+ headers: HttpHeaders;
69
+ contentType: string;
70
+ size: number | null;
71
+ responseTime: Timestamp;
72
+ };
73
+
74
+ export type Initiator = {
75
+ type: string;
76
+ url?: string;
77
+ lineNumber?: number;
78
+ columnNumber?: number;
79
+ };
80
+
81
+ export type ResourceType = 'XHR' | 'Fetch' | 'Other';
82
+
83
+ export type RequestOverride = {
84
+ status?: number;
85
+ body?: string;
86
+ };
87
+
88
+ export type HttpEventMap = {
89
+ 'request-sent': {
90
+ requestId: RequestId;
91
+ request: Request;
92
+ timestamp: Timestamp;
93
+ initiator: Initiator;
94
+ type: ResourceType;
95
+ };
96
+
97
+ 'response-received': {
98
+ requestId: RequestId;
99
+ timestamp: Timestamp;
100
+ type: ResourceType;
101
+ response: Response;
102
+ };
103
+
104
+ 'request-completed': {
105
+ requestId: RequestId;
106
+ timestamp: Timestamp;
107
+ duration: number;
108
+ size: number | null;
109
+ ttfb: number;
110
+ };
111
+
112
+ 'request-failed': {
113
+ requestId: RequestId;
114
+ timestamp: Timestamp;
115
+ type: ResourceType;
116
+ error: string;
117
+ canceled: boolean;
118
+ };
119
+
120
+ 'request-progress': {
121
+ requestId: RequestId;
122
+ timestamp: Timestamp;
123
+ loaded: number;
124
+ total: number;
125
+ lengthComputable: boolean;
126
+ };
127
+
128
+ 'get-response-body': {
129
+ requestId: RequestId;
130
+ };
131
+
132
+ 'response-body': {
133
+ requestId: RequestId;
134
+ body: string | null;
135
+ };
136
+
137
+ 'set-overrides': {
138
+ overrides: [string, RequestOverride][];
139
+ };
140
+ };
@@ -1,4 +1,4 @@
1
- import type { Response } from './client';
1
+ import type { Response } from './http-events';
2
2
 
3
3
  export type SSEConnectionStatus = 'connecting' | 'open' | 'closed';
4
4
  export type SSERequestId = string;
@@ -61,7 +61,7 @@ const formatStartTime = (startTime: number): string => {
61
61
  };
62
62
 
63
63
  const extractDomainAndPath = (
64
- url: string
64
+ url: string,
65
65
  ): { domain: string; path: string } => {
66
66
  try {
67
67
  const { hostname, pathname, search, hash, port } = new URL(url);
@@ -80,7 +80,7 @@ const generateName = (url: string, showEntirePathName = false): string => {
80
80
  const urlObj = new URL(url);
81
81
  const pathname = urlObj.pathname;
82
82
  const filename = showEntirePathName ? undefined : pathname.split('/').pop();
83
-
83
+
84
84
  return filename || pathname || urlObj.hostname;
85
85
  } catch {
86
86
  return url;
@@ -128,7 +128,7 @@ const sortTime: SortingFn<NetworkRequest> = (rowA, rowB, columnId) => {
128
128
  const processNetworkRequests = (
129
129
  processedRequests: ProcessedRequest[],
130
130
  overrides: Map<string, RequestOverride>,
131
- showEntirePathAsName = false
131
+ showEntirePathAsName = false,
132
132
  ): NetworkRequest[] => {
133
133
  return processedRequests.map((request): NetworkRequest => {
134
134
  const { domain, path } = extractDomainAndPath(request.name);
@@ -262,7 +262,11 @@ export const RequestList = ({ filter }: RequestListProps) => {
262
262
  }, [processedRequests, filter]);
263
263
 
264
264
  const requests = useMemo(() => {
265
- return processNetworkRequests(filteredRequests, overrides, clientUISettings?.showUrlAsName);
265
+ return processNetworkRequests(
266
+ filteredRequests,
267
+ overrides,
268
+ clientUISettings?.showUrlAsName,
269
+ );
266
270
  }, [filteredRequests, overrides, clientUISettings?.showUrlAsName]);
267
271
 
268
272
  const table = useReactTable({
@@ -302,7 +306,7 @@ export const RequestList = ({ filter }: RequestListProps) => {
302
306
  ? null
303
307
  : flexRender(
304
308
  header.column.columnDef.header,
305
- header.getContext()
309
+ header.getContext(),
306
310
  )}
307
311
  {header.column.getCanSort() && (
308
312
  <span className="text-gray-500">
@@ -21,7 +21,7 @@ export const getProcessedRequests = memoize((state: NetworkActivityState) => {
21
21
  status: httpEntry.status,
22
22
  timestamp: httpEntry.timestamp,
23
23
  duration: httpEntry.duration,
24
- size: httpEntry.size,
24
+ size: httpEntry.size ?? null,
25
25
  method: httpEntry.request.method,
26
26
  httpStatus: httpEntry.response?.status,
27
27
  progress: httpEntry.progress,
@@ -35,6 +35,7 @@ export const getProcessedRequests = memoize((state: NetworkActivityState) => {
35
35
  status: wsEntry.status,
36
36
  timestamp: wsEntry.timestamp,
37
37
  duration: wsEntry.duration,
38
+ size: null,
38
39
  method: 'WS',
39
40
  httpStatus: 0,
40
41
  });
@@ -47,6 +48,7 @@ export const getProcessedRequests = memoize((state: NetworkActivityState) => {
47
48
  status: sseEntry.status,
48
49
  timestamp: sseEntry.timestamp,
49
50
  duration: sseEntry.duration,
51
+ size: null,
50
52
  method: 'SSE',
51
53
  httpStatus: 0,
52
54
  });
@@ -63,7 +65,7 @@ export const getSelectedRequest = memoize((state: NetworkActivityState) => {
63
65
  });
64
66
 
65
67
  export const getRequestSummary = (
66
- requestId: string
68
+ requestId: string,
67
69
  ): ((state: NetworkActivityState) => ProcessedRequest | null) =>
68
70
  memoize((state: NetworkActivityState) => {
69
71
  const { networkEntries } = state;
@@ -79,7 +81,7 @@ export const getRequestSummary = (
79
81
  status: httpEntry.status,
80
82
  timestamp: httpEntry.timestamp,
81
83
  duration: httpEntry.duration,
82
- size: httpEntry.size,
84
+ size: httpEntry.size ?? null,
83
85
  method: httpEntry.request.method,
84
86
  httpStatus: httpEntry.response?.status || 0,
85
87
  progress: httpEntry.progress,
@@ -93,6 +95,7 @@ export const getRequestSummary = (
93
95
  status: wsEntry.status,
94
96
  timestamp: wsEntry.timestamp,
95
97
  duration: wsEntry.duration,
98
+ size: null,
96
99
  method: 'WS',
97
100
  httpStatus: 0,
98
101
  };
@@ -105,6 +108,7 @@ export const getRequestSummary = (
105
108
  status: sseEntry.status,
106
109
  timestamp: sseEntry.timestamp,
107
110
  duration: sseEntry.duration,
111
+ size: null,
108
112
  method: 'SSE',
109
113
  httpStatus: 0,
110
114
  };
@@ -65,7 +65,7 @@ export const createNetworkActivityStore = () =>
65
65
  persist(
66
66
  (set, get) => ({
67
67
  // Initial state
68
- isRecording: false,
68
+ isRecording: true,
69
69
  selectedRequestId: null,
70
70
  networkEntries: new Map(),
71
71
  websocketMessages: new Map(),
@@ -684,9 +684,10 @@ export const createNetworkActivityStore = () =>
684
684
  typeof value === 'object' &&
685
685
  value !== null &&
686
686
  '_type' in value &&
687
- value._type === 'map'
687
+ value._type === 'map' &&
688
+ 'value' in value
688
689
  ) {
689
- return new Map(value.value);
690
+ return new Map(value.value as [string, RequestOverride][]);
690
691
  }
691
692
  return value;
692
693
  },
@@ -1,8 +0,0 @@
1
- import { NetworkActivityDevToolsClient } from '../../shared/client';
2
- export type NetworkInspector = {
3
- enable: () => void;
4
- disable: () => void;
5
- isEnabled: () => boolean;
6
- dispose: () => void;
7
- };
8
- export declare const getNetworkInspector: (pluginClient: NetworkActivityDevToolsClient) => NetworkInspector;
@@ -1,408 +0,0 @@
1
- import { safeStringify } from '../../utils/safeStringify';
2
- import {
3
- HttpMethod,
4
- NetworkActivityDevToolsClient,
5
- RequestPostData,
6
- RequestTextPostData,
7
- RequestBinaryPostData,
8
- RequestFormDataPostData,
9
- XHRPostData,
10
- } from '../../shared/client';
11
- import { getContentType } from '../utils';
12
- import { getNetworkRequestsRegistry } from './network-requests-registry';
13
- import { getBlobName } from '../utils/getBlobName';
14
- import { getFormDataEntries } from '../utils/getFormDataEntries';
15
- import { XHRInterceptor } from './xhr-interceptor';
16
- import { getStringSizeInBytes } from '../../utils/getStringSizeInBytes';
17
- import { applyReactNativeResponseHeadersLogic } from '../../utils/applyReactNativeResponseHeadersLogic';
18
- import {
19
- isBlob,
20
- isArrayBuffer,
21
- isFormData,
22
- isNullOrUndefined,
23
- } from '../../utils/typeChecks';
24
- import { getOverridesRegistry } from './overrides-registry';
25
-
26
- const networkRequestsRegistry = getNetworkRequestsRegistry();
27
- const overridesRegistry = getOverridesRegistry();
28
-
29
- const getBinaryPostData = (body: Blob): RequestBinaryPostData => ({
30
- type: 'binary',
31
- value: {
32
- size: body.size,
33
- type: body.type,
34
- name: getBlobName(body),
35
- },
36
- });
37
-
38
- const getArrayBufferPostData = (
39
- body: ArrayBuffer | ArrayBufferView
40
- ): RequestBinaryPostData => ({
41
- type: 'binary',
42
- value: {
43
- size: body.byteLength,
44
- },
45
- });
46
-
47
- const getTextPostData = (body: unknown): RequestTextPostData => ({
48
- type: 'text',
49
- value: safeStringify(body),
50
- });
51
-
52
- const getFormDataPostData = (body: FormData): RequestFormDataPostData => ({
53
- type: 'form-data',
54
- value: getFormDataEntries(body).reduce<RequestFormDataPostData['value']>(
55
- (acc, [key, value]) => {
56
- if (isBlob(value)) {
57
- acc[key] = getBinaryPostData(value);
58
- } else if (isArrayBuffer(value)) {
59
- acc[key] = getArrayBufferPostData(value);
60
- } else {
61
- acc[key] = getTextPostData(value);
62
- }
63
-
64
- return acc;
65
- },
66
- {}
67
- ),
68
- });
69
-
70
- const getRequestBody = (body: XHRPostData): RequestPostData => {
71
- if (isNullOrUndefined(body)) {
72
- return body;
73
- }
74
-
75
- if (isBlob(body)) {
76
- return getBinaryPostData(body);
77
- }
78
-
79
- if (isArrayBuffer(body)) {
80
- return getArrayBufferPostData(body);
81
- }
82
-
83
- if (isFormData(body)) {
84
- return getFormDataPostData(body);
85
- }
86
-
87
- return getTextPostData(body);
88
- };
89
-
90
- const getResponseSize = (request: XMLHttpRequest): number | null => {
91
- try {
92
- const { responseType, response } = request;
93
-
94
- // Handle a case of 204 where no-content was sent.
95
- if (response === null) {
96
- return 0;
97
- }
98
-
99
- if (responseType === '' || responseType === 'text') {
100
- return getStringSizeInBytes(request.responseText);
101
- }
102
-
103
- if (responseType === 'json') {
104
- return getStringSizeInBytes(safeStringify(response));
105
- }
106
-
107
- if (responseType === 'blob') {
108
- return response.size;
109
- }
110
-
111
- if (responseType === 'arraybuffer') {
112
- return response.byteLength;
113
- }
114
-
115
- return 0;
116
- } catch {
117
- return null;
118
- }
119
- };
120
-
121
- const getResponseBody = async (
122
- request: XMLHttpRequest
123
- ): Promise<string | null> => {
124
- const responseType = request.responseType;
125
-
126
- // Response type is empty in certain cases, like when using axios.
127
- if (responseType === '' || responseType === 'text') {
128
- return request.responseText as string;
129
- }
130
-
131
- if (responseType === 'blob') {
132
- // This may be a text blob.
133
- const contentType = request.getResponseHeader('Content-Type') || '';
134
-
135
- if (
136
- contentType.startsWith('text/') ||
137
- contentType.startsWith('application/json')
138
- ) {
139
- // It looks like a text blob, let's read it and forward it to the client.
140
- return new Promise((resolve) => {
141
- const reader = new FileReader();
142
- reader.onload = () => {
143
- resolve(reader.result as string);
144
- };
145
- reader.readAsText(request.response);
146
- });
147
- }
148
- }
149
-
150
- if (responseType === 'json') {
151
- return safeStringify(request.response);
152
- }
153
-
154
- return null;
155
- };
156
-
157
- const getInitiatorFromStack = (): {
158
- type: string;
159
- url?: string;
160
- lineNumber?: number;
161
- columnNumber?: number;
162
- } => {
163
- try {
164
- const stack = new Error().stack;
165
- if (!stack) {
166
- return { type: 'other' };
167
- }
168
-
169
- const line = stack.split('\n')[9];
170
- const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
171
- if (match) {
172
- return {
173
- type: 'script',
174
- url: match[2],
175
- lineNumber: parseInt(match[3]),
176
- columnNumber: parseInt(match[4]),
177
- };
178
- }
179
- } catch {
180
- // Ignore stack parsing errors
181
- }
182
-
183
- return { type: 'other' };
184
- };
185
-
186
- export type NetworkInspector = {
187
- enable: () => void;
188
- disable: () => void;
189
- isEnabled: () => boolean;
190
- dispose: () => void;
191
- };
192
-
193
- const READY_STATE_HEADERS_RECEIVED = 2;
194
-
195
- export const getNetworkInspector = (
196
- pluginClient: NetworkActivityDevToolsClient
197
- ): NetworkInspector => {
198
- const generateRequestId = (): string => {
199
- return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
200
- };
201
-
202
- const handleRequestSend = (
203
- data: XHRPostData,
204
- request: XMLHttpRequest
205
- ): void => {
206
- const sendTime = Date.now();
207
-
208
- const requestId = generateRequestId();
209
- request._rozeniteRequestId = requestId;
210
-
211
- const initiator = getInitiatorFromStack();
212
-
213
- networkRequestsRegistry.addEntry(requestId, request);
214
-
215
- let ttfb = 0;
216
-
217
- pluginClient.send('request-sent', {
218
- requestId: requestId,
219
- timestamp: sendTime,
220
- request: {
221
- url: request._url as string,
222
- method: request._method as HttpMethod,
223
- headers: request._headers,
224
- postData: getRequestBody(data),
225
- },
226
- type: 'XHR',
227
- initiator,
228
- });
229
-
230
- request.addEventListener('progress', (event) => {
231
- pluginClient.send('request-progress', {
232
- requestId: requestId,
233
- timestamp: Date.now(),
234
- loaded: event.loaded,
235
- total: event.total,
236
- lengthComputable: event.lengthComputable,
237
- });
238
- });
239
-
240
- request.addEventListener('readystatechange', () => {
241
- if (request.readyState === READY_STATE_HEADERS_RECEIVED) {
242
- ttfb = Date.now() - sendTime;
243
- }
244
- });
245
-
246
- request.addEventListener('load', () => {
247
- pluginClient.send('response-received', {
248
- requestId: requestId,
249
- timestamp: Date.now(),
250
- type: 'XHR',
251
- response: {
252
- url: request._url as string,
253
- status: request.status,
254
- statusText: request.statusText,
255
- headers: applyReactNativeResponseHeadersLogic(
256
- request.responseHeaders || {}
257
- ),
258
- contentType: getContentType(request),
259
- size: getResponseSize(request),
260
- responseTime: Date.now(),
261
- },
262
- });
263
- });
264
-
265
- request.addEventListener('loadend', () => {
266
- pluginClient.send('request-completed', {
267
- requestId: requestId,
268
- timestamp: Date.now(),
269
- duration: Date.now() - sendTime,
270
- size: getResponseSize(request),
271
- ttfb,
272
- });
273
- });
274
-
275
- request.addEventListener('error', () => {
276
- pluginClient.send('request-failed', {
277
- requestId: requestId,
278
- timestamp: Date.now(),
279
- type: 'XHR',
280
- error: 'Failed',
281
- canceled: false,
282
- });
283
- });
284
-
285
- request.addEventListener('abort', () => {
286
- pluginClient.send('request-failed', {
287
- requestId: requestId,
288
- timestamp: Date.now(),
289
- type: 'XHR',
290
- error: 'Aborted',
291
- canceled: true,
292
- });
293
- });
294
-
295
- request.addEventListener('timeout', () => {
296
- pluginClient.send('request-failed', {
297
- requestId: requestId,
298
- timestamp: Date.now(),
299
- type: 'XHR',
300
- error: 'Timeout',
301
- canceled: false,
302
- });
303
- });
304
- };
305
-
306
- const handleRequestOverride = (request: XMLHttpRequest): void => {
307
- const override = overridesRegistry.getOverrideForUrl(
308
- request._url as string
309
- );
310
-
311
- if (!override) {
312
- return;
313
- }
314
-
315
- request.addEventListener('readystatechange', () => {
316
- if (override.body !== undefined) {
317
- Object.defineProperty(request, 'responseType', {
318
- writable: true,
319
- });
320
-
321
- Object.defineProperty(request, 'response', {
322
- writable: true,
323
- });
324
- Object.defineProperty(request, 'responseText', {
325
- writable: true,
326
- });
327
-
328
- const contentType = getContentType(request);
329
-
330
- if (contentType === 'application/json') {
331
- request.responseType = 'json';
332
- } else if (contentType === 'text/plain') {
333
- request.responseType = 'text';
334
- }
335
-
336
- // @ts-expect-error - Mocking response
337
- request.response = override.body;
338
- // @ts-expect-error - Mocking responseText
339
- request.responseText = override.body;
340
- }
341
-
342
- if (override.status !== undefined) {
343
- Object.defineProperty(request, 'status', {
344
- writable: true,
345
- });
346
-
347
- // @ts-expect-error - Mocking status
348
- request.status = override.status;
349
- }
350
- });
351
- };
352
-
353
- const enable = () => {
354
- XHRInterceptor.disableInterception();
355
- XHRInterceptor.setSendCallback(handleRequestSend);
356
- XHRInterceptor.setOverrideCallback(handleRequestOverride);
357
- XHRInterceptor.enableInterception();
358
- };
359
-
360
- const disable = () => {
361
- XHRInterceptor.disableInterception();
362
- networkRequestsRegistry.clear();
363
- };
364
-
365
- const isEnabled = () => {
366
- return XHRInterceptor.isInterceptorEnabled();
367
- };
368
-
369
- const enableSubscription = pluginClient.onMessage('network-enable', () => {
370
- enable();
371
- });
372
-
373
- const disableSubscription = pluginClient.onMessage('network-disable', () => {
374
- disable();
375
- });
376
-
377
- const handleBodySubscription = pluginClient.onMessage(
378
- 'get-response-body',
379
- async ({ requestId }) => {
380
- const request = networkRequestsRegistry.getEntry(requestId);
381
-
382
- if (!request) {
383
- return;
384
- }
385
-
386
- const body = await getResponseBody(request);
387
-
388
- pluginClient.send('response-body', {
389
- requestId,
390
- body,
391
- });
392
- }
393
- );
394
-
395
- const dispose = () => {
396
- disable();
397
- enableSubscription.remove();
398
- disableSubscription.remove();
399
- handleBodySubscription.remove();
400
- };
401
-
402
- return {
403
- enable,
404
- disable,
405
- isEnabled,
406
- dispose,
407
- };
408
- };