@rozenite/network-activity-plugin 1.0.0-alpha.12 → 1.0.0-alpha.13
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/dist/App.html +2 -2
- package/dist/assets/{App-JuOeT_VQ.js → App-CZPlDq_M.js} +9056 -8965
- package/dist/assets/{App-DCuHdq4D.css → App-CfJuBHc_.css} +3 -0
- package/dist/rozenite.json +1 -1
- package/dist/src/shared/client.d.ts +9 -6
- package/dist/src/ui/components/CopyRequestDropdown.d.ts +7 -0
- package/dist/src/ui/components/RequestBody.d.ts +6 -0
- package/dist/src/ui/utils/checkRequestBodyBinary.d.ts +2 -0
- package/dist/src/ui/utils/generateCurlCommand.d.ts +2 -7
- 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 +1 -2
- package/dist/src/utils/applyReactNativeResponseHeadersLogic.d.ts +1 -2
- package/dist/src/utils/getHttpHeaderValueAsString.d.ts +11 -0
- package/dist/src/utils/typeChecks.d.ts +9 -0
- package/dist/useNetworkActivityDevTools.cjs +61 -31
- package/dist/useNetworkActivityDevTools.js +61 -31
- package/package.json +4 -4
- package/src/react-native/http/network-inspector.ts +60 -28
- package/src/react-native/sse/sse-inspector.ts +22 -4
- package/src/shared/client.ts +22 -6
- package/src/ui/components/CodeBlock.tsx +1 -1
- package/src/ui/components/CopyRequestDropdown.tsx +95 -0
- package/src/ui/components/KeyValueGrid.tsx +1 -4
- package/src/ui/components/RequestBody.tsx +86 -0
- package/src/ui/components/RequestList.tsx +1 -1
- package/src/ui/state/model.ts +6 -1
- package/src/ui/tabs/CookiesTab.tsx +2 -6
- package/src/ui/tabs/HeadersTab.tsx +2 -7
- package/src/ui/tabs/RequestTab.tsx +35 -51
- package/src/ui/utils/checkRequestBodyBinary.ts +7 -0
- package/src/ui/utils/generateCurlCommand.ts +9 -12
- package/src/ui/utils/generateFetchCall.ts +64 -0
- package/src/ui/utils/generateMultipartBody.ts +19 -0
- package/src/utils/applyReactNativeRequestHeadersLogic.ts +2 -3
- package/src/utils/applyReactNativeResponseHeadersLogic.ts +2 -3
- package/src/utils/getHttpHeaderValueAsString.ts +13 -0
- package/src/utils/typeChecks.ts +27 -0
- package/dist/src/ui/components/CopyAsCurlButton.d.ts +0 -5
- package/dist/src/utils/isNumber.d.ts +0 -1
- package/src/ui/components/CopyAsCurlButton.tsx +0 -45
- package/src/utils/isNumber.ts +0 -3
package/dist/rozenite.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@rozenite/network-activity-plugin","version":"1.0.0-alpha.
|
|
1
|
+
{"name":"@rozenite/network-activity-plugin","version":"1.0.0-alpha.12","description":"Network Activity for Rozenite.","panels":[{"name":"Network Activity","source":"/App.html"}]}
|
|
@@ -7,20 +7,23 @@ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
|
|
|
7
7
|
export type RequestId = string;
|
|
8
8
|
export type Timestamp = number;
|
|
9
9
|
export type XHRPostData = string | Blob | FormData | ArrayBuffer | ArrayBufferView | unknown | null | undefined;
|
|
10
|
-
export type
|
|
10
|
+
export type RequestTextPostData = {
|
|
11
11
|
type: 'text';
|
|
12
12
|
value: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
value: Record<string, unknown>;
|
|
16
|
-
} | {
|
|
13
|
+
};
|
|
14
|
+
export type RequestBinaryPostData = {
|
|
17
15
|
type: 'binary';
|
|
18
16
|
value: {
|
|
19
17
|
size: number;
|
|
20
18
|
type?: string;
|
|
21
19
|
name?: string;
|
|
22
20
|
};
|
|
23
|
-
}
|
|
21
|
+
};
|
|
22
|
+
export type RequestFormDataPostData = {
|
|
23
|
+
type: 'form-data';
|
|
24
|
+
value: Record<string, RequestTextPostData | RequestBinaryPostData>;
|
|
25
|
+
};
|
|
26
|
+
export type RequestPostData = RequestTextPostData | RequestFormDataPostData | RequestBinaryPostData | null | undefined;
|
|
24
27
|
export type Cookie = {
|
|
25
28
|
name: string;
|
|
26
29
|
value: string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
2
|
+
type NetworkEntry = HttpNetworkEntry | SSENetworkEntry;
|
|
3
|
+
type CopyDropdownProps = {
|
|
4
|
+
selectedRequest: NetworkEntry;
|
|
5
|
+
};
|
|
6
|
+
export declare const CopyRequestDropdown: ({ selectedRequest }: CopyDropdownProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export {};
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function generateCurlCommand(request:
|
|
3
|
-
method: string;
|
|
4
|
-
url: string;
|
|
5
|
-
headers?: Record<string, string>;
|
|
6
|
-
postData?: RequestPostData;
|
|
7
|
-
}): string;
|
|
1
|
+
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
2
|
+
export declare function generateCurlCommand(request: HttpNetworkEntry | SSENetworkEntry): string;
|
|
@@ -2,7 +2,6 @@ import { HttpHeaders, RequestPostData } from '../shared/client';
|
|
|
2
2
|
/**
|
|
3
3
|
* Partially emulates React Native's behavior for setting HTTP headers.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* https://github.com/facebook/react-native/blob/de5093c88771977b58f7bec3f3ffa64a9595334e/packages/react-native/Libraries/Network/RCTNetworking.mm#L345-L349
|
|
5
|
+
* @see https://github.com/facebook/react-native/blob/de5093c88771977b58f7bec3f3ffa64a9595334e/packages/react-native/Libraries/Network/RCTNetworking.mm#L345-L349
|
|
7
6
|
*/
|
|
8
7
|
export declare function applyReactNativeRequestHeadersLogic(headers: HttpHeaders, postData?: RequestPostData): HttpHeaders;
|
|
@@ -4,7 +4,6 @@ import { HttpHeaders, XHRHeaders } from '../shared/client';
|
|
|
4
4
|
* React Native concatenates multiple header values into single strings,
|
|
5
5
|
* this function parses them back into arrays where appropriate.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* https://github.com/facebook/react-native/blob/588f0c5ce6c283f116228456da2170d2adc3cbf4/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L637
|
|
7
|
+
* @see https://github.com/facebook/react-native/blob/588f0c5ce6c283f116228456da2170d2adc3cbf4/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L637
|
|
9
8
|
*/
|
|
10
9
|
export declare const applyReactNativeResponseHeadersLogic: (headers: XHRHeaders) => HttpHeaders;
|
|
@@ -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,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[];
|
|
@@ -255,40 +255,60 @@ const applyReactNativeResponseHeadersLogic = (headers) => {
|
|
|
255
255
|
}
|
|
256
256
|
return parsedHeaders;
|
|
257
257
|
};
|
|
258
|
+
const isBlob = (value) => value instanceof Blob;
|
|
259
|
+
const isArrayBuffer = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
260
|
+
const isFormData = (value) => value instanceof FormData;
|
|
261
|
+
const isNullOrUndefined = (value) => value === null || value === void 0;
|
|
258
262
|
const networkRequestsRegistry = getNetworkRequestsRegistry();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
263
|
+
const getBinaryPostData = (body) => ({
|
|
264
|
+
type: "binary",
|
|
265
|
+
value: {
|
|
266
|
+
size: body.size,
|
|
267
|
+
type: body.type,
|
|
268
|
+
name: getBlobName(body)
|
|
262
269
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
type: body.type,
|
|
269
|
-
name: getBlobName(body)
|
|
270
|
-
}
|
|
271
|
-
};
|
|
270
|
+
});
|
|
271
|
+
const getArrayBufferPostData = (body) => ({
|
|
272
|
+
type: "binary",
|
|
273
|
+
value: {
|
|
274
|
+
size: body.byteLength
|
|
272
275
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
276
|
+
});
|
|
277
|
+
const getTextPostData = (body) => ({
|
|
278
|
+
type: "text",
|
|
279
|
+
value: safeStringify(body)
|
|
280
|
+
});
|
|
281
|
+
const getFormDataPostData = (body) => ({
|
|
282
|
+
type: "form-data",
|
|
283
|
+
value: getFormDataEntries(body).reduce(
|
|
284
|
+
(acc, [key, value]) => {
|
|
285
|
+
if (isBlob(value)) {
|
|
286
|
+
acc[key] = getBinaryPostData(value);
|
|
287
|
+
} else if (isArrayBuffer(value)) {
|
|
288
|
+
acc[key] = getArrayBufferPostData(value);
|
|
289
|
+
} else {
|
|
290
|
+
acc[key] = getTextPostData(value);
|
|
278
291
|
}
|
|
279
|
-
|
|
292
|
+
return acc;
|
|
293
|
+
},
|
|
294
|
+
{}
|
|
295
|
+
)
|
|
296
|
+
});
|
|
297
|
+
const getRequestBody = (body) => {
|
|
298
|
+
if (isNullOrUndefined(body)) {
|
|
299
|
+
return body;
|
|
280
300
|
}
|
|
281
|
-
if (body
|
|
282
|
-
return
|
|
283
|
-
type: "form-data",
|
|
284
|
-
value: Object.fromEntries(getFormDataEntries(body))
|
|
285
|
-
};
|
|
301
|
+
if (isBlob(body)) {
|
|
302
|
+
return getBinaryPostData(body);
|
|
286
303
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
304
|
+
if (isArrayBuffer(body)) {
|
|
305
|
+
return getArrayBufferPostData(body);
|
|
306
|
+
}
|
|
307
|
+
if (isFormData(body)) {
|
|
308
|
+
return getFormDataPostData(body);
|
|
309
|
+
}
|
|
310
|
+
return getTextPostData(body);
|
|
311
|
+
};
|
|
292
312
|
const getResponseSize = (request) => {
|
|
293
313
|
try {
|
|
294
314
|
const { responseType, response } = request;
|
|
@@ -732,9 +752,7 @@ const getSSEInspector = () => {
|
|
|
732
752
|
var _a;
|
|
733
753
|
const requestId = (_a = eventSource2._xhr) == null ? void 0 : _a._rozeniteRequestId;
|
|
734
754
|
if (!requestId) {
|
|
735
|
-
|
|
736
|
-
"No request ID found for EventSource. This should never happen!"
|
|
737
|
-
);
|
|
755
|
+
return null;
|
|
738
756
|
}
|
|
739
757
|
return requestId;
|
|
740
758
|
};
|
|
@@ -743,6 +761,9 @@ const getSSEInspector = () => {
|
|
|
743
761
|
SSEInterceptor.setOpenEventCallback((_, eventSource2) => {
|
|
744
762
|
const sseEventSource = eventSource2;
|
|
745
763
|
const requestId = getRequestId(sseEventSource);
|
|
764
|
+
if (!requestId) {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
746
767
|
const sseXhr = sseEventSource._xhr;
|
|
747
768
|
const event = {
|
|
748
769
|
type: "sse-open",
|
|
@@ -763,6 +784,9 @@ const getSSEInspector = () => {
|
|
|
763
784
|
SSEInterceptor.setMessageCallback((messageEvent, eventSource2) => {
|
|
764
785
|
const sseEventSource = eventSource2;
|
|
765
786
|
const requestId = getRequestId(sseEventSource);
|
|
787
|
+
if (!requestId) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
766
790
|
const event = {
|
|
767
791
|
type: "sse-message",
|
|
768
792
|
requestId,
|
|
@@ -777,6 +801,9 @@ const getSSEInspector = () => {
|
|
|
777
801
|
SSEInterceptor.setErrorCallback((errorEvent, eventSource2) => {
|
|
778
802
|
const sseEventSource = eventSource2;
|
|
779
803
|
const requestId = getRequestId(sseEventSource);
|
|
804
|
+
if (!requestId) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
780
807
|
const event = {
|
|
781
808
|
type: "sse-error",
|
|
782
809
|
requestId,
|
|
@@ -791,6 +818,9 @@ const getSSEInspector = () => {
|
|
|
791
818
|
SSEInterceptor.setCloseCallback((_, eventSource2) => {
|
|
792
819
|
const sseEventSource = eventSource2;
|
|
793
820
|
const requestId = getRequestId(sseEventSource);
|
|
821
|
+
if (!requestId) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
794
824
|
const event = {
|
|
795
825
|
type: "sse-close",
|
|
796
826
|
requestId,
|
|
@@ -251,40 +251,60 @@ const applyReactNativeResponseHeadersLogic = (headers) => {
|
|
|
251
251
|
}
|
|
252
252
|
return parsedHeaders;
|
|
253
253
|
};
|
|
254
|
+
const isBlob = (value) => value instanceof Blob;
|
|
255
|
+
const isArrayBuffer = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
256
|
+
const isFormData = (value) => value instanceof FormData;
|
|
257
|
+
const isNullOrUndefined = (value) => value === null || value === void 0;
|
|
254
258
|
const networkRequestsRegistry = getNetworkRequestsRegistry();
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
259
|
+
const getBinaryPostData = (body) => ({
|
|
260
|
+
type: "binary",
|
|
261
|
+
value: {
|
|
262
|
+
size: body.size,
|
|
263
|
+
type: body.type,
|
|
264
|
+
name: getBlobName(body)
|
|
258
265
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
type: body.type,
|
|
265
|
-
name: getBlobName(body)
|
|
266
|
-
}
|
|
267
|
-
};
|
|
266
|
+
});
|
|
267
|
+
const getArrayBufferPostData = (body) => ({
|
|
268
|
+
type: "binary",
|
|
269
|
+
value: {
|
|
270
|
+
size: body.byteLength
|
|
268
271
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
});
|
|
273
|
+
const getTextPostData = (body) => ({
|
|
274
|
+
type: "text",
|
|
275
|
+
value: safeStringify(body)
|
|
276
|
+
});
|
|
277
|
+
const getFormDataPostData = (body) => ({
|
|
278
|
+
type: "form-data",
|
|
279
|
+
value: getFormDataEntries(body).reduce(
|
|
280
|
+
(acc, [key, value]) => {
|
|
281
|
+
if (isBlob(value)) {
|
|
282
|
+
acc[key] = getBinaryPostData(value);
|
|
283
|
+
} else if (isArrayBuffer(value)) {
|
|
284
|
+
acc[key] = getArrayBufferPostData(value);
|
|
285
|
+
} else {
|
|
286
|
+
acc[key] = getTextPostData(value);
|
|
274
287
|
}
|
|
275
|
-
|
|
288
|
+
return acc;
|
|
289
|
+
},
|
|
290
|
+
{}
|
|
291
|
+
)
|
|
292
|
+
});
|
|
293
|
+
const getRequestBody = (body) => {
|
|
294
|
+
if (isNullOrUndefined(body)) {
|
|
295
|
+
return body;
|
|
276
296
|
}
|
|
277
|
-
if (body
|
|
278
|
-
return
|
|
279
|
-
type: "form-data",
|
|
280
|
-
value: Object.fromEntries(getFormDataEntries(body))
|
|
281
|
-
};
|
|
297
|
+
if (isBlob(body)) {
|
|
298
|
+
return getBinaryPostData(body);
|
|
282
299
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
300
|
+
if (isArrayBuffer(body)) {
|
|
301
|
+
return getArrayBufferPostData(body);
|
|
302
|
+
}
|
|
303
|
+
if (isFormData(body)) {
|
|
304
|
+
return getFormDataPostData(body);
|
|
305
|
+
}
|
|
306
|
+
return getTextPostData(body);
|
|
307
|
+
};
|
|
288
308
|
const getResponseSize = (request) => {
|
|
289
309
|
try {
|
|
290
310
|
const { responseType, response } = request;
|
|
@@ -728,9 +748,7 @@ const getSSEInspector = () => {
|
|
|
728
748
|
var _a;
|
|
729
749
|
const requestId = (_a = eventSource._xhr) == null ? void 0 : _a._rozeniteRequestId;
|
|
730
750
|
if (!requestId) {
|
|
731
|
-
|
|
732
|
-
"No request ID found for EventSource. This should never happen!"
|
|
733
|
-
);
|
|
751
|
+
return null;
|
|
734
752
|
}
|
|
735
753
|
return requestId;
|
|
736
754
|
};
|
|
@@ -739,6 +757,9 @@ const getSSEInspector = () => {
|
|
|
739
757
|
SSEInterceptor.setOpenEventCallback((_, eventSource) => {
|
|
740
758
|
const sseEventSource = eventSource;
|
|
741
759
|
const requestId = getRequestId(sseEventSource);
|
|
760
|
+
if (!requestId) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
742
763
|
const sseXhr = sseEventSource._xhr;
|
|
743
764
|
const event = {
|
|
744
765
|
type: "sse-open",
|
|
@@ -759,6 +780,9 @@ const getSSEInspector = () => {
|
|
|
759
780
|
SSEInterceptor.setMessageCallback((messageEvent, eventSource) => {
|
|
760
781
|
const sseEventSource = eventSource;
|
|
761
782
|
const requestId = getRequestId(sseEventSource);
|
|
783
|
+
if (!requestId) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
762
786
|
const event = {
|
|
763
787
|
type: "sse-message",
|
|
764
788
|
requestId,
|
|
@@ -773,6 +797,9 @@ const getSSEInspector = () => {
|
|
|
773
797
|
SSEInterceptor.setErrorCallback((errorEvent, eventSource) => {
|
|
774
798
|
const sseEventSource = eventSource;
|
|
775
799
|
const requestId = getRequestId(sseEventSource);
|
|
800
|
+
if (!requestId) {
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
776
803
|
const event = {
|
|
777
804
|
type: "sse-error",
|
|
778
805
|
requestId,
|
|
@@ -787,6 +814,9 @@ const getSSEInspector = () => {
|
|
|
787
814
|
SSEInterceptor.setCloseCallback((_, eventSource) => {
|
|
788
815
|
const sseEventSource = eventSource;
|
|
789
816
|
const requestId = getRequestId(sseEventSource);
|
|
817
|
+
if (!requestId) {
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
790
820
|
const event = {
|
|
791
821
|
type: "sse-close",
|
|
792
822
|
requestId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rozenite/network-activity-plugin",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.13",
|
|
4
4
|
"description": "Network Activity for Rozenite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/react-native.cjs",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"types": "./dist/react-native.d.ts",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"nanoevents": "^9.1.0",
|
|
11
|
-
"@rozenite/plugin-bridge": "1.0.0-alpha.
|
|
11
|
+
"@rozenite/plugin-bridge": "1.0.0-alpha.13"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@floating-ui/react": "^0.26.0",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"zustand": "^5.0.6",
|
|
37
37
|
"@types/react": "~18.3.23",
|
|
38
38
|
"@types/react-dom": "~18.3.1",
|
|
39
|
-
"@rozenite/vite-plugin": "1.0.0-alpha.
|
|
40
|
-
"rozenite": "1.0.0-alpha.
|
|
39
|
+
"@rozenite/vite-plugin": "1.0.0-alpha.13",
|
|
40
|
+
"rozenite": "1.0.0-alpha.13"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"react-native-sse": "*"
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
HttpMethod,
|
|
4
4
|
NetworkActivityDevToolsClient,
|
|
5
5
|
RequestPostData,
|
|
6
|
+
RequestTextPostData,
|
|
7
|
+
RequestBinaryPostData,
|
|
8
|
+
RequestFormDataPostData,
|
|
6
9
|
XHRPostData,
|
|
7
10
|
} from '../../shared/client';
|
|
8
11
|
import { getContentType } from '../utils';
|
|
@@ -12,46 +15,75 @@ import { getFormDataEntries } from '../utils/getFormDataEntries';
|
|
|
12
15
|
import { XHRInterceptor } from './xhr-interceptor';
|
|
13
16
|
import { getStringSizeInBytes } from '../../utils/getStringSizeInBytes';
|
|
14
17
|
import { applyReactNativeResponseHeadersLogic } from '../../utils/applyReactNativeResponseHeadersLogic';
|
|
18
|
+
import {
|
|
19
|
+
isBlob,
|
|
20
|
+
isArrayBuffer,
|
|
21
|
+
isFormData,
|
|
22
|
+
isNullOrUndefined,
|
|
23
|
+
} from '../../utils/typeChecks';
|
|
15
24
|
|
|
16
25
|
const networkRequestsRegistry = getNetworkRequestsRegistry();
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
const getBinaryPostData = (body: Blob): RequestBinaryPostData => ({
|
|
28
|
+
type: 'binary',
|
|
29
|
+
value: {
|
|
30
|
+
size: body.size,
|
|
31
|
+
type: body.type,
|
|
32
|
+
name: getBlobName(body),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const getArrayBufferPostData = (
|
|
37
|
+
body: ArrayBuffer | ArrayBufferView
|
|
38
|
+
): RequestBinaryPostData => ({
|
|
39
|
+
type: 'binary',
|
|
40
|
+
value: {
|
|
41
|
+
size: body.byteLength,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const getTextPostData = (body: unknown): RequestTextPostData => ({
|
|
46
|
+
type: 'text',
|
|
47
|
+
value: safeStringify(body),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const getFormDataPostData = (body: FormData): RequestFormDataPostData => ({
|
|
51
|
+
type: 'form-data',
|
|
52
|
+
value: getFormDataEntries(body).reduce<RequestFormDataPostData['value']>(
|
|
53
|
+
(acc, [key, value]) => {
|
|
54
|
+
if (isBlob(value)) {
|
|
55
|
+
acc[key] = getBinaryPostData(value);
|
|
56
|
+
} else if (isArrayBuffer(value)) {
|
|
57
|
+
acc[key] = getArrayBufferPostData(value);
|
|
58
|
+
} else {
|
|
59
|
+
acc[key] = getTextPostData(value);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return acc;
|
|
63
|
+
},
|
|
64
|
+
{}
|
|
65
|
+
),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const getRequestBody = (body: XHRPostData): RequestPostData => {
|
|
69
|
+
if (isNullOrUndefined(body)) {
|
|
20
70
|
return body;
|
|
21
71
|
}
|
|
22
72
|
|
|
23
|
-
if (body
|
|
24
|
-
return
|
|
25
|
-
type: 'binary',
|
|
26
|
-
value: {
|
|
27
|
-
size: body.size,
|
|
28
|
-
type: body.type,
|
|
29
|
-
name: getBlobName(body),
|
|
30
|
-
},
|
|
31
|
-
};
|
|
73
|
+
if (isBlob(body)) {
|
|
74
|
+
return getBinaryPostData(body);
|
|
32
75
|
}
|
|
33
76
|
|
|
34
|
-
if (
|
|
35
|
-
return
|
|
36
|
-
type: 'binary',
|
|
37
|
-
value: {
|
|
38
|
-
size: body.byteLength,
|
|
39
|
-
},
|
|
40
|
-
};
|
|
77
|
+
if (isArrayBuffer(body)) {
|
|
78
|
+
return getArrayBufferPostData(body);
|
|
41
79
|
}
|
|
42
80
|
|
|
43
|
-
if (body
|
|
44
|
-
return
|
|
45
|
-
type: 'form-data',
|
|
46
|
-
value: Object.fromEntries(getFormDataEntries(body)),
|
|
47
|
-
};
|
|
81
|
+
if (isFormData(body)) {
|
|
82
|
+
return getFormDataPostData(body);
|
|
48
83
|
}
|
|
49
84
|
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
value: safeStringify(body),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
85
|
+
return getTextPostData(body);
|
|
86
|
+
};
|
|
55
87
|
|
|
56
88
|
const getResponseSize = (request: XMLHttpRequest): number | null => {
|
|
57
89
|
try {
|
|
@@ -22,13 +22,14 @@ export type SSEInspector = {
|
|
|
22
22
|
export const getSSEInspector = (): SSEInspector => {
|
|
23
23
|
const eventEmitter = createNanoEvents<NanoEventsMap>();
|
|
24
24
|
|
|
25
|
-
const getRequestId = (
|
|
25
|
+
const getRequestId = (
|
|
26
|
+
eventSource: EventSourceWithInternals
|
|
27
|
+
): string | null => {
|
|
26
28
|
const requestId = eventSource._xhr?._rozeniteRequestId;
|
|
27
29
|
|
|
28
30
|
if (!requestId) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
31
|
+
// It means that the EventSource was created before the inspector was enabled.
|
|
32
|
+
return null;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
return requestId;
|
|
@@ -39,6 +40,11 @@ export const getSSEInspector = (): SSEInspector => {
|
|
|
39
40
|
SSEInterceptor.setOpenEventCallback((_, eventSource) => {
|
|
40
41
|
const sseEventSource = eventSource as EventSourceWithInternals;
|
|
41
42
|
const requestId = getRequestId(sseEventSource);
|
|
43
|
+
|
|
44
|
+
if (!requestId) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
const sseXhr = sseEventSource._xhr as XMLHttpRequest;
|
|
43
49
|
|
|
44
50
|
const event: SSEEvent = {
|
|
@@ -62,6 +68,10 @@ export const getSSEInspector = (): SSEInspector => {
|
|
|
62
68
|
const sseEventSource = eventSource as EventSourceWithInternals;
|
|
63
69
|
const requestId = getRequestId(sseEventSource);
|
|
64
70
|
|
|
71
|
+
if (!requestId) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
const event: SSEEvent = {
|
|
66
76
|
type: 'sse-message',
|
|
67
77
|
requestId,
|
|
@@ -78,6 +88,10 @@ export const getSSEInspector = (): SSEInspector => {
|
|
|
78
88
|
const sseEventSource = eventSource as EventSourceWithInternals;
|
|
79
89
|
const requestId = getRequestId(sseEventSource);
|
|
80
90
|
|
|
91
|
+
if (!requestId) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
81
95
|
const event: SSEEvent = {
|
|
82
96
|
type: 'sse-error',
|
|
83
97
|
requestId,
|
|
@@ -95,6 +109,10 @@ export const getSSEInspector = (): SSEInspector => {
|
|
|
95
109
|
const sseEventSource = eventSource as EventSourceWithInternals;
|
|
96
110
|
const requestId = getRequestId(sseEventSource);
|
|
97
111
|
|
|
112
|
+
if (!requestId) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
98
116
|
const event: SSEEvent = {
|
|
99
117
|
type: 'sse-close',
|
|
100
118
|
requestId,
|
package/src/shared/client.ts
CHANGED
|
@@ -20,13 +20,29 @@ export type XHRPostData =
|
|
|
20
20
|
| null
|
|
21
21
|
| undefined;
|
|
22
22
|
|
|
23
|
+
export type RequestTextPostData = {
|
|
24
|
+
type: 'text';
|
|
25
|
+
value: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type RequestBinaryPostData = {
|
|
29
|
+
type: 'binary';
|
|
30
|
+
value: {
|
|
31
|
+
size: number;
|
|
32
|
+
type?: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type RequestFormDataPostData = {
|
|
38
|
+
type: 'form-data';
|
|
39
|
+
value: Record<string, RequestTextPostData | RequestBinaryPostData>;
|
|
40
|
+
};
|
|
41
|
+
|
|
23
42
|
export type RequestPostData =
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
type: 'binary';
|
|
28
|
-
value: { size: number; type?: string; name?: string };
|
|
29
|
-
}
|
|
43
|
+
| RequestTextPostData
|
|
44
|
+
| RequestFormDataPostData
|
|
45
|
+
| RequestBinaryPostData
|
|
30
46
|
| null
|
|
31
47
|
| undefined;
|
|
32
48
|
|
|
@@ -4,7 +4,7 @@ import { cn } from '../utils/cn';
|
|
|
4
4
|
export type CodeBlockProps = HTMLProps<HTMLPreElement>;
|
|
5
5
|
|
|
6
6
|
const codeBlockClassNames =
|
|
7
|
-
'text-sm font-mono text-gray-300 whitespace-pre-wrap bg-gray-800 p-3 rounded border border-gray-700 overflow-x-auto wrap-anywhere';
|
|
7
|
+
'text-sm font-mono text-gray-300 whitespace-pre-wrap bg-gray-800 p-3 rounded-md border border-gray-700 overflow-x-auto wrap-anywhere';
|
|
8
8
|
|
|
9
9
|
export const CodeBlock = ({
|
|
10
10
|
children,
|