@rozenite/network-activity-plugin 1.0.0-alpha.5 → 1.0.0-alpha.7

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 (75) hide show
  1. package/dist/{panel.html → App.html} +3 -3
  2. package/dist/assets/App-CIflVb88.js +24164 -0
  3. package/dist/assets/App-Czu6Vt2P.css +1233 -0
  4. package/dist/react-native.cjs +1 -1
  5. package/dist/react-native.d.ts +1 -90
  6. package/dist/rozenite.config.d.ts +7 -0
  7. package/dist/rozenite.json +1 -1
  8. package/dist/src/react-native/network-inspector.d.ts +8 -0
  9. package/dist/src/react-native/network-requests-registry.d.ts +6 -0
  10. package/dist/src/react-native/useNetworkActivityDevTools.d.ts +2 -0
  11. package/dist/src/react-native/xhr-interceptor.d.ts +38 -0
  12. package/dist/src/shared/client.d.ts +64 -0
  13. package/dist/src/ui/App.d.ts +1 -0
  14. package/dist/src/ui/components/Badge.d.ts +9 -0
  15. package/dist/src/ui/components/Button.d.ts +11 -0
  16. package/dist/src/ui/components/Input.d.ts +3 -0
  17. package/dist/src/ui/components/JsonTree.d.ts +5 -0
  18. package/dist/src/ui/components/RequestList.d.ts +45 -0
  19. package/dist/src/ui/components/ScrollArea.d.ts +4 -0
  20. package/dist/src/ui/components/Separator.d.ts +3 -0
  21. package/dist/src/ui/tabs/CookiesTab.d.ts +8 -0
  22. package/dist/src/ui/tabs/HeadersTab.d.ts +17 -0
  23. package/dist/src/ui/tabs/RequestTab.d.ts +10 -0
  24. package/dist/src/ui/tabs/ResponseTab.d.ts +12 -0
  25. package/dist/src/ui/tabs/TimingTab.d.ts +7 -0
  26. package/dist/src/ui/types.d.ts +23 -0
  27. package/dist/src/ui/utils.d.ts +2 -0
  28. package/dist/src/ui/views/InspectorView.d.ts +5 -0
  29. package/dist/src/ui/views/LoadingView.d.ts +1 -0
  30. package/dist/useNetworkActivityDevTools.cjs +360 -0
  31. package/dist/useNetworkActivityDevTools.js +108 -236
  32. package/package.json +23 -16
  33. package/postcss.config.js +6 -0
  34. package/rozenite.config.ts +1 -1
  35. package/src/react-native/network-inspector.ts +113 -260
  36. package/src/react-native/network-requests-registry.ts +7 -77
  37. package/src/react-native/useNetworkActivityDevTools.ts +1 -1
  38. package/src/react-native/xhr-interceptor.ts +2 -2
  39. package/src/react-native/xml-request.d.ts +11 -1
  40. package/src/shared/client.ts +80 -0
  41. package/src/ui/App.tsx +19 -0
  42. package/src/ui/components/Badge.tsx +36 -0
  43. package/src/ui/components/Button.tsx +56 -0
  44. package/src/ui/components/Input.tsx +22 -0
  45. package/src/ui/components/JsonTree.tsx +37 -0
  46. package/src/ui/components/RequestList.tsx +376 -0
  47. package/src/ui/components/ScrollArea.tsx +48 -0
  48. package/src/ui/components/Separator.tsx +31 -0
  49. package/src/ui/components/Tabs.tsx +55 -0
  50. package/src/ui/globals.css +90 -0
  51. package/src/ui/tabs/CookiesTab.tsx +290 -0
  52. package/src/ui/tabs/HeadersTab.tsx +117 -0
  53. package/src/ui/tabs/RequestTab.tsx +72 -0
  54. package/src/ui/tabs/ResponseTab.tsx +140 -0
  55. package/src/ui/tabs/TimingTab.tsx +71 -0
  56. package/src/ui/types.ts +30 -0
  57. package/src/ui/utils.ts +5 -97
  58. package/src/ui/views/InspectorView.tsx +349 -0
  59. package/src/ui/views/LoadingView.tsx +19 -0
  60. package/tailwind.config.ts +93 -0
  61. package/dist/assets/panel-BNxB_KsS.js +0 -16663
  62. package/dist/assets/panel-DXGMsavf.css +0 -555
  63. package/src/types/client.ts +0 -111
  64. package/src/types/network.ts +0 -32
  65. package/src/ui/components.module.css +0 -158
  66. package/src/ui/components.tsx +0 -241
  67. package/src/ui/network-details.module.css +0 -197
  68. package/src/ui/network-details.tsx +0 -345
  69. package/src/ui/network-list.module.css +0 -128
  70. package/src/ui/network-list.tsx +0 -240
  71. package/src/ui/network-toolbar.module.css +0 -9
  72. package/src/ui/network-toolbar.tsx +0 -34
  73. package/src/ui/panel.module.css +0 -67
  74. package/src/ui/panel.tsx +0 -318
  75. package/src/ui/tanstack-query.tsx +0 -204
@@ -1,14 +1,20 @@
1
- import { NetworkActivityDevToolsClient } from '../types/client';
1
+ import { NetworkActivityDevToolsClient } from '../shared/client';
2
2
  import { getNetworkRequestsRegistry } from './network-requests-registry';
3
3
  import { XHRInterceptor } from './xhr-interceptor';
4
4
 
5
5
  const networkRequestsRegistry = getNetworkRequestsRegistry();
6
6
 
7
- const mimeTypeFromResponseType = (responseType: string): string | undefined => {
7
+ const getContentType = (request: XMLHttpRequest): string => {
8
+ const responseHeaders = request.responseHeaders;
9
+ const responseType = request.responseType;
10
+
11
+ if (responseHeaders?.['content-type']) {
12
+ return responseHeaders['content-type'].split(';')[0].trim();
13
+ }
14
+
8
15
  switch (responseType) {
9
16
  case 'arraybuffer':
10
17
  case 'blob':
11
- case 'base64':
12
18
  return 'application/octet-stream';
13
19
  case 'text':
14
20
  case '':
@@ -18,81 +24,45 @@ const mimeTypeFromResponseType = (responseType: string): string | undefined => {
18
24
  case 'document':
19
25
  return 'text/html';
20
26
  }
21
-
22
- return undefined;
23
27
  };
24
28
 
25
- const parseHeaders = (headersString: string): Record<string, string> => {
26
- const headers: Record<string, string> = {};
27
- if (!headersString) return headers;
28
-
29
- const lines = headersString.split('\r\n');
30
- for (const line of lines) {
31
- const colonIndex = line.indexOf(':');
32
- if (colonIndex > 0) {
33
- const key = line.substring(0, colonIndex).trim();
34
- const value = line.substring(colonIndex + 1).trim();
35
- headers[key] = value;
36
- }
29
+ const getResponseSize = (request: XMLHttpRequest): number => {
30
+ if (typeof request.response === 'object') {
31
+ return request.response.size;
37
32
  }
38
- return headers;
33
+
34
+ return request.response.length || 0;
39
35
  };
40
36
 
41
37
  const getResponseBody = async (
42
38
  request: XMLHttpRequest
43
- ): Promise<{ body: string; base64Encoded: boolean }> => {
44
- try {
45
- if (request.responseType === 'arraybuffer') {
46
- const arrayBuffer = request.response as ArrayBuffer;
47
- return {
48
- body: btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))),
49
- base64Encoded: true,
50
- };
51
- }
39
+ ): Promise<string | null> => {
40
+ const responseType = request.responseType;
52
41
 
53
- if (request.responseType === 'blob') {
54
- const contentType = request.getResponseHeader('Content-Type') || '';
55
-
56
- if (
57
- contentType.startsWith('text/') ||
58
- contentType.startsWith('application/json')
59
- ) {
60
- return new Promise((resolve) => {
61
- const reader = new FileReader();
62
- reader.onload = () => {
63
- resolve({
64
- body: reader.result as string,
65
- base64Encoded: false,
66
- });
67
- };
68
- reader.readAsText(request.response);
69
- });
70
- }
71
- }
42
+ if (responseType === 'text') {
43
+ return request.responseText as string;
44
+ }
72
45
 
73
- if (request.responseType === 'text') {
74
- return {
75
- body: request.responseText || request.response || '',
76
- base64Encoded: false,
77
- };
46
+ if (responseType === 'blob') {
47
+ // This may be a text blob.
48
+ const contentType = request.getResponseHeader('Content-Type') || '';
49
+
50
+ if (
51
+ contentType.startsWith('text/') ||
52
+ contentType.startsWith('application/json')
53
+ ) {
54
+ // It looks like a text blob, let's read it and forward it to the client.
55
+ return new Promise((resolve) => {
56
+ const reader = new FileReader();
57
+ reader.onload = () => {
58
+ resolve(reader.result as string);
59
+ };
60
+ reader.readAsText(request.response);
61
+ });
78
62
  }
79
-
80
- return {
81
- body: request.responseText || request.response || '',
82
- base64Encoded: false,
83
- };
84
- } catch (error) {
85
- return {
86
- body: `[Error reading response: ${error}]`,
87
- base64Encoded: false,
88
- };
89
63
  }
90
- };
91
64
 
92
- const findRequestId = (request: XMLHttpRequest): string | null => {
93
- const allRequests = networkRequestsRegistry.getAllEntries();
94
- const entry = allRequests.find(({ request: req }) => req === request);
95
- return entry?.id ?? null;
65
+ return null;
96
66
  };
97
67
 
98
68
  const getInitiatorFromStack = (): {
@@ -131,6 +101,8 @@ export type NetworkInspector = {
131
101
  dispose: () => void;
132
102
  };
133
103
 
104
+ const READY_STATE_HEADERS_RECEIVED = 2;
105
+
134
106
  export const getNetworkInspector = (
135
107
  pluginClient: NetworkActivityDevToolsClient
136
108
  ): NetworkInspector => {
@@ -138,202 +110,86 @@ export const getNetworkInspector = (
138
110
  return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
139
111
  };
140
112
 
141
- const generateLoaderId = (): string => {
142
- return `loader_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
143
- };
113
+ const handleRequestSend = (data: string, request: XMLHttpRequest): void => {
114
+ const sendTime = Date.now();
144
115
 
145
- const enable = () => {
146
- XHRInterceptor.disableInterception();
116
+ const requestId = generateRequestId();
117
+ const initiator = getInitiatorFromStack();
147
118
 
148
- XHRInterceptor.setOpenCallback(
149
- (method: string, url: string, request: XMLHttpRequest) => {
150
- const requestId = generateRequestId();
151
- const loaderId = generateLoaderId();
152
- const startTime = Date.now();
153
- const initiator = getInitiatorFromStack();
154
-
155
- // Store request in registry with metadata
156
- networkRequestsRegistry.addEntry(requestId, request, {
157
- id: requestId,
158
- loaderId,
159
- documentURL:
160
- typeof document !== 'undefined' ? document.URL : undefined,
161
- method,
162
- url,
163
- headers: request?._headers || {},
164
- startTime,
165
- status: 'pending',
166
- type: 'XHR',
167
- initiator,
168
- });
169
- }
170
- );
119
+ networkRequestsRegistry.addEntry(requestId, request);
171
120
 
172
- XHRInterceptor.setSendCallback((data: string, request: XMLHttpRequest) => {
173
- const requestId = findRequestId(request);
174
- if (!requestId) return;
121
+ let ttfb = 0;
175
122
 
176
- const entry = networkRequestsRegistry.getEntry(requestId);
177
- if (!entry) return;
123
+ pluginClient.send('request-sent', {
124
+ requestId: requestId,
125
+ timestamp: sendTime / 1000,
126
+ request: {
127
+ url: request._url as string,
128
+ method: request._method as string,
129
+ headers: request._headers,
130
+ postData: data,
131
+ },
132
+ type: 'XHR',
133
+ initiator,
134
+ });
178
135
 
179
- const metadata = entry.metadata;
136
+ request.addEventListener('readystatechange', () => {
137
+ if (request.readyState === READY_STATE_HEADERS_RECEIVED) {
138
+ ttfb = Date.now() - sendTime;
139
+ }
140
+ });
180
141
 
181
- // Update metadata with post data
182
- networkRequestsRegistry.updateEntry(requestId, {
183
- postData: data,
184
- hasPostData: !!data,
185
- headers: request?._headers || {},
142
+ request.addEventListener('load', () => {
143
+ pluginClient.send('response-received', {
144
+ requestId: requestId,
145
+ timestamp: Date.now() / 1000,
146
+ type: 'XHR',
147
+ response: {
148
+ url: request._url as string,
149
+ status: request.status,
150
+ statusText: request.statusText,
151
+ headers: request.responseHeaders as Record<string, string>,
152
+ contentType: getContentType(request),
153
+ size: getResponseSize(request),
154
+ responseTime: Date.now() / 1000,
155
+ },
186
156
  });
157
+ });
187
158
 
188
- // Send Network.requestWillBeSent event
189
- pluginClient.send('Network.requestWillBeSent', {
190
- requestId,
191
- loaderId: metadata.loaderId || '',
192
- documentURL: metadata.documentURL || '',
193
- request: {
194
- url: metadata.url,
195
- method: metadata.method,
196
- headers: metadata.headers,
197
- postData: data,
198
- hasPostData: !!data,
199
- },
200
- timestamp: metadata.startTime,
201
- wallTime: metadata.startTime,
202
- initiator: metadata.initiator || { type: 'other' },
203
- type: metadata.type,
159
+ request.addEventListener('loadend', () => {
160
+ pluginClient.send('request-completed', {
161
+ requestId: requestId,
162
+ timestamp: Date.now() / 1000,
163
+ duration: Date.now() - sendTime,
164
+ size: getResponseSize(request),
165
+ ttfb,
204
166
  });
205
167
  });
206
168
 
207
- XHRInterceptor.setHeaderReceivedCallback(
208
- (
209
- responseContentType: string | void,
210
- responseSize: number | void,
211
- allHeaders: string,
212
- request: XMLHttpRequest
213
- ) => {
214
- const requestId = findRequestId(request);
215
- if (!requestId) return;
216
-
217
- const entry = networkRequestsRegistry.getEntry(requestId);
218
- if (!entry) return;
219
-
220
- const metadata = entry.metadata;
221
- const headers = parseHeaders(allHeaders);
222
- const mimeType =
223
- responseContentType ||
224
- mimeTypeFromResponseType(request.responseType) ||
225
- 'text/plain';
226
-
227
- // Update metadata with response info
228
- networkRequestsRegistry.updateEntry(requestId, {
229
- status: 'loading',
230
- response: {
231
- url: metadata.url,
232
- status: request.status,
233
- statusText: request.statusText,
234
- headers,
235
- mimeType,
236
- encodedDataLength: responseSize || 0,
237
- responseTime: Date.now(),
238
- },
239
- });
240
-
241
- // Send Network.responseReceived event
242
- pluginClient.send('Network.responseReceived', {
243
- requestId,
244
- loaderId: metadata.loaderId || '',
245
- timestamp: Date.now(),
246
- type: metadata.type || 'Other',
247
- response: {
248
- url: metadata.url,
249
- status: request.status,
250
- statusText: request.statusText,
251
- headers,
252
- mimeType,
253
- encodedDataLength: responseSize || 0,
254
- responseTime: Date.now(),
255
- },
256
- });
257
- }
258
- );
259
-
260
- XHRInterceptor.setResponseCallback(
261
- (
262
- status: number,
263
- timeout: number,
264
- response: string,
265
- responseURL: string,
266
- responseType: string,
267
- request: XMLHttpRequest
268
- ) => {
269
- const requestId = findRequestId(request);
270
- if (!requestId) return;
271
-
272
- const entry = networkRequestsRegistry.getEntry(requestId);
273
- if (!entry) return;
274
-
275
- const metadata = entry.metadata;
276
- if (!metadata) return;
277
-
278
- const endTime = Date.now();
279
- const duration = endTime - metadata.startTime;
280
- const dataLength = response ? response.length : 0;
281
-
282
- // Update metadata with final data
283
- networkRequestsRegistry.updateEntry(requestId, {
284
- endTime,
285
- duration,
286
- dataLength,
287
- encodedDataLength: dataLength,
288
- });
289
-
290
- // Check if request failed
291
- if (status >= 400 || request.readyState === 0) {
292
- const errorText = request.statusText || 'Request failed';
293
- const canceled = request.readyState === 0;
294
-
295
- // Update metadata
296
- networkRequestsRegistry.updateEntry(requestId, {
297
- status: 'failed',
298
- errorText,
299
- canceled,
300
- });
301
-
302
- // Send Network.loadingFailed event
303
- pluginClient.send('Network.loadingFailed', {
304
- requestId,
305
- timestamp: endTime,
306
- type: metadata.type || 'Other',
307
- errorText,
308
- canceled,
309
- });
310
- } else {
311
- // Update metadata
312
- networkRequestsRegistry.updateEntry(requestId, {
313
- status: 'finished',
314
- encodedDataLength: dataLength,
315
- });
316
-
317
- // Send Network.dataReceived event if there's data
318
- if (dataLength > 0) {
319
- pluginClient.send('Network.dataReceived', {
320
- requestId,
321
- timestamp: endTime,
322
- dataLength,
323
- encodedDataLength: dataLength,
324
- });
325
- }
326
-
327
- // Send Network.loadingFinished event
328
- pluginClient.send('Network.loadingFinished', {
329
- requestId,
330
- timestamp: endTime,
331
- encodedDataLength: dataLength,
332
- });
333
- }
334
- }
335
- );
169
+ request.addEventListener('error', () => {
170
+ pluginClient.send('request-failed', {
171
+ requestId: requestId,
172
+ timestamp: Date.now() / 1000,
173
+ type: 'XHR',
174
+ error: 'Failed',
175
+ canceled: false,
176
+ });
177
+ });
178
+
179
+ request.addEventListener('abort', () => {
180
+ pluginClient.send('request-failed', {
181
+ requestId: requestId,
182
+ timestamp: Date.now() / 1000,
183
+ type: 'XHR',
184
+ error: 'Aborted',
185
+ canceled: true,
186
+ });
187
+ });
188
+ };
336
189
 
190
+ const enable = () => {
191
+ XHRInterceptor.disableInterception();
192
+ XHRInterceptor.setSendCallback(handleRequestSend);
337
193
  XHRInterceptor.enableInterception();
338
194
  };
339
195
 
@@ -355,22 +211,19 @@ export const getNetworkInspector = (
355
211
  });
356
212
 
357
213
  const handleBodySubscription = pluginClient.onMessage(
358
- 'Network.getResponseBody',
359
- async (payload) => {
360
- const requestId = payload.requestId;
361
- const entry = networkRequestsRegistry.getEntry(requestId);
362
- if (!entry) {
214
+ 'get-response-body',
215
+ async ({ requestId }) => {
216
+ const request = networkRequestsRegistry.getEntry(requestId);
217
+
218
+ if (!request) {
363
219
  return;
364
220
  }
365
221
 
366
- const { request } = entry;
367
- const { body, base64Encoded } = await getResponseBody(request);
222
+ const body = await getResponseBody(request);
368
223
 
369
- // Send Network.responseBodyReceived event
370
- pluginClient.send('Network.responseBodyReceived', {
224
+ pluginClient.send('response-body', {
371
225
  requestId,
372
226
  body,
373
- base64Encoded,
374
227
  });
375
228
  }
376
229
  );
@@ -1,50 +1,12 @@
1
- import {
2
- NetworkRequestId,
3
- NetworkLoaderId,
4
- NetworkResourceType,
5
- NetworkRequest,
6
- NetworkResponse,
7
- NetworkInitiator,
8
- } from '../types/client';
9
-
10
- export type NetworkRequestMetadata = {
11
- id: NetworkRequestId;
12
- loaderId?: NetworkLoaderId;
13
- documentURL?: string;
14
- method: string;
15
- url: string;
16
- headers: Record<string, string>;
17
- postData?: string;
18
- hasPostData?: boolean;
19
- type?: NetworkResourceType;
20
- initiator?: NetworkInitiator;
21
- startTime: number;
22
- endTime?: number;
23
- duration?: number;
24
- status: 'pending' | 'loading' | 'finished' | 'failed';
25
- response?: NetworkResponse;
26
- errorText?: string;
27
- canceled?: boolean;
28
- encodedDataLength?: number;
29
- dataLength?: number;
30
- };
31
-
32
- export type NetworkRegistryEntry = {
1
+ type NetworkRegistryEntry = {
33
2
  id: string;
34
- request: XMLHttpRequest;
35
- metadata: NetworkRequestMetadata;
36
3
  sentAt: number;
4
+ request: XMLHttpRequest;
37
5
  };
38
6
 
39
7
  export type NetworkRequestRegistry = {
40
- addEntry: (
41
- id: string,
42
- request: XMLHttpRequest,
43
- metadata: Partial<NetworkRequestMetadata>
44
- ) => void;
45
- getEntry: (id: string) => NetworkRegistryEntry | null;
46
- updateEntry: (id: string, updates: Partial<NetworkRequestMetadata>) => void;
47
- getAllEntries: () => Array<NetworkRegistryEntry>;
8
+ addEntry: (id: string, request: XMLHttpRequest) => void;
9
+ getEntry: (id: string) => XMLHttpRequest | null;
48
10
  clear: () => void;
49
11
  };
50
12
 
@@ -65,47 +27,17 @@ export const getNetworkRequestsRegistry = (): NetworkRequestRegistry => {
65
27
  });
66
28
  };
67
29
 
68
- const addEntry = (
69
- id: string,
70
- request: XMLHttpRequest,
71
- metadata: Partial<NetworkRequestMetadata>
72
- ) => {
30
+ const addEntry = (id: string, request: XMLHttpRequest): void => {
73
31
  trimRegistry();
74
-
75
- const fullMetadata: NetworkRequestMetadata = {
76
- id,
77
- method: metadata.method || 'GET',
78
- url: metadata.url || '',
79
- headers: metadata.headers || {},
80
- startTime: metadata.startTime || Date.now(),
81
- status: metadata.status || 'pending',
82
- ...metadata,
83
- };
84
-
85
32
  registry.set(id, {
86
33
  id,
87
34
  request,
88
- metadata: fullMetadata,
89
35
  sentAt: Date.now(),
90
36
  });
91
37
  };
92
38
 
93
- const getEntry = (id: string) => {
94
- return registry.get(id) ?? null;
95
- };
96
-
97
- const updateEntry = (
98
- id: string,
99
- updates: Partial<NetworkRequestMetadata>
100
- ) => {
101
- const entry = registry.get(id);
102
- if (entry) {
103
- entry.metadata = { ...entry.metadata, ...updates };
104
- }
105
- };
106
-
107
- const getAllEntries = () => {
108
- return Array.from(registry.values());
39
+ const getEntry = (id: string): XMLHttpRequest | null => {
40
+ return registry.get(id)?.request ?? null;
109
41
  };
110
42
 
111
43
  const clear = () => {
@@ -115,8 +47,6 @@ export const getNetworkRequestsRegistry = (): NetworkRequestRegistry => {
115
47
  return {
116
48
  addEntry,
117
49
  getEntry,
118
- updateEntry,
119
- getAllEntries,
120
50
  clear,
121
51
  };
122
52
  };
@@ -1,7 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
  import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
3
3
  import { getNetworkInspector } from './network-inspector';
4
- import { NetworkActivityEventMap } from '../types/client';
4
+ import { NetworkActivityEventMap } from '../shared/client';
5
5
 
6
6
  export const useNetworkActivityDevTools = () => {
7
7
  const client = useRozeniteDevToolsClient<NetworkActivityEventMap>({
@@ -31,8 +31,8 @@ type XHRInterceptorRequestHeaderCallback = (
31
31
  ) => void;
32
32
 
33
33
  type XHRInterceptorHeaderReceivedCallback = (
34
- responseContentType: string | void,
35
- responseSize: number | void,
34
+ responseContentType: string | undefined,
35
+ responseSize: number | undefined,
36
36
  allHeaders: string,
37
37
  request: XMLHttpRequest
38
38
  ) => void;
@@ -1,3 +1,12 @@
1
+ declare type BlobData = {
2
+ blobId: string;
3
+ lastModified?: number;
4
+ name?: string;
5
+ offset: number;
6
+ size: number;
7
+ type?: string;
8
+ };
9
+
1
10
  declare global {
2
11
  interface XMLHttpRequest {
3
12
  _requestId?: number;
@@ -10,13 +19,14 @@ declare global {
10
19
  _method?: string | null;
11
20
  _perfKey?: string | null;
12
21
  _responseType: ResponseType;
13
- _response: string;
22
+ _response: string | BlobData;
14
23
  _sent: boolean;
15
24
  _url?: string | null;
16
25
  _timedOut: boolean;
17
26
  _trackingName?: string;
18
27
  _incrementalEvents: boolean;
19
28
  _startTime?: number | null;
29
+ responseHeaders?: { [key: string]: string };
20
30
  }
21
31
  }
22
32
 
@@ -0,0 +1,80 @@
1
+ import { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+
3
+ export type RequestId = string;
4
+ export type Timestamp = number;
5
+
6
+ export type Request = {
7
+ url: string;
8
+ method: string;
9
+ headers: Record<string, string>;
10
+ postData?: string;
11
+ };
12
+
13
+ export type Response = {
14
+ url: string;
15
+ status: number;
16
+ statusText: string;
17
+ headers: Record<string, string>;
18
+ contentType: string;
19
+ size: number;
20
+ responseTime: Timestamp;
21
+ };
22
+
23
+ export type Initiator = {
24
+ type: string;
25
+ url?: string;
26
+ lineNumber?: number;
27
+ columnNumber?: number;
28
+ };
29
+
30
+ export type ResourceType = 'XHR' | 'Fetch' | 'Other';
31
+
32
+ export type NetworkActivityEventMap = {
33
+ // Control events
34
+ 'network-enable': unknown;
35
+ 'network-disable': unknown;
36
+
37
+ // Network request events
38
+ 'request-sent': {
39
+ requestId: RequestId;
40
+ request: Request;
41
+ timestamp: Timestamp;
42
+ initiator: Initiator;
43
+ type: ResourceType;
44
+ };
45
+
46
+ 'response-received': {
47
+ requestId: RequestId;
48
+ timestamp: Timestamp;
49
+ type: ResourceType;
50
+ response: Response;
51
+ };
52
+
53
+ 'request-completed': {
54
+ requestId: RequestId;
55
+ timestamp: Timestamp;
56
+ duration: number;
57
+ size: number;
58
+ ttfb: number;
59
+ };
60
+
61
+ 'request-failed': {
62
+ requestId: RequestId;
63
+ timestamp: Timestamp;
64
+ type: ResourceType;
65
+ error: string;
66
+ canceled: boolean;
67
+ };
68
+
69
+ 'get-response-body': {
70
+ requestId: RequestId;
71
+ };
72
+
73
+ 'response-body': {
74
+ requestId: RequestId;
75
+ body: string | null;
76
+ };
77
+ };
78
+
79
+ export type NetworkActivityDevToolsClient =
80
+ RozeniteDevToolsClient<NetworkActivityEventMap>;