@rozenite/network-activity-plugin 1.0.0-alpha.9 → 1.0.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.
- package/README.md +2 -0
- package/dist/App.html +2 -2
- package/dist/assets/{App-DoHQsY5s.css → App-BrSkOkws.css} +223 -2
- package/dist/assets/{App-CA1Fbh0I.js → App-C6wCDVkW.js} +8157 -2677
- package/dist/react-native.cjs +4 -1
- package/dist/react-native.js +4 -1
- package/dist/rozenite.json +1 -1
- package/dist/src/react-native/config.d.ts +20 -0
- package/dist/src/react-native/http/overrides-registry.d.ts +6 -0
- package/dist/src/react-native/http/xhr-interceptor.d.ts +7 -1
- package/dist/src/react-native/sse/sse-interceptor.d.ts +2 -2
- package/dist/src/react-native/useNetworkActivityDevTools.d.ts +2 -1
- package/dist/src/react-native/utils/getBlobName.d.ts +35 -0
- package/dist/src/react-native/utils/getFormDataEntries.d.ts +18 -0
- package/dist/src/shared/client.d.ts +48 -4
- package/dist/src/shared/sse-events.d.ts +4 -1
- package/dist/src/ui/components/Button.d.ts +2 -2
- package/dist/src/ui/components/CodeBlock.d.ts +3 -0
- package/dist/src/ui/components/CodeEditor.d.ts +5 -0
- package/dist/src/ui/components/CookieCard.d.ts +7 -0
- package/dist/src/ui/components/CopyRequestDropdown.d.ts +7 -0
- package/dist/src/ui/components/DropdownMenu.d.ts +27 -0
- package/dist/src/ui/components/FilterBar.d.ts +10 -0
- package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +1 -1
- package/dist/src/ui/components/KeyValueGrid.d.ts +13 -0
- package/dist/src/ui/components/OverrideResponse.d.ts +8 -0
- package/dist/src/ui/components/RequestBody.d.ts +6 -0
- package/dist/src/ui/components/RequestList.d.ts +9 -4
- package/dist/src/ui/components/ScrollArea.d.ts +3 -2
- package/dist/src/ui/components/Section.d.ts +8 -0
- package/dist/src/ui/components/Separator.d.ts +2 -1
- package/dist/src/ui/components/Tabs.d.ts +7 -0
- package/dist/src/ui/state/hooks.d.ts +4 -0
- package/dist/src/ui/state/model.d.ts +12 -7
- package/dist/src/ui/state/store.d.ts +27 -3
- package/dist/src/ui/utils/checkRequestBodyBinary.d.ts +2 -0
- package/dist/src/ui/utils/escapeShellArg.d.ts +1 -0
- package/dist/src/ui/utils/generateCurlCommand.d.ts +2 -0
- package/dist/src/ui/utils/generateFetchCall.d.ts +2 -0
- package/dist/src/ui/utils/generateMultipartBody.d.ts +4 -0
- package/dist/src/utils/applyReactNativeRequestHeadersLogic.d.ts +7 -0
- package/dist/src/utils/applyReactNativeResponseHeadersLogic.d.ts +9 -0
- package/dist/src/utils/cookieParser.d.ts +6 -0
- package/dist/src/utils/getContentTypeMimeType.d.ts +2 -0
- package/dist/src/utils/getHttpHeader.d.ts +5 -0
- package/dist/src/utils/getHttpHeaderValueAsString.d.ts +11 -0
- package/dist/src/utils/getStringSizeInBytes.d.ts +1 -0
- package/dist/src/utils/inferContentTypeFromPostData.d.ts +2 -0
- package/dist/src/utils/safeStringify.d.ts +1 -0
- package/dist/src/utils/typeChecks.d.ts +9 -0
- package/dist/useNetworkActivityDevTools.cjs +319 -24
- package/dist/useNetworkActivityDevTools.js +320 -25
- package/package.json +7 -4
- package/react-native.ts +6 -1
- package/src/react-native/config.ts +43 -0
- package/src/react-native/http/network-inspector.ts +170 -8
- package/src/react-native/http/overrides-registry.ts +32 -0
- package/src/react-native/http/xhr-interceptor.ts +19 -2
- package/src/react-native/sse/sse-inspector.ts +27 -5
- package/src/react-native/sse/sse-interceptor.ts +26 -8
- package/src/react-native/useNetworkActivityDevTools.ts +86 -8
- package/src/react-native/utils/getBlobName.ts +45 -0
- package/src/react-native/utils/getFormDataEntries.ts +32 -0
- package/src/react-native/utils.ts +3 -3
- package/src/shared/client.ts +73 -4
- package/src/shared/sse-events.ts +4 -1
- package/src/ui/components/Button.tsx +1 -0
- package/src/ui/components/CodeBlock.tsx +19 -0
- package/src/ui/components/CodeEditor.tsx +26 -0
- package/src/ui/components/CookieCard.tsx +64 -0
- package/src/ui/components/CopyRequestDropdown.tsx +95 -0
- package/src/ui/components/DropdownMenu.tsx +206 -0
- package/src/ui/components/FilterBar.tsx +117 -0
- package/src/ui/components/Input.tsx +1 -1
- package/src/ui/components/JsonTree.tsx +10 -3
- package/src/ui/components/JsonTreeCopyableItem.tsx +14 -10
- package/src/ui/components/KeyValueGrid.tsx +51 -0
- package/src/ui/components/OverrideResponse.tsx +132 -0
- package/src/ui/components/RequestBody.tsx +86 -0
- package/src/ui/components/RequestList.tsx +65 -13
- package/src/ui/components/ScrollArea.tsx +1 -0
- package/src/ui/components/Section.tsx +46 -0
- package/src/ui/components/SidePanel.tsx +15 -5
- package/src/ui/globals.css +4 -0
- package/src/ui/hooks/useCopyToClipboard.ts +2 -2
- package/src/ui/state/hooks.ts +8 -0
- package/src/ui/state/model.ts +18 -7
- package/src/ui/state/store.ts +610 -500
- package/src/ui/tabs/CookiesTab.tsx +60 -263
- package/src/ui/tabs/HeadersTab.tsx +78 -89
- package/src/ui/tabs/RequestTab.tsx +58 -46
- package/src/ui/tabs/ResponseTab.tsx +98 -67
- package/src/ui/tabs/SSEMessagesTab.tsx +50 -39
- package/src/ui/utils/checkRequestBodyBinary.ts +7 -0
- package/src/ui/utils/escapeShellArg.ts +12 -0
- package/src/ui/utils/generateCurlCommand.ts +83 -0
- package/src/ui/utils/generateFetchCall.ts +64 -0
- package/src/ui/utils/generateMultipartBody.ts +19 -0
- package/src/ui/views/InspectorView.tsx +15 -3
- package/src/utils/applyReactNativeRequestHeadersLogic.ts +30 -0
- package/src/utils/applyReactNativeResponseHeadersLogic.ts +28 -0
- package/src/utils/cookieParser.ts +126 -0
- package/src/utils/getContentTypeMimeType.ts +17 -0
- package/src/utils/getHttpHeader.ts +17 -0
- package/src/utils/getHttpHeaderValueAsString.ts +13 -0
- package/src/utils/getStringSizeInBytes.ts +3 -0
- package/src/utils/inferContentTypeFromPostData.ts +9 -0
- package/src/utils/safeStringify.ts +7 -0
- package/src/utils/typeChecks.ts +27 -0
- package/dist/src/ui/utils/getHttpHeaderValue.d.ts +0 -2
- package/src/ui/utils/getHttpHeaderValue.ts +0 -14
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combines multiple HTTP header values according to RFC 7230 Section 3.2.2
|
|
3
|
+
*
|
|
4
|
+
* Per RFC 7230 Section 3.2.2: "A recipient MAY combine multiple header fields
|
|
5
|
+
* with the same field name into one 'field-name: field-value' pair, without
|
|
6
|
+
* changing the semantics of the message, by appending each subsequent field
|
|
7
|
+
* value to the combined field value in order, separated by a comma."
|
|
8
|
+
*
|
|
9
|
+
* @see https://tools.ietf.org/html/rfc7230#section-3.2.2
|
|
10
|
+
*/
|
|
11
|
+
export declare function getHttpHeaderValueAsString(value: string | string[]): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getStringSizeInBytes: (value: string) => number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function safeStringify(data: unknown): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const isBlob: (value: unknown) => value is Blob;
|
|
2
|
+
export declare const isArrayBuffer: (value: unknown) => value is ArrayBuffer | ArrayBufferView;
|
|
3
|
+
export declare const isFormData: (value: unknown) => value is FormData;
|
|
4
|
+
export declare const isNullOrUndefined: (value: unknown) => value is null | undefined;
|
|
5
|
+
export declare const isString: (value: unknown) => value is string;
|
|
6
|
+
export declare const isNumber: (value: unknown) => value is number;
|
|
7
|
+
export declare const isBoolean: (value: unknown) => value is boolean;
|
|
8
|
+
export declare const isObject: (value: unknown) => value is object;
|
|
9
|
+
export declare const isArray: (value: unknown) => value is unknown[];
|
|
@@ -8,21 +8,37 @@ const WebSocketInterceptor = require("react-native/Libraries/WebSocket/WebSocket
|
|
|
8
8
|
const eventSource = require("./event-source.cjs");
|
|
9
9
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
10
10
|
const WebSocketInterceptor__default = /* @__PURE__ */ _interopDefault(WebSocketInterceptor);
|
|
11
|
-
function
|
|
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) {
|
|
12
19
|
const lowerName = name.toLowerCase();
|
|
13
20
|
for (const key in headers) {
|
|
14
21
|
if (key.toLowerCase() === lowerName) {
|
|
15
|
-
return headers[key];
|
|
22
|
+
return { value: headers[key], originalKey: key };
|
|
16
23
|
}
|
|
17
24
|
}
|
|
18
25
|
return void 0;
|
|
19
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
|
+
}
|
|
20
36
|
const getContentType = (request) => {
|
|
21
37
|
const responseHeaders = request.responseHeaders;
|
|
22
38
|
const responseType = request.responseType;
|
|
23
|
-
const contentType =
|
|
39
|
+
const contentType = getContentTypeMime(responseHeaders || {});
|
|
24
40
|
if (contentType) {
|
|
25
|
-
return contentType
|
|
41
|
+
return contentType;
|
|
26
42
|
}
|
|
27
43
|
switch (responseType) {
|
|
28
44
|
case "arraybuffer":
|
|
@@ -70,6 +86,28 @@ const getNetworkRequestsRegistry = () => {
|
|
|
70
86
|
clear
|
|
71
87
|
};
|
|
72
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;
|
|
73
111
|
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
74
112
|
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
75
113
|
const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
@@ -78,6 +116,7 @@ let sendCallback;
|
|
|
78
116
|
let requestHeaderCallback;
|
|
79
117
|
let headerReceivedCallback;
|
|
80
118
|
let responseCallback;
|
|
119
|
+
let overrideCallback;
|
|
81
120
|
let isInterceptorEnabled$1 = false;
|
|
82
121
|
const XHRInterceptor = {
|
|
83
122
|
/**
|
|
@@ -110,6 +149,12 @@ const XHRInterceptor = {
|
|
|
110
149
|
setRequestHeaderCallback(callback) {
|
|
111
150
|
requestHeaderCallback = callback;
|
|
112
151
|
},
|
|
152
|
+
/**
|
|
153
|
+
* Invoked before XMLHttpRequest.send(...) is called.
|
|
154
|
+
*/
|
|
155
|
+
setOverrideCallback(callback) {
|
|
156
|
+
overrideCallback = callback;
|
|
157
|
+
},
|
|
113
158
|
isInterceptorEnabled() {
|
|
114
159
|
return isInterceptorEnabled$1;
|
|
115
160
|
},
|
|
@@ -133,6 +178,9 @@ const XHRInterceptor = {
|
|
|
133
178
|
if (sendCallback) {
|
|
134
179
|
sendCallback(data, this);
|
|
135
180
|
}
|
|
181
|
+
if (overrideCallback) {
|
|
182
|
+
overrideCallback(this);
|
|
183
|
+
}
|
|
136
184
|
if (this.addEventListener) {
|
|
137
185
|
this.addEventListener(
|
|
138
186
|
"readystatechange",
|
|
@@ -193,14 +241,128 @@ const XHRInterceptor = {
|
|
|
193
241
|
sendCallback = null;
|
|
194
242
|
headerReceivedCallback = null;
|
|
195
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();
|
|
196
290
|
}
|
|
291
|
+
return registryInstance;
|
|
197
292
|
};
|
|
198
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
|
+
};
|
|
199
344
|
const getResponseSize = (request) => {
|
|
200
|
-
|
|
201
|
-
|
|
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;
|
|
202
365
|
}
|
|
203
|
-
return request.response.length || 0;
|
|
204
366
|
};
|
|
205
367
|
const getResponseBody = async (request) => {
|
|
206
368
|
const responseType = request.responseType;
|
|
@@ -219,6 +381,9 @@ const getResponseBody = async (request) => {
|
|
|
219
381
|
});
|
|
220
382
|
}
|
|
221
383
|
}
|
|
384
|
+
if (responseType === "json") {
|
|
385
|
+
return safeStringify(request.response);
|
|
386
|
+
}
|
|
222
387
|
return null;
|
|
223
388
|
};
|
|
224
389
|
const getInitiatorFromStack = () => {
|
|
@@ -260,7 +425,7 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
260
425
|
url: request._url,
|
|
261
426
|
method: request._method,
|
|
262
427
|
headers: request._headers,
|
|
263
|
-
postData: data
|
|
428
|
+
postData: getRequestBody(data)
|
|
264
429
|
},
|
|
265
430
|
type: "XHR",
|
|
266
431
|
initiator
|
|
@@ -279,7 +444,9 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
279
444
|
url: request._url,
|
|
280
445
|
status: request.status,
|
|
281
446
|
statusText: request.statusText,
|
|
282
|
-
headers:
|
|
447
|
+
headers: applyReactNativeResponseHeadersLogic(
|
|
448
|
+
request.responseHeaders || {}
|
|
449
|
+
),
|
|
283
450
|
contentType: getContentType(request),
|
|
284
451
|
size: getResponseSize(request),
|
|
285
452
|
responseTime: Date.now()
|
|
@@ -314,9 +481,45 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
314
481
|
});
|
|
315
482
|
});
|
|
316
483
|
};
|
|
484
|
+
const handleRequestOverride = (request) => {
|
|
485
|
+
const override = overridesRegistry$1.getOverrideForUrl(
|
|
486
|
+
request._url
|
|
487
|
+
);
|
|
488
|
+
if (!override) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
request.addEventListener("readystatechange", () => {
|
|
492
|
+
if (override.body !== void 0) {
|
|
493
|
+
Object.defineProperty(request, "responseType", {
|
|
494
|
+
writable: true
|
|
495
|
+
});
|
|
496
|
+
Object.defineProperty(request, "response", {
|
|
497
|
+
writable: true
|
|
498
|
+
});
|
|
499
|
+
Object.defineProperty(request, "responseText", {
|
|
500
|
+
writable: true
|
|
501
|
+
});
|
|
502
|
+
const contentType = getContentType(request);
|
|
503
|
+
if (contentType === "application/json") {
|
|
504
|
+
request.responseType = "json";
|
|
505
|
+
} else if (contentType === "text/plain") {
|
|
506
|
+
request.responseType = "text";
|
|
507
|
+
}
|
|
508
|
+
request.response = override.body;
|
|
509
|
+
request.responseText = override.body;
|
|
510
|
+
}
|
|
511
|
+
if (override.status !== void 0) {
|
|
512
|
+
Object.defineProperty(request, "status", {
|
|
513
|
+
writable: true
|
|
514
|
+
});
|
|
515
|
+
request.status = override.status;
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
};
|
|
317
519
|
const enable = () => {
|
|
318
520
|
XHRInterceptor.disableInterception();
|
|
319
521
|
XHRInterceptor.setSendCallback(handleRequestSend);
|
|
522
|
+
XHRInterceptor.setOverrideCallback(handleRequestOverride);
|
|
320
523
|
XHRInterceptor.enableInterception();
|
|
321
524
|
};
|
|
322
525
|
const disable = () => {
|
|
@@ -522,6 +725,8 @@ let closeCallback;
|
|
|
522
725
|
let isInterceptorEnabled = false;
|
|
523
726
|
const eventSourceClass = eventSource.getEventSource();
|
|
524
727
|
const originalOpen = eventSourceClass.prototype.open;
|
|
728
|
+
const originalDispatch = eventSourceClass.prototype.dispatch;
|
|
729
|
+
const BUILT_IN_EVENT_TYPES = /* @__PURE__ */ new Set(["open", "error", "close", "done"]);
|
|
525
730
|
const SSEInterceptor = {
|
|
526
731
|
/**
|
|
527
732
|
* Invoked when EventSource.open() is called (connection attempt starting).
|
|
@@ -569,11 +774,6 @@ const SSEInterceptor = {
|
|
|
569
774
|
openEventCallback(event, this);
|
|
570
775
|
}
|
|
571
776
|
});
|
|
572
|
-
this.addEventListener("message", (event) => {
|
|
573
|
-
if (messageCallback) {
|
|
574
|
-
messageCallback(event, this);
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
777
|
this.addEventListener(
|
|
578
778
|
"error",
|
|
579
779
|
(event) => {
|
|
@@ -589,6 +789,14 @@ const SSEInterceptor = {
|
|
|
589
789
|
});
|
|
590
790
|
return originalOpen.call(this);
|
|
591
791
|
};
|
|
792
|
+
eventSourceClass.prototype.dispatch = function(eventType, data) {
|
|
793
|
+
if (!BUILT_IN_EVENT_TYPES.has(eventType)) {
|
|
794
|
+
if (messageCallback) {
|
|
795
|
+
messageCallback(data, this);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return originalDispatch.call(this, eventType, data);
|
|
799
|
+
};
|
|
592
800
|
isInterceptorEnabled = true;
|
|
593
801
|
},
|
|
594
802
|
// Unpatch EventSource open method and remove the callbacks.
|
|
@@ -598,6 +806,7 @@ const SSEInterceptor = {
|
|
|
598
806
|
}
|
|
599
807
|
isInterceptorEnabled = false;
|
|
600
808
|
eventSourceClass.prototype.open = originalOpen;
|
|
809
|
+
eventSourceClass.prototype.dispatch = originalDispatch;
|
|
601
810
|
connectCallback = null;
|
|
602
811
|
messageCallback = null;
|
|
603
812
|
errorCallback = null;
|
|
@@ -611,9 +820,7 @@ const getSSEInspector = () => {
|
|
|
611
820
|
var _a;
|
|
612
821
|
const requestId = (_a = eventSource2._xhr) == null ? void 0 : _a._rozeniteRequestId;
|
|
613
822
|
if (!requestId) {
|
|
614
|
-
|
|
615
|
-
"No request ID found for EventSource. This should never happen!"
|
|
616
|
-
);
|
|
823
|
+
return null;
|
|
617
824
|
}
|
|
618
825
|
return requestId;
|
|
619
826
|
};
|
|
@@ -622,6 +829,9 @@ const getSSEInspector = () => {
|
|
|
622
829
|
SSEInterceptor.setOpenEventCallback((_, eventSource2) => {
|
|
623
830
|
const sseEventSource = eventSource2;
|
|
624
831
|
const requestId = getRequestId(sseEventSource);
|
|
832
|
+
if (!requestId) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
625
835
|
const sseXhr = sseEventSource._xhr;
|
|
626
836
|
const event = {
|
|
627
837
|
type: "sse-open",
|
|
@@ -642,17 +852,26 @@ const getSSEInspector = () => {
|
|
|
642
852
|
SSEInterceptor.setMessageCallback((messageEvent, eventSource2) => {
|
|
643
853
|
const sseEventSource = eventSource2;
|
|
644
854
|
const requestId = getRequestId(sseEventSource);
|
|
855
|
+
if (!requestId) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
645
858
|
const event = {
|
|
646
859
|
type: "sse-message",
|
|
647
860
|
requestId,
|
|
648
861
|
timestamp: Date.now(),
|
|
649
|
-
|
|
862
|
+
payload: {
|
|
863
|
+
type: messageEvent.type,
|
|
864
|
+
data: messageEvent.data || ""
|
|
865
|
+
}
|
|
650
866
|
};
|
|
651
867
|
eventEmitter.emit("sse-message", event);
|
|
652
868
|
});
|
|
653
869
|
SSEInterceptor.setErrorCallback((errorEvent, eventSource2) => {
|
|
654
870
|
const sseEventSource = eventSource2;
|
|
655
871
|
const requestId = getRequestId(sseEventSource);
|
|
872
|
+
if (!requestId) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
656
875
|
const event = {
|
|
657
876
|
type: "sse-error",
|
|
658
877
|
requestId,
|
|
@@ -667,6 +886,9 @@ const getSSEInspector = () => {
|
|
|
667
886
|
SSEInterceptor.setCloseCallback((_, eventSource2) => {
|
|
668
887
|
const sseEventSource = eventSource2;
|
|
669
888
|
const requestId = getRequestId(sseEventSource);
|
|
889
|
+
if (!requestId) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
670
892
|
const event = {
|
|
671
893
|
type: "sse-close",
|
|
672
894
|
requestId,
|
|
@@ -681,26 +903,93 @@ const getSSEInspector = () => {
|
|
|
681
903
|
},
|
|
682
904
|
isEnabled: () => SSEInterceptor.isInterceptorEnabled(),
|
|
683
905
|
dispose: () => {
|
|
906
|
+
SSEInterceptor.disableInterception();
|
|
684
907
|
eventEmitter.events = {};
|
|
685
908
|
},
|
|
686
909
|
on: (event, callback) => eventEmitter.on(event, callback)
|
|
687
910
|
};
|
|
688
911
|
};
|
|
689
|
-
const
|
|
912
|
+
const DEFAULT_CONFIG = {
|
|
913
|
+
inspectors: {
|
|
914
|
+
http: true,
|
|
915
|
+
websocket: true,
|
|
916
|
+
sse: true
|
|
917
|
+
},
|
|
918
|
+
clientUISettings: {
|
|
919
|
+
showUrlAsName: false
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
const validateConfig = (config) => {
|
|
923
|
+
const inspectors = config.inspectors;
|
|
924
|
+
if (!inspectors) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
if (inspectors.sse && !inspectors.http) {
|
|
928
|
+
throw new Error("SSE inspector requires HTTP inspector to be enabled.");
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
const overridesRegistry = getOverridesRegistry();
|
|
932
|
+
const useNetworkActivityDevTools = (config = DEFAULT_CONFIG) => {
|
|
933
|
+
var _a, _b, _c, _d;
|
|
934
|
+
const isRecordingEnabledRef = react.useRef(false);
|
|
690
935
|
const client = pluginBridge.useRozeniteDevToolsClient({
|
|
691
936
|
pluginId: "@rozenite/network-activity-plugin"
|
|
692
937
|
});
|
|
938
|
+
const isHttpInspectorEnabled = ((_a = config.inspectors) == null ? void 0 : _a.http) ?? true;
|
|
939
|
+
const isWebSocketInspectorEnabled = ((_b = config.inspectors) == null ? void 0 : _b.websocket) ?? true;
|
|
940
|
+
const isSSEInspectorEnabled = ((_c = config.inspectors) == null ? void 0 : _c.sse) ?? true;
|
|
941
|
+
const showUrlAsName = (_d = config.clientUISettings) == null ? void 0 : _d.showUrlAsName;
|
|
693
942
|
react.useEffect(() => {
|
|
694
943
|
if (!client) {
|
|
695
944
|
return;
|
|
696
945
|
}
|
|
946
|
+
validateConfig(config);
|
|
947
|
+
}, [config]);
|
|
948
|
+
react.useEffect(() => {
|
|
949
|
+
if (!client) {
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
const sendClientUISettings = () => {
|
|
953
|
+
var _a2;
|
|
954
|
+
client.send("client-ui-settings", {
|
|
955
|
+
settings: {
|
|
956
|
+
showUrlAsName: showUrlAsName ?? ((_a2 = DEFAULT_CONFIG.clientUISettings) == null ? void 0 : _a2.showUrlAsName)
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
};
|
|
960
|
+
const subscriptions = [
|
|
961
|
+
client.onMessage("network-enable", () => {
|
|
962
|
+
isRecordingEnabledRef.current = true;
|
|
963
|
+
}),
|
|
964
|
+
client.onMessage("network-disable", () => {
|
|
965
|
+
isRecordingEnabledRef.current = false;
|
|
966
|
+
}),
|
|
967
|
+
client.onMessage("set-overrides", (data) => {
|
|
968
|
+
overridesRegistry.setOverrides(data.overrides);
|
|
969
|
+
}),
|
|
970
|
+
client.onMessage("get-client-ui-settings", () => {
|
|
971
|
+
sendClientUISettings();
|
|
972
|
+
})
|
|
973
|
+
];
|
|
974
|
+
sendClientUISettings();
|
|
975
|
+
return () => {
|
|
976
|
+
subscriptions.forEach((subscription) => subscription.remove());
|
|
977
|
+
};
|
|
978
|
+
}, [client, showUrlAsName]);
|
|
979
|
+
react.useEffect(() => {
|
|
980
|
+
if (!client || !isHttpInspectorEnabled) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
697
983
|
const networkInspector = getNetworkInspector(client);
|
|
984
|
+
if (isRecordingEnabledRef.current) {
|
|
985
|
+
networkInspector.enable();
|
|
986
|
+
}
|
|
698
987
|
return () => {
|
|
699
988
|
networkInspector.dispose();
|
|
700
989
|
};
|
|
701
|
-
}, [client]);
|
|
990
|
+
}, [client, isHttpInspectorEnabled]);
|
|
702
991
|
react.useEffect(() => {
|
|
703
|
-
if (!client) {
|
|
992
|
+
if (!client || !isWebSocketInspectorEnabled) {
|
|
704
993
|
return;
|
|
705
994
|
}
|
|
706
995
|
const eventsToForward = [
|
|
@@ -724,12 +1013,15 @@ const useNetworkActivityDevTools = () => {
|
|
|
724
1013
|
client.onMessage("network-disable", () => {
|
|
725
1014
|
websocketInspector.disable();
|
|
726
1015
|
});
|
|
1016
|
+
if (isRecordingEnabledRef.current) {
|
|
1017
|
+
websocketInspector.enable();
|
|
1018
|
+
}
|
|
727
1019
|
return () => {
|
|
728
1020
|
websocketInspector.dispose();
|
|
729
1021
|
};
|
|
730
|
-
}, [client]);
|
|
1022
|
+
}, [client, isWebSocketInspectorEnabled]);
|
|
731
1023
|
react.useEffect(() => {
|
|
732
|
-
if (!client) {
|
|
1024
|
+
if (!client || !isSSEInspectorEnabled) {
|
|
733
1025
|
return;
|
|
734
1026
|
}
|
|
735
1027
|
const eventsToForward = [
|
|
@@ -750,10 +1042,13 @@ const useNetworkActivityDevTools = () => {
|
|
|
750
1042
|
client.onMessage("network-disable", () => {
|
|
751
1043
|
sseInspector.disable();
|
|
752
1044
|
});
|
|
1045
|
+
if (isRecordingEnabledRef.current) {
|
|
1046
|
+
sseInspector.enable();
|
|
1047
|
+
}
|
|
753
1048
|
return () => {
|
|
754
1049
|
sseInspector.dispose();
|
|
755
1050
|
};
|
|
756
|
-
}, [client]);
|
|
1051
|
+
}, [client, isSSEInspectorEnabled]);
|
|
757
1052
|
return client;
|
|
758
1053
|
};
|
|
759
1054
|
exports.useNetworkActivityDevTools = useNetworkActivityDevTools;
|