@rozenite/network-activity-plugin 1.0.0-alpha.9 → 1.1.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-Kyi7zHUX.js} +8188 -2671
- 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 +55 -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 +22 -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 +337 -24
- package/dist/useNetworkActivityDevTools.js +338 -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 +190 -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 +81 -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 +74 -14
- 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/components/Toolbar.tsx +3 -2
- package/src/ui/globals.css +4 -0
- package/src/ui/hooks/useCopyToClipboard.ts +2 -2
- package/src/ui/state/derived.ts +2 -0
- package/src/ui/state/hooks.ts +8 -0
- package/src/ui/state/model.ts +28 -7
- package/src/ui/state/store.ts +640 -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,9 @@
|
|
|
1
|
+
import { HttpHeaders, XHRHeaders } from '../shared/client';
|
|
2
|
+
/**
|
|
3
|
+
* Applies React Native specific logic to response headers.
|
|
4
|
+
* React Native concatenates multiple header values into single strings,
|
|
5
|
+
* this function parses them back into arrays where appropriate.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/facebook/react-native/blob/588f0c5ce6c283f116228456da2170d2adc3cbf4/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L637
|
|
8
|
+
*/
|
|
9
|
+
export declare const applyReactNativeResponseHeadersLogic: (headers: XHRHeaders) => HttpHeaders;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Cookie, HttpHeaders } from '../shared/client';
|
|
2
|
+
export declare const parseSetCookieHeader: (setCookieStr: string) => Cookie;
|
|
3
|
+
export declare const splitSetCookieHeaderByComma: (header: string) => string[];
|
|
4
|
+
export declare const parseCookieHeader: (cookieString: string) => Cookie[];
|
|
5
|
+
export declare const parseRequestCookiesFromHeaders: (headers: HttpHeaders) => Cookie[];
|
|
6
|
+
export declare const parseResponseCookiesFromHeaders: (headers: HttpHeaders) => Cookie[];
|
|
@@ -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,11 +425,20 @@ 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
|
|
267
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
|
+
});
|
|
268
442
|
request.addEventListener("readystatechange", () => {
|
|
269
443
|
if (request.readyState === READY_STATE_HEADERS_RECEIVED) {
|
|
270
444
|
ttfb = Date.now() - sendTime;
|
|
@@ -279,7 +453,9 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
279
453
|
url: request._url,
|
|
280
454
|
status: request.status,
|
|
281
455
|
statusText: request.statusText,
|
|
282
|
-
headers:
|
|
456
|
+
headers: applyReactNativeResponseHeadersLogic(
|
|
457
|
+
request.responseHeaders || {}
|
|
458
|
+
),
|
|
283
459
|
contentType: getContentType(request),
|
|
284
460
|
size: getResponseSize(request),
|
|
285
461
|
responseTime: Date.now()
|
|
@@ -313,10 +489,55 @@ const getNetworkInspector = (pluginClient) => {
|
|
|
313
489
|
canceled: true
|
|
314
490
|
});
|
|
315
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) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
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";
|
|
525
|
+
}
|
|
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
|
|
532
|
+
});
|
|
533
|
+
request.status = override.status;
|
|
534
|
+
}
|
|
535
|
+
});
|
|
316
536
|
};
|
|
317
537
|
const enable = () => {
|
|
318
538
|
XHRInterceptor.disableInterception();
|
|
319
539
|
XHRInterceptor.setSendCallback(handleRequestSend);
|
|
540
|
+
XHRInterceptor.setOverrideCallback(handleRequestOverride);
|
|
320
541
|
XHRInterceptor.enableInterception();
|
|
321
542
|
};
|
|
322
543
|
const disable = () => {
|
|
@@ -522,6 +743,8 @@ let closeCallback;
|
|
|
522
743
|
let isInterceptorEnabled = false;
|
|
523
744
|
const eventSourceClass = eventSource.getEventSource();
|
|
524
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"]);
|
|
525
748
|
const SSEInterceptor = {
|
|
526
749
|
/**
|
|
527
750
|
* Invoked when EventSource.open() is called (connection attempt starting).
|
|
@@ -569,11 +792,6 @@ const SSEInterceptor = {
|
|
|
569
792
|
openEventCallback(event, this);
|
|
570
793
|
}
|
|
571
794
|
});
|
|
572
|
-
this.addEventListener("message", (event) => {
|
|
573
|
-
if (messageCallback) {
|
|
574
|
-
messageCallback(event, this);
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
795
|
this.addEventListener(
|
|
578
796
|
"error",
|
|
579
797
|
(event) => {
|
|
@@ -589,6 +807,14 @@ const SSEInterceptor = {
|
|
|
589
807
|
});
|
|
590
808
|
return originalOpen.call(this);
|
|
591
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);
|
|
817
|
+
};
|
|
592
818
|
isInterceptorEnabled = true;
|
|
593
819
|
},
|
|
594
820
|
// Unpatch EventSource open method and remove the callbacks.
|
|
@@ -598,6 +824,7 @@ const SSEInterceptor = {
|
|
|
598
824
|
}
|
|
599
825
|
isInterceptorEnabled = false;
|
|
600
826
|
eventSourceClass.prototype.open = originalOpen;
|
|
827
|
+
eventSourceClass.prototype.dispatch = originalDispatch;
|
|
601
828
|
connectCallback = null;
|
|
602
829
|
messageCallback = null;
|
|
603
830
|
errorCallback = null;
|
|
@@ -611,9 +838,7 @@ const getSSEInspector = () => {
|
|
|
611
838
|
var _a;
|
|
612
839
|
const requestId = (_a = eventSource2._xhr) == null ? void 0 : _a._rozeniteRequestId;
|
|
613
840
|
if (!requestId) {
|
|
614
|
-
|
|
615
|
-
"No request ID found for EventSource. This should never happen!"
|
|
616
|
-
);
|
|
841
|
+
return null;
|
|
617
842
|
}
|
|
618
843
|
return requestId;
|
|
619
844
|
};
|
|
@@ -622,6 +847,9 @@ const getSSEInspector = () => {
|
|
|
622
847
|
SSEInterceptor.setOpenEventCallback((_, eventSource2) => {
|
|
623
848
|
const sseEventSource = eventSource2;
|
|
624
849
|
const requestId = getRequestId(sseEventSource);
|
|
850
|
+
if (!requestId) {
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
625
853
|
const sseXhr = sseEventSource._xhr;
|
|
626
854
|
const event = {
|
|
627
855
|
type: "sse-open",
|
|
@@ -642,17 +870,26 @@ const getSSEInspector = () => {
|
|
|
642
870
|
SSEInterceptor.setMessageCallback((messageEvent, eventSource2) => {
|
|
643
871
|
const sseEventSource = eventSource2;
|
|
644
872
|
const requestId = getRequestId(sseEventSource);
|
|
873
|
+
if (!requestId) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
645
876
|
const event = {
|
|
646
877
|
type: "sse-message",
|
|
647
878
|
requestId,
|
|
648
879
|
timestamp: Date.now(),
|
|
649
|
-
|
|
880
|
+
payload: {
|
|
881
|
+
type: messageEvent.type,
|
|
882
|
+
data: messageEvent.data || ""
|
|
883
|
+
}
|
|
650
884
|
};
|
|
651
885
|
eventEmitter.emit("sse-message", event);
|
|
652
886
|
});
|
|
653
887
|
SSEInterceptor.setErrorCallback((errorEvent, eventSource2) => {
|
|
654
888
|
const sseEventSource = eventSource2;
|
|
655
889
|
const requestId = getRequestId(sseEventSource);
|
|
890
|
+
if (!requestId) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
656
893
|
const event = {
|
|
657
894
|
type: "sse-error",
|
|
658
895
|
requestId,
|
|
@@ -667,6 +904,9 @@ const getSSEInspector = () => {
|
|
|
667
904
|
SSEInterceptor.setCloseCallback((_, eventSource2) => {
|
|
668
905
|
const sseEventSource = eventSource2;
|
|
669
906
|
const requestId = getRequestId(sseEventSource);
|
|
907
|
+
if (!requestId) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
670
910
|
const event = {
|
|
671
911
|
type: "sse-close",
|
|
672
912
|
requestId,
|
|
@@ -681,26 +921,93 @@ const getSSEInspector = () => {
|
|
|
681
921
|
},
|
|
682
922
|
isEnabled: () => SSEInterceptor.isInterceptorEnabled(),
|
|
683
923
|
dispose: () => {
|
|
924
|
+
SSEInterceptor.disableInterception();
|
|
684
925
|
eventEmitter.events = {};
|
|
685
926
|
},
|
|
686
927
|
on: (event, callback) => eventEmitter.on(event, callback)
|
|
687
928
|
};
|
|
688
929
|
};
|
|
689
|
-
const
|
|
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
|
+
}
|
|
948
|
+
};
|
|
949
|
+
const overridesRegistry = getOverridesRegistry();
|
|
950
|
+
const useNetworkActivityDevTools = (config = DEFAULT_CONFIG) => {
|
|
951
|
+
var _a, _b, _c, _d;
|
|
952
|
+
const isRecordingEnabledRef = react.useRef(false);
|
|
690
953
|
const client = pluginBridge.useRozeniteDevToolsClient({
|
|
691
954
|
pluginId: "@rozenite/network-activity-plugin"
|
|
692
955
|
});
|
|
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;
|
|
693
960
|
react.useEffect(() => {
|
|
694
961
|
if (!client) {
|
|
695
962
|
return;
|
|
696
963
|
}
|
|
964
|
+
validateConfig(config);
|
|
965
|
+
}, [config]);
|
|
966
|
+
react.useEffect(() => {
|
|
967
|
+
if (!client) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const sendClientUISettings = () => {
|
|
971
|
+
var _a2;
|
|
972
|
+
client.send("client-ui-settings", {
|
|
973
|
+
settings: {
|
|
974
|
+
showUrlAsName: showUrlAsName ?? ((_a2 = DEFAULT_CONFIG.clientUISettings) == null ? void 0 : _a2.showUrlAsName)
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
};
|
|
978
|
+
const subscriptions = [
|
|
979
|
+
client.onMessage("network-enable", () => {
|
|
980
|
+
isRecordingEnabledRef.current = true;
|
|
981
|
+
}),
|
|
982
|
+
client.onMessage("network-disable", () => {
|
|
983
|
+
isRecordingEnabledRef.current = false;
|
|
984
|
+
}),
|
|
985
|
+
client.onMessage("set-overrides", (data) => {
|
|
986
|
+
overridesRegistry.setOverrides(data.overrides);
|
|
987
|
+
}),
|
|
988
|
+
client.onMessage("get-client-ui-settings", () => {
|
|
989
|
+
sendClientUISettings();
|
|
990
|
+
})
|
|
991
|
+
];
|
|
992
|
+
sendClientUISettings();
|
|
993
|
+
return () => {
|
|
994
|
+
subscriptions.forEach((subscription) => subscription.remove());
|
|
995
|
+
};
|
|
996
|
+
}, [client, showUrlAsName]);
|
|
997
|
+
react.useEffect(() => {
|
|
998
|
+
if (!client || !isHttpInspectorEnabled) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
697
1001
|
const networkInspector = getNetworkInspector(client);
|
|
1002
|
+
if (isRecordingEnabledRef.current) {
|
|
1003
|
+
networkInspector.enable();
|
|
1004
|
+
}
|
|
698
1005
|
return () => {
|
|
699
1006
|
networkInspector.dispose();
|
|
700
1007
|
};
|
|
701
|
-
}, [client]);
|
|
1008
|
+
}, [client, isHttpInspectorEnabled]);
|
|
702
1009
|
react.useEffect(() => {
|
|
703
|
-
if (!client) {
|
|
1010
|
+
if (!client || !isWebSocketInspectorEnabled) {
|
|
704
1011
|
return;
|
|
705
1012
|
}
|
|
706
1013
|
const eventsToForward = [
|
|
@@ -724,12 +1031,15 @@ const useNetworkActivityDevTools = () => {
|
|
|
724
1031
|
client.onMessage("network-disable", () => {
|
|
725
1032
|
websocketInspector.disable();
|
|
726
1033
|
});
|
|
1034
|
+
if (isRecordingEnabledRef.current) {
|
|
1035
|
+
websocketInspector.enable();
|
|
1036
|
+
}
|
|
727
1037
|
return () => {
|
|
728
1038
|
websocketInspector.dispose();
|
|
729
1039
|
};
|
|
730
|
-
}, [client]);
|
|
1040
|
+
}, [client, isWebSocketInspectorEnabled]);
|
|
731
1041
|
react.useEffect(() => {
|
|
732
|
-
if (!client) {
|
|
1042
|
+
if (!client || !isSSEInspectorEnabled) {
|
|
733
1043
|
return;
|
|
734
1044
|
}
|
|
735
1045
|
const eventsToForward = [
|
|
@@ -750,10 +1060,13 @@ const useNetworkActivityDevTools = () => {
|
|
|
750
1060
|
client.onMessage("network-disable", () => {
|
|
751
1061
|
sseInspector.disable();
|
|
752
1062
|
});
|
|
1063
|
+
if (isRecordingEnabledRef.current) {
|
|
1064
|
+
sseInspector.enable();
|
|
1065
|
+
}
|
|
753
1066
|
return () => {
|
|
754
1067
|
sseInspector.dispose();
|
|
755
1068
|
};
|
|
756
|
-
}, [client]);
|
|
1069
|
+
}, [client, isSSEInspectorEnabled]);
|
|
757
1070
|
return client;
|
|
758
1071
|
};
|
|
759
1072
|
exports.useNetworkActivityDevTools = useNetworkActivityDevTools;
|