@rozenite/network-activity-plugin 1.0.0-alpha.10-canary.1754923715388 → 1.0.0-alpha.11
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-BE5UWKca.js → App-BKBLGSeM.js} +106 -75
- package/dist/assets/{App-zkbklFIE.css → App-Ct73Yrm6.css} +19 -6
- package/dist/src/ui/components/CopyAsCurlButton.d.ts +2 -2
- package/dist/src/ui/components/KeyValueGrid.d.ts +13 -0
- package/dist/src/ui/components/Section.d.ts +6 -0
- package/dist/useNetworkActivityDevTools.cjs +4 -0
- package/dist/useNetworkActivityDevTools.js +4 -0
- package/package.json +4 -4
- package/src/react-native/http/network-inspector.ts +5 -0
- package/src/react-native/http/xhr-interceptor.ts +1 -0
- package/src/ui/components/CopyAsCurlButton.tsx +2 -2
- package/src/ui/components/KeyValueGrid.tsx +54 -0
- package/src/ui/components/ScrollArea.tsx +1 -0
- package/src/ui/components/Section.tsx +15 -0
- package/src/ui/components/SidePanel.tsx +7 -5
- package/src/ui/globals.css +4 -0
- package/src/ui/tabs/HeadersTab.tsx +70 -89
package/dist/App.html
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
<script>
|
|
23
23
|
var __ROZENITE_PANEL__ = true;
|
|
24
24
|
</script>
|
|
25
|
-
<script type="module" crossorigin src="./assets/App-
|
|
26
|
-
<link rel="stylesheet" crossorigin href="./assets/App-
|
|
25
|
+
<script type="module" crossorigin src="./assets/App-BKBLGSeM.js"></script>
|
|
26
|
+
<link rel="stylesheet" crossorigin href="./assets/App-Ct73Yrm6.css">
|
|
27
27
|
</head>
|
|
28
28
|
<body>
|
|
29
29
|
<div id="root"></div>
|
|
@@ -20556,6 +20556,7 @@ const ScrollArea = reactExports.forwardRef(({ className, children, ...props }, r
|
|
|
20556
20556
|
children: [
|
|
20557
20557
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Viewport, { className: "h-full w-full rounded-[inherit]", children }),
|
|
20558
20558
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ScrollBar, {}),
|
|
20559
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ScrollBar, { orientation: "horizontal" }),
|
|
20559
20560
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Corner, {})
|
|
20560
20561
|
]
|
|
20561
20562
|
}
|
|
@@ -20577,6 +20578,38 @@ const ScrollBar = reactExports.forwardRef(({ className, orientation = "vertical"
|
|
|
20577
20578
|
}
|
|
20578
20579
|
));
|
|
20579
20580
|
ScrollBar.displayName = ScrollAreaScrollbar.displayName;
|
|
20581
|
+
const Section = ({ title, children }) => {
|
|
20582
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
20583
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-sm font-medium text-gray-300 mb-2", children: title }),
|
|
20584
|
+
children
|
|
20585
|
+
] });
|
|
20586
|
+
};
|
|
20587
|
+
const KeyValueGrid = ({
|
|
20588
|
+
items = [],
|
|
20589
|
+
emptyMessage,
|
|
20590
|
+
className
|
|
20591
|
+
}) => {
|
|
20592
|
+
const gridClassName = cn(
|
|
20593
|
+
"grid grid-cols-[minmax(7rem,25%)_minmax(3rem,1fr)] gap-x-2 gap-y-2 text-sm",
|
|
20594
|
+
className
|
|
20595
|
+
);
|
|
20596
|
+
if (items.length === 0) {
|
|
20597
|
+
return emptyMessage ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: gridClassName, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "col-span-2 text-gray-500 italic", children: emptyMessage }) }) : null;
|
|
20598
|
+
}
|
|
20599
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: gridClassName, children: items.map((item, index2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(reactExports.Fragment, { children: [
|
|
20600
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20601
|
+
"span",
|
|
20602
|
+
{
|
|
20603
|
+
className: cn(
|
|
20604
|
+
"text-gray-400 wrap-anywhere",
|
|
20605
|
+
item.keyClassName
|
|
20606
|
+
),
|
|
20607
|
+
children: item.key
|
|
20608
|
+
}
|
|
20609
|
+
),
|
|
20610
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("wrap-anywhere", item.valueClassName), children: item.value })
|
|
20611
|
+
] }, index2)) });
|
|
20612
|
+
};
|
|
20580
20613
|
async function copyToClipboard(text2) {
|
|
20581
20614
|
return navigator.clipboard.writeText(text2);
|
|
20582
20615
|
}
|
|
@@ -20693,78 +20726,74 @@ const CopyAsCurlButton = ({
|
|
|
20693
20726
|
);
|
|
20694
20727
|
};
|
|
20695
20728
|
const HeadersTab = ({ selectedRequest }) => {
|
|
20696
|
-
var _a, _b
|
|
20697
|
-
const
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
20701
|
-
|
|
20729
|
+
var _a, _b;
|
|
20730
|
+
const requestBody = selectedRequest.request.body;
|
|
20731
|
+
const generalItems = reactExports.useMemo(
|
|
20732
|
+
() => {
|
|
20733
|
+
var _a2, _b2;
|
|
20734
|
+
return [
|
|
20735
|
+
{
|
|
20736
|
+
key: "Request URL",
|
|
20737
|
+
value: selectedRequest.request.url,
|
|
20738
|
+
valueClassName: "text-blue-400"
|
|
20739
|
+
},
|
|
20740
|
+
{
|
|
20741
|
+
key: "Request Method",
|
|
20742
|
+
value: selectedRequest.request.method
|
|
20743
|
+
},
|
|
20744
|
+
{
|
|
20745
|
+
key: "Status Code",
|
|
20746
|
+
value: ((_a2 = selectedRequest.response) == null ? void 0 : _a2.status) ?? "Pending",
|
|
20747
|
+
valueClassName: getStatusColor(((_b2 = selectedRequest.response) == null ? void 0 : _b2.status) ?? 0)
|
|
20748
|
+
},
|
|
20749
|
+
...requestBody ? [
|
|
20750
|
+
{
|
|
20751
|
+
key: "Content-Type",
|
|
20752
|
+
value: requestBody.type,
|
|
20753
|
+
valueClassName: "text-blue-400"
|
|
20754
|
+
}
|
|
20755
|
+
] : []
|
|
20756
|
+
];
|
|
20757
|
+
},
|
|
20758
|
+
[selectedRequest]
|
|
20759
|
+
);
|
|
20760
|
+
const responseHeadersItems = reactExports.useMemo(() => {
|
|
20761
|
+
var _a2;
|
|
20762
|
+
const headers = (_a2 = selectedRequest.response) == null ? void 0 : _a2.headers;
|
|
20763
|
+
if (!headers) return [];
|
|
20764
|
+
return Object.entries(headers).map(([key, value]) => ({
|
|
20765
|
+
key: key.toLowerCase(),
|
|
20766
|
+
value
|
|
20767
|
+
}));
|
|
20768
|
+
}, [(_a = selectedRequest.response) == null ? void 0 : _a.headers]);
|
|
20769
|
+
const requestHeadersItems = reactExports.useMemo(() => {
|
|
20770
|
+
const headers = selectedRequest.request.headers;
|
|
20771
|
+
if (!headers) return [];
|
|
20772
|
+
return Object.entries(headers).map(([key, value]) => ({
|
|
20773
|
+
key: key.toLowerCase(),
|
|
20774
|
+
value
|
|
20775
|
+
}));
|
|
20776
|
+
}, [selectedRequest.request.headers]);
|
|
20777
|
+
const isCopyAsCurlEnabled = ((_b = selectedRequest.request.body) == null ? void 0 : _b.data.type) !== "binary";
|
|
20702
20778
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "h-full w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 space-y-4", children: [
|
|
20703
20779
|
isCopyAsCurlEnabled && /* @__PURE__ */ jsxRuntimeExports.jsx(CopyAsCurlButton, { selectedRequest }),
|
|
20704
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
((_b = selectedRequest.response) == null ? void 0 : _b.status) ?? 0
|
|
20722
|
-
),
|
|
20723
|
-
children: ((_c = selectedRequest.response) == null ? void 0 : _c.status) ?? "Pending"
|
|
20724
|
-
}
|
|
20725
|
-
)
|
|
20726
|
-
] }),
|
|
20727
|
-
selectedRequest.request.body && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex", children: [
|
|
20728
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-32 text-gray-400", children: "Content-Type:" }),
|
|
20729
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400", children: selectedRequest.request.body.type })
|
|
20730
|
-
] })
|
|
20731
|
-
] })
|
|
20732
|
-
] }),
|
|
20733
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
20734
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-sm font-medium text-gray-300 mb-2", children: "Response Headers" }),
|
|
20735
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 text-sm font-mono", children: (() => {
|
|
20736
|
-
var _a2;
|
|
20737
|
-
const responseHeaders = (_a2 = selectedRequest.response) == null ? void 0 : _a2.headers;
|
|
20738
|
-
if (responseHeaders && Object.keys(responseHeaders).length > 0) {
|
|
20739
|
-
return Object.entries(responseHeaders).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex", children: [
|
|
20740
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "w-32 text-gray-400", children: [
|
|
20741
|
-
key.toLowerCase(),
|
|
20742
|
-
":"
|
|
20743
|
-
] }),
|
|
20744
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 break-all", children: value })
|
|
20745
|
-
] }, key));
|
|
20746
|
-
} else {
|
|
20747
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-gray-500 italic", children: "No response headers available" });
|
|
20748
|
-
}
|
|
20749
|
-
})() })
|
|
20750
|
-
] }),
|
|
20751
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
20752
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-sm font-medium text-gray-300 mb-2", children: "Request Headers" }),
|
|
20753
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 text-sm font-mono", children: (() => {
|
|
20754
|
-
const requestHeaders = selectedRequest.request.headers;
|
|
20755
|
-
if (requestHeaders && Object.keys(requestHeaders).length > 0) {
|
|
20756
|
-
return Object.entries(requestHeaders).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex", children: [
|
|
20757
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "w-32 text-gray-400", children: [
|
|
20758
|
-
key.toLowerCase(),
|
|
20759
|
-
":"
|
|
20760
|
-
] }),
|
|
20761
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 break-all", children: value })
|
|
20762
|
-
] }, key));
|
|
20763
|
-
} else {
|
|
20764
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-gray-500 italic", children: "No request headers available" });
|
|
20765
|
-
}
|
|
20766
|
-
})() })
|
|
20767
|
-
] })
|
|
20780
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Section, { title: "General", children: /* @__PURE__ */ jsxRuntimeExports.jsx(KeyValueGrid, { items: generalItems }) }),
|
|
20781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Section, { title: "Response Headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20782
|
+
KeyValueGrid,
|
|
20783
|
+
{
|
|
20784
|
+
items: responseHeadersItems,
|
|
20785
|
+
emptyMessage: "No response headers available",
|
|
20786
|
+
className: "font-mono"
|
|
20787
|
+
}
|
|
20788
|
+
) }),
|
|
20789
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Section, { title: "Request Headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20790
|
+
KeyValueGrid,
|
|
20791
|
+
{
|
|
20792
|
+
items: requestHeadersItems,
|
|
20793
|
+
emptyMessage: "No request headers available",
|
|
20794
|
+
className: "font-mono"
|
|
20795
|
+
}
|
|
20796
|
+
) })
|
|
20768
20797
|
] }) });
|
|
20769
20798
|
};
|
|
20770
20799
|
var colorString = { exports: {} };
|
|
@@ -25461,21 +25490,23 @@ const SidePanel = () => {
|
|
|
25461
25490
|
};
|
|
25462
25491
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-1/2 flex flex-col bg-gray-900", children: [
|
|
25463
25492
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-3 border-b border-gray-700 bg-gray-800", children: [
|
|
25464
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
25493
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
|
|
25465
25494
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
25466
25495
|
"div",
|
|
25467
25496
|
{
|
|
25468
|
-
className: `w-3 h-3 rounded-full ${getTypeColor(
|
|
25497
|
+
className: `w-3 h-3 rounded-full flex-shrink-0 ${getTypeColor(
|
|
25469
25498
|
selectedRequest.type
|
|
25470
25499
|
)}`
|
|
25471
25500
|
}
|
|
25472
25501
|
),
|
|
25473
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: requestName }),
|
|
25502
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium truncate", children: requestName }),
|
|
25474
25503
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
25475
25504
|
Badge,
|
|
25476
25505
|
{
|
|
25477
25506
|
variant: "outline",
|
|
25478
|
-
className: `${getStatusColor(
|
|
25507
|
+
className: `${getStatusColor(
|
|
25508
|
+
requestStatus
|
|
25509
|
+
)} border-current flex-shrink-0`,
|
|
25479
25510
|
children: requestStatus
|
|
25480
25511
|
}
|
|
25481
25512
|
)
|
|
@@ -25486,7 +25517,7 @@ const SidePanel = () => {
|
|
|
25486
25517
|
variant: "ghost",
|
|
25487
25518
|
size: "sm",
|
|
25488
25519
|
onClick: onClose,
|
|
25489
|
-
className: "h-6 w-6 p-0 text-gray-400 hover:text-blue-400",
|
|
25520
|
+
className: "h-6 w-6 p-0 text-gray-400 hover:text-blue-400 flex-shrink-0 ml-2",
|
|
25490
25521
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "h-4 w-4" })
|
|
25491
25522
|
}
|
|
25492
25523
|
)
|
|
@@ -562,6 +562,9 @@ video {
|
|
|
562
562
|
.z-50 {
|
|
563
563
|
z-index: 50;
|
|
564
564
|
}
|
|
565
|
+
.col-span-2 {
|
|
566
|
+
grid-column: span 2 / span 2;
|
|
567
|
+
}
|
|
565
568
|
.-m-2 {
|
|
566
569
|
margin: -0.5rem;
|
|
567
570
|
}
|
|
@@ -690,9 +693,6 @@ video {
|
|
|
690
693
|
.w-3\.5 {
|
|
691
694
|
width: 0.875rem;
|
|
692
695
|
}
|
|
693
|
-
.w-32 {
|
|
694
|
-
width: 8rem;
|
|
695
|
-
}
|
|
696
696
|
.w-4 {
|
|
697
697
|
width: 1rem;
|
|
698
698
|
}
|
|
@@ -720,6 +720,9 @@ video {
|
|
|
720
720
|
.flex-1 {
|
|
721
721
|
flex: 1 1 0%;
|
|
722
722
|
}
|
|
723
|
+
.flex-shrink-0 {
|
|
724
|
+
flex-shrink: 0;
|
|
725
|
+
}
|
|
723
726
|
.shrink-0 {
|
|
724
727
|
flex-shrink: 0;
|
|
725
728
|
}
|
|
@@ -756,6 +759,9 @@ video {
|
|
|
756
759
|
.grid-cols-5 {
|
|
757
760
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
758
761
|
}
|
|
762
|
+
.grid-cols-\[minmax\(7rem\2c 25\%\)_minmax\(3rem\2c 1fr\)\] {
|
|
763
|
+
grid-template-columns: minmax(7rem,25%) minmax(3rem,1fr);
|
|
764
|
+
}
|
|
759
765
|
.flex-col {
|
|
760
766
|
flex-direction: column;
|
|
761
767
|
}
|
|
@@ -777,6 +783,13 @@ video {
|
|
|
777
783
|
.gap-4 {
|
|
778
784
|
gap: 1rem;
|
|
779
785
|
}
|
|
786
|
+
.gap-x-2 {
|
|
787
|
+
-moz-column-gap: 0.5rem;
|
|
788
|
+
column-gap: 0.5rem;
|
|
789
|
+
}
|
|
790
|
+
.gap-y-2 {
|
|
791
|
+
row-gap: 0.5rem;
|
|
792
|
+
}
|
|
780
793
|
.space-y-1 > :not([hidden]) ~ :not([hidden]) {
|
|
781
794
|
--tw-space-y-reverse: 0;
|
|
782
795
|
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
|
|
@@ -825,9 +838,6 @@ video {
|
|
|
825
838
|
.whitespace-pre-wrap {
|
|
826
839
|
white-space: pre-wrap;
|
|
827
840
|
}
|
|
828
|
-
.break-all {
|
|
829
|
-
word-break: break-all;
|
|
830
|
-
}
|
|
831
841
|
.rounded {
|
|
832
842
|
border-radius: 0.25rem;
|
|
833
843
|
}
|
|
@@ -1221,6 +1231,9 @@ video {
|
|
|
1221
1231
|
transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));
|
|
1222
1232
|
}
|
|
1223
1233
|
}
|
|
1234
|
+
.wrap-anywhere {
|
|
1235
|
+
overflow-wrap: anywhere;
|
|
1236
|
+
}
|
|
1224
1237
|
.file\:border-0::file-selector-button {
|
|
1225
1238
|
border-width: 0px;
|
|
1226
1239
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HttpNetworkEntry } from '../state/model';
|
|
1
|
+
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
2
2
|
export type CopyAsCurlButtonProps = {
|
|
3
|
-
selectedRequest?: HttpNetworkEntry;
|
|
3
|
+
selectedRequest?: HttpNetworkEntry | SSENetworkEntry;
|
|
4
4
|
};
|
|
5
5
|
export declare const CopyAsCurlButton: ({ selectedRequest, }: CopyAsCurlButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type KeyValueItem = {
|
|
3
|
+
key: string;
|
|
4
|
+
value: React.ReactNode;
|
|
5
|
+
keyClassName?: string;
|
|
6
|
+
valueClassName?: string;
|
|
7
|
+
};
|
|
8
|
+
export type KeyValueGridProps = {
|
|
9
|
+
items?: KeyValueItem[];
|
|
10
|
+
emptyMessage?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const KeyValueGrid: ({ items, emptyMessage, className, }: KeyValueGridProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -105,6 +105,7 @@ function getFormDataEntries(formData) {
|
|
|
105
105
|
}
|
|
106
106
|
return [];
|
|
107
107
|
}
|
|
108
|
+
const XMLHttpRequest = global.XMLHttpRequest || window.XMLHttpRequest;
|
|
108
109
|
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
109
110
|
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
110
111
|
const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
@@ -265,6 +266,9 @@ function getRequestBody(body) {
|
|
|
265
266
|
};
|
|
266
267
|
}
|
|
267
268
|
const getResponseSize = (request) => {
|
|
269
|
+
if (request.response === null) {
|
|
270
|
+
return 0;
|
|
271
|
+
}
|
|
268
272
|
if (typeof request.response === "object") {
|
|
269
273
|
return request.response.size;
|
|
270
274
|
}
|
|
@@ -101,6 +101,7 @@ function getFormDataEntries(formData) {
|
|
|
101
101
|
}
|
|
102
102
|
return [];
|
|
103
103
|
}
|
|
104
|
+
const XMLHttpRequest = global.XMLHttpRequest || window.XMLHttpRequest;
|
|
104
105
|
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
105
106
|
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
106
107
|
const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
@@ -261,6 +262,9 @@ function getRequestBody(body) {
|
|
|
261
262
|
};
|
|
262
263
|
}
|
|
263
264
|
const getResponseSize = (request) => {
|
|
265
|
+
if (request.response === null) {
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
264
268
|
if (typeof request.response === "object") {
|
|
265
269
|
return request.response.size;
|
|
266
270
|
}
|
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.11",
|
|
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.11"
|
|
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
|
-
"
|
|
40
|
-
"rozenite": "1.0.0-alpha.
|
|
39
|
+
"rozenite": "1.0.0-alpha.11",
|
|
40
|
+
"@rozenite/vite-plugin": "1.0.0-alpha.11"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"react-native-sse": "*"
|
|
@@ -52,6 +52,11 @@ function getRequestBody(body: XHRPostData): RequestPostData {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const getResponseSize = (request: XMLHttpRequest): number => {
|
|
55
|
+
// Handle a case of 204 where no-content was sent.
|
|
56
|
+
if (request.response === null) {
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
if (typeof request.response === 'object') {
|
|
56
61
|
return request.response.size;
|
|
57
62
|
}
|
|
@@ -11,6 +11,7 @@ import { XHRPostData } from '../../shared/client';
|
|
|
11
11
|
* Source: https://github.com/facebook/react-native/blob/2c683c5787dd03ac15d2aad45dcc53650529ee7f/packages/react-native/src/private/devsupport/devmenu/elementinspector/XHRInterceptor.js
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
const XMLHttpRequest = global.XMLHttpRequest || window.XMLHttpRequest;
|
|
14
15
|
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
15
16
|
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
16
17
|
const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
@@ -2,10 +2,10 @@ import { useCopyToClipboard } from '../hooks/useCopyToClipboard';
|
|
|
2
2
|
import { Copy, Check } from 'lucide-react';
|
|
3
3
|
import { Button } from './Button';
|
|
4
4
|
import { generateCurlCommand } from '../utils/generateCurlCommand';
|
|
5
|
-
import { HttpNetworkEntry } from '../state/model';
|
|
5
|
+
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
6
6
|
|
|
7
7
|
export type CopyAsCurlButtonProps = {
|
|
8
|
-
selectedRequest?: HttpNetworkEntry;
|
|
8
|
+
selectedRequest?: HttpNetworkEntry | SSENetworkEntry;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export const CopyAsCurlButton = ({
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
|
|
4
|
+
export type KeyValueItem = {
|
|
5
|
+
key: string;
|
|
6
|
+
value: React.ReactNode;
|
|
7
|
+
keyClassName?: string;
|
|
8
|
+
valueClassName?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type KeyValueGridProps = {
|
|
12
|
+
items?: KeyValueItem[];
|
|
13
|
+
emptyMessage?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const KeyValueGrid = ({
|
|
18
|
+
items = [],
|
|
19
|
+
emptyMessage,
|
|
20
|
+
className,
|
|
21
|
+
}: KeyValueGridProps) => {
|
|
22
|
+
const gridClassName = cn(
|
|
23
|
+
'grid grid-cols-[minmax(7rem,25%)_minmax(3rem,1fr)] gap-x-2 gap-y-2 text-sm',
|
|
24
|
+
className
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (items.length === 0) {
|
|
28
|
+
return emptyMessage ? (
|
|
29
|
+
<div className={gridClassName}>
|
|
30
|
+
<span className="col-span-2 text-gray-500 italic">{emptyMessage}</span>
|
|
31
|
+
</div>
|
|
32
|
+
) : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className={gridClassName}>
|
|
37
|
+
{items.map((item, index) => (
|
|
38
|
+
<Fragment key={index}>
|
|
39
|
+
<span
|
|
40
|
+
className={cn(
|
|
41
|
+
'text-gray-400 wrap-anywhere',
|
|
42
|
+
item.keyClassName
|
|
43
|
+
)}
|
|
44
|
+
>
|
|
45
|
+
{item.key}
|
|
46
|
+
</span>
|
|
47
|
+
<span className={cn('wrap-anywhere', item.valueClassName)}>
|
|
48
|
+
{item.value}
|
|
49
|
+
</span>
|
|
50
|
+
</Fragment>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export type SectionProps = {
|
|
4
|
+
title: string;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const Section = ({ title, children }: SectionProps) => {
|
|
9
|
+
return (
|
|
10
|
+
<div>
|
|
11
|
+
<h4 className="text-sm font-medium text-gray-300 mb-2">{title}</h4>
|
|
12
|
+
{children}
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -278,16 +278,18 @@ export const SidePanel = () => {
|
|
|
278
278
|
<div className="w-1/2 flex flex-col bg-gray-900">
|
|
279
279
|
{/* Side Panel Header */}
|
|
280
280
|
<div className="flex items-center justify-between p-3 border-b border-gray-700 bg-gray-800">
|
|
281
|
-
<div className="flex items-center gap-2">
|
|
281
|
+
<div className="flex items-center gap-2 min-w-0 flex-1">
|
|
282
282
|
<div
|
|
283
|
-
className={`w-3 h-3 rounded-full ${getTypeColor(
|
|
283
|
+
className={`w-3 h-3 rounded-full flex-shrink-0 ${getTypeColor(
|
|
284
284
|
selectedRequest.type
|
|
285
285
|
)}`}
|
|
286
286
|
></div>
|
|
287
|
-
<span className="font-medium">{requestName}</span>
|
|
287
|
+
<span className="font-medium truncate">{requestName}</span>
|
|
288
288
|
<Badge
|
|
289
289
|
variant="outline"
|
|
290
|
-
className={`${getStatusColor(
|
|
290
|
+
className={`${getStatusColor(
|
|
291
|
+
requestStatus
|
|
292
|
+
)} border-current flex-shrink-0`}
|
|
291
293
|
>
|
|
292
294
|
{requestStatus}
|
|
293
295
|
</Badge>
|
|
@@ -296,7 +298,7 @@ export const SidePanel = () => {
|
|
|
296
298
|
variant="ghost"
|
|
297
299
|
size="sm"
|
|
298
300
|
onClick={onClose}
|
|
299
|
-
className="h-6 w-6 p-0 text-gray-400 hover:text-blue-400"
|
|
301
|
+
className="h-6 w-6 p-0 text-gray-400 hover:text-blue-400 flex-shrink-0 ml-2"
|
|
300
302
|
>
|
|
301
303
|
<X className="h-4 w-4" />
|
|
302
304
|
</Button>
|
package/src/ui/globals.css
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { ScrollArea } from '../components/ScrollArea';
|
|
3
|
+
import { Section } from '../components/Section';
|
|
4
|
+
import { KeyValueGrid, KeyValueItem } from '../components/KeyValueGrid';
|
|
3
5
|
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
4
6
|
import { getStatusColor } from '../utils/getStatusColor';
|
|
5
7
|
import { CopyAsCurlButton } from '../components/CopyAsCurlButton';
|
|
@@ -9,11 +11,58 @@ export type HeadersTabProps = {
|
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
export const HeadersTab = ({ selectedRequest }: HeadersTabProps) => {
|
|
12
|
-
const
|
|
13
|
-
const { hostname, port, pathname } = new URL(selectedRequest.request.url);
|
|
14
|
+
const requestBody = selectedRequest.request.body;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
const generalItems: KeyValueItem[] = useMemo(
|
|
17
|
+
() => [
|
|
18
|
+
{
|
|
19
|
+
key: 'Request URL',
|
|
20
|
+
value: selectedRequest.request.url,
|
|
21
|
+
valueClassName: 'text-blue-400',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
key: 'Request Method',
|
|
25
|
+
value: selectedRequest.request.method,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: 'Status Code',
|
|
29
|
+
value: selectedRequest.response?.status ?? 'Pending',
|
|
30
|
+
valueClassName: getStatusColor(selectedRequest.response?.status ?? 0),
|
|
31
|
+
},
|
|
32
|
+
...(requestBody
|
|
33
|
+
? [
|
|
34
|
+
{
|
|
35
|
+
key: 'Content-Type',
|
|
36
|
+
value: requestBody.type,
|
|
37
|
+
valueClassName: 'text-blue-400',
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
: []),
|
|
41
|
+
],
|
|
42
|
+
[selectedRequest]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const responseHeadersItems: KeyValueItem[] = useMemo(() => {
|
|
46
|
+
const headers = selectedRequest.response?.headers;
|
|
47
|
+
|
|
48
|
+
if (!headers) return [];
|
|
49
|
+
|
|
50
|
+
return Object.entries(headers).map(([key, value]) => ({
|
|
51
|
+
key: key.toLowerCase(),
|
|
52
|
+
value,
|
|
53
|
+
}));
|
|
54
|
+
}, [selectedRequest.response?.headers]);
|
|
55
|
+
|
|
56
|
+
const requestHeadersItems: KeyValueItem[] = useMemo(() => {
|
|
57
|
+
const headers = selectedRequest.request.headers;
|
|
58
|
+
|
|
59
|
+
if (!headers) return [];
|
|
60
|
+
|
|
61
|
+
return Object.entries(headers).map(([key, value]) => ({
|
|
62
|
+
key: key.toLowerCase(),
|
|
63
|
+
value,
|
|
64
|
+
}));
|
|
65
|
+
}, [selectedRequest.request.headers]);
|
|
17
66
|
|
|
18
67
|
const isCopyAsCurlEnabled =
|
|
19
68
|
selectedRequest.request.body?.data.type !== 'binary';
|
|
@@ -24,93 +73,25 @@ export const HeadersTab = ({ selectedRequest }: HeadersTabProps) => {
|
|
|
24
73
|
{isCopyAsCurlEnabled && (
|
|
25
74
|
<CopyAsCurlButton selectedRequest={selectedRequest} />
|
|
26
75
|
)}
|
|
27
|
-
<
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
<div className="flex">
|
|
31
|
-
<span className="w-32 text-gray-400">Request URL:</span>
|
|
32
|
-
<span className="text-blue-400">
|
|
33
|
-
{url}
|
|
34
|
-
</span>
|
|
35
|
-
</div>
|
|
36
|
-
<div className="flex">
|
|
37
|
-
<span className="w-32 text-gray-400">Request Method:</span>
|
|
38
|
-
<span>{selectedRequest.request.method}</span>
|
|
39
|
-
</div>
|
|
40
|
-
<div className="flex">
|
|
41
|
-
<span className="w-32 text-gray-400">Status Code:</span>
|
|
42
|
-
<span
|
|
43
|
-
className={getStatusColor(
|
|
44
|
-
selectedRequest.response?.status ?? 0
|
|
45
|
-
)}
|
|
46
|
-
>
|
|
47
|
-
{selectedRequest.response?.status ?? 'Pending'}
|
|
48
|
-
</span>
|
|
49
|
-
</div>
|
|
50
|
-
{selectedRequest.request.body && (
|
|
51
|
-
<div className="flex">
|
|
52
|
-
<span className="w-32 text-gray-400">Content-Type:</span>
|
|
53
|
-
<span className="text-blue-400">
|
|
54
|
-
{selectedRequest.request.body.type}
|
|
55
|
-
</span>
|
|
56
|
-
</div>
|
|
57
|
-
)}
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
76
|
+
<Section title="General">
|
|
77
|
+
<KeyValueGrid items={generalItems} />
|
|
78
|
+
</Section>
|
|
60
79
|
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (responseHeaders && Object.keys(responseHeaders).length > 0) {
|
|
69
|
-
return Object.entries(responseHeaders).map(([key, value]) => (
|
|
70
|
-
<div key={key} className="flex">
|
|
71
|
-
<span className="w-32 text-gray-400">
|
|
72
|
-
{key.toLowerCase()}:
|
|
73
|
-
</span>
|
|
74
|
-
<span className="flex-1 break-all">{value}</span>
|
|
75
|
-
</div>
|
|
76
|
-
));
|
|
77
|
-
} else {
|
|
78
|
-
return (
|
|
79
|
-
<div className="text-gray-500 italic">
|
|
80
|
-
No response headers available
|
|
81
|
-
</div>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
})()}
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
80
|
+
<Section title="Response Headers">
|
|
81
|
+
<KeyValueGrid
|
|
82
|
+
items={responseHeadersItems}
|
|
83
|
+
emptyMessage="No response headers available"
|
|
84
|
+
className="font-mono"
|
|
85
|
+
/>
|
|
86
|
+
</Section>
|
|
87
87
|
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (requestHeaders && Object.keys(requestHeaders).length > 0) {
|
|
96
|
-
return Object.entries(requestHeaders).map(([key, value]) => (
|
|
97
|
-
<div key={key} className="flex">
|
|
98
|
-
<span className="w-32 text-gray-400">
|
|
99
|
-
{key.toLowerCase()}:
|
|
100
|
-
</span>
|
|
101
|
-
<span className="flex-1 break-all">{value}</span>
|
|
102
|
-
</div>
|
|
103
|
-
));
|
|
104
|
-
} else {
|
|
105
|
-
return (
|
|
106
|
-
<div className="text-gray-500 italic">
|
|
107
|
-
No request headers available
|
|
108
|
-
</div>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
})()}
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
88
|
+
<Section title="Request Headers">
|
|
89
|
+
<KeyValueGrid
|
|
90
|
+
items={requestHeadersItems}
|
|
91
|
+
emptyMessage="No request headers available"
|
|
92
|
+
className="font-mono"
|
|
93
|
+
/>
|
|
94
|
+
</Section>
|
|
114
95
|
</div>
|
|
115
96
|
</ScrollArea>
|
|
116
97
|
);
|