@rozenite/network-activity-plugin 1.0.0-alpha.7 → 1.0.0-alpha.9
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-CIflVb88.js → App-CA1Fbh0I.js} +12009 -10809
- package/dist/assets/{App-Czu6Vt2P.css → App-DoHQsY5s.css} +43 -0
- package/dist/event-source.cjs +22 -0
- package/dist/event-source.js +23 -0
- package/dist/rozenite.json +1 -1
- package/dist/src/react-native/{network-inspector.d.ts → http/network-inspector.d.ts} +1 -1
- package/dist/src/react-native/sse/event-source.d.ts +2 -0
- package/dist/src/react-native/sse/sse-inspector.d.ts +9 -0
- package/dist/src/react-native/sse/sse-interceptor.d.ts +36 -0
- package/dist/src/react-native/sse/types.d.ts +6 -0
- package/dist/src/react-native/utils.d.ts +6 -0
- package/dist/src/react-native/websocket/websocket-inspector.d.ts +9 -0
- package/dist/src/react-native/websocket/websocket-interceptor.d.ts +74 -0
- package/dist/src/shared/client.d.ts +8 -4
- package/dist/src/shared/sse-events.d.ts +35 -0
- package/dist/src/shared/websocket-events.d.ts +60 -0
- package/dist/src/ui/components/Badge.d.ts +1 -1
- package/dist/src/ui/components/Button.d.ts +1 -1
- package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +7 -0
- package/dist/src/ui/components/RequestList.d.ts +6 -26
- package/dist/src/ui/components/SidePanel.d.ts +1 -0
- package/dist/src/ui/components/Toolbar.d.ts +1 -0
- package/dist/src/ui/hooks/useCopyToClipboard.d.ts +4 -0
- package/dist/src/ui/state/derived.d.ts +5 -0
- package/dist/src/ui/state/hooks.d.ts +17 -0
- package/dist/src/ui/state/model.d.ts +98 -0
- package/dist/src/ui/state/store.d.ts +24 -0
- package/dist/src/ui/tabs/CookiesTab.d.ts +3 -6
- package/dist/src/ui/tabs/HeadersTab.d.ts +3 -15
- package/dist/src/ui/tabs/MessagesTab.d.ts +5 -0
- package/dist/src/ui/tabs/RequestTab.d.ts +2 -7
- package/dist/src/ui/tabs/ResponseTab.d.ts +2 -8
- package/dist/src/ui/tabs/SSEMessagesTab.d.ts +5 -0
- package/dist/src/ui/tabs/TimingTab.d.ts +3 -5
- package/dist/src/ui/types.d.ts +6 -3
- package/dist/src/ui/utils/assert.d.ts +1 -0
- package/dist/src/ui/utils/copyToClipboard.d.ts +1 -0
- package/dist/src/ui/utils/getHttpHeaderValue.d.ts +2 -0
- package/dist/src/ui/utils/getId.d.ts +1 -0
- package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
- package/dist/useNetworkActivityDevTools.cjs +433 -34
- package/dist/useNetworkActivityDevTools.js +431 -34
- package/package.json +19 -8
- package/src/react-native/{network-inspector.ts → http/network-inspector.ts} +14 -32
- package/src/react-native/{xml-request.d.ts → http/xml-request.d.ts} +1 -0
- package/src/react-native/sse/event-source.ts +25 -0
- package/src/react-native/sse/sse-inspector.ts +117 -0
- package/src/react-native/sse/sse-interceptor.ts +162 -0
- package/src/react-native/sse/types.ts +9 -0
- package/src/react-native/useNetworkActivityDevTools.ts +75 -1
- package/src/react-native/utils.ts +43 -0
- package/src/react-native/websocket/websocket-inspector.ts +180 -0
- package/src/react-native/websocket/websocket-interceptor.d.ts +4 -0
- package/src/react-native/websocket/websocket-interceptor.ts +166 -0
- package/src/shared/client.ts +10 -4
- package/src/shared/sse-events.ts +44 -0
- package/src/shared/websocket-events.ts +79 -0
- package/src/ui/components/Badge.tsx +1 -1
- package/src/ui/components/Button.tsx +1 -1
- package/src/ui/components/Input.tsx +1 -1
- package/src/ui/components/JsonTree.tsx +13 -0
- package/src/ui/components/JsonTreeCopyableItem.tsx +33 -0
- package/src/ui/components/RequestList.tsx +42 -123
- package/src/ui/components/ScrollArea.tsx +1 -1
- package/src/ui/components/Separator.tsx +1 -1
- package/src/ui/components/SidePanel.tsx +323 -0
- package/src/ui/components/Tabs.tsx +2 -2
- package/src/ui/components/Toolbar.tsx +45 -0
- package/src/ui/hooks/useCopyToClipboard.ts +28 -0
- package/src/ui/state/derived.ts +112 -0
- package/src/ui/state/hooks.ts +44 -0
- package/src/ui/state/model.ts +129 -0
- package/src/ui/state/store.ts +559 -0
- package/src/ui/tabs/CookiesTab.tsx +168 -179
- package/src/ui/tabs/HeadersTab.tsx +24 -31
- package/src/ui/tabs/MessagesTab.tsx +276 -0
- package/src/ui/tabs/RequestTab.tsx +28 -31
- package/src/ui/tabs/ResponseTab.tsx +10 -12
- package/src/ui/tabs/SSEMessagesTab.tsx +213 -0
- package/src/ui/tabs/TimingTab.tsx +33 -44
- package/src/ui/types.ts +6 -2
- package/src/ui/utils/assert.ts +5 -0
- package/src/ui/utils/copyToClipboard.ts +3 -0
- package/src/ui/utils/getHttpHeaderValue.ts +14 -0
- package/src/ui/utils/getId.ts +10 -0
- package/src/ui/utils/getStatusColor.ts +15 -0
- package/src/ui/views/InspectorView.tsx +24 -320
- package/tailwind.config.ts +3 -0
- package/vite.config.ts +12 -0
- /package/dist/src/react-native/{network-requests-registry.d.ts → http/network-requests-registry.d.ts} +0 -0
- /package/dist/src/react-native/{xhr-interceptor.d.ts → http/xhr-interceptor.d.ts} +0 -0
- /package/dist/src/ui/{utils.d.ts → utils/cn.d.ts} +0 -0
- /package/src/react-native/{network-requests-registry.ts → http/network-requests-registry.ts} +0 -0
- /package/src/react-native/{xhr-interceptor.ts → http/xhr-interceptor.ts} +0 -0
- /package/src/ui/{utils.ts → utils/cn.ts} +0 -0
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
import { ScrollArea } from '../components/ScrollArea';
|
|
2
|
-
import {
|
|
3
|
-
import { NetworkEntry } from '../types';
|
|
2
|
+
import { HttpNetworkEntry } from '../state/model';
|
|
4
3
|
|
|
5
4
|
export type TimingTabProps = {
|
|
6
|
-
selectedRequest:
|
|
7
|
-
networkEntries: Map<string, NetworkEntry>;
|
|
5
|
+
selectedRequest: HttpNetworkEntry;
|
|
8
6
|
};
|
|
9
7
|
|
|
10
|
-
export const TimingTab = ({
|
|
11
|
-
selectedRequest
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const networkEntry = selectedRequest
|
|
15
|
-
? networkEntries.get(selectedRequest.id)
|
|
8
|
+
export const TimingTab = ({ selectedRequest }: TimingTabProps) => {
|
|
9
|
+
const startTime = selectedRequest.timestamp || 0;
|
|
10
|
+
const endTime = selectedRequest.duration
|
|
11
|
+
? selectedRequest.timestamp + selectedRequest.duration
|
|
16
12
|
: null;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div className="flex items-center justify-center h-full text-gray-400">
|
|
21
|
-
Select a request to view timing information
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const startTime = networkEntry.startTime || 0;
|
|
27
|
-
const endTime = networkEntry.endTime || 0;
|
|
28
|
-
const ttfb = networkEntry.ttfb || 0;
|
|
29
|
-
const duration = networkEntry.duration || 0;
|
|
13
|
+
const ttfb = selectedRequest.ttfb || 0;
|
|
14
|
+
const duration = selectedRequest.duration || 0;
|
|
30
15
|
|
|
31
16
|
const formatTime = (time: number): string => {
|
|
32
17
|
if (time < 1) {
|
|
@@ -40,29 +25,33 @@ export const TimingTab = ({
|
|
|
40
25
|
};
|
|
41
26
|
|
|
42
27
|
return (
|
|
43
|
-
<ScrollArea className="h-full
|
|
44
|
-
<div className="
|
|
45
|
-
<div className="space-y-
|
|
46
|
-
<div className="
|
|
47
|
-
<
|
|
48
|
-
|
|
28
|
+
<ScrollArea className="h-full w-full">
|
|
29
|
+
<div className="p-4">
|
|
30
|
+
<div className="space-y-4">
|
|
31
|
+
<div className="space-y-2">
|
|
32
|
+
<div className="flex justify-between text-sm">
|
|
33
|
+
<span className="text-gray-400">Start Time</span>
|
|
34
|
+
<span className="text-gray-300">
|
|
35
|
+
{formatTimestamp(startTime)}
|
|
36
|
+
</span>
|
|
37
|
+
</div>
|
|
38
|
+
<div className="flex justify-between text-sm">
|
|
39
|
+
<span className="text-gray-400">Time To First Byte (TTFB)</span>
|
|
40
|
+
<span className="text-gray-300">{formatTime(ttfb)}</span>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="flex justify-between text-sm">
|
|
43
|
+
<span className="text-gray-400">End Time</span>
|
|
44
|
+
<span className="text-gray-300">
|
|
45
|
+
{endTime ? formatTimestamp(endTime) : 'Pending'}
|
|
46
|
+
</span>
|
|
47
|
+
</div>
|
|
49
48
|
</div>
|
|
50
|
-
<div className="flex justify-between text-sm">
|
|
51
|
-
<span className="text-gray-400">Time To First Byte (TTFB)</span>
|
|
52
|
-
<span className="text-gray-300">{formatTime(ttfb)}</span>
|
|
53
|
-
</div>
|
|
54
|
-
<div className="flex justify-between text-sm">
|
|
55
|
-
<span className="text-gray-400">End Time</span>
|
|
56
|
-
<span className="text-gray-300">
|
|
57
|
-
{endTime ? formatTimestamp(endTime) : 'Pending'}
|
|
58
|
-
</span>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
<div className="border-t border-gray-700 pt-4">
|
|
51
|
+
<div className="flex justify-between text-sm font-medium">
|
|
52
|
+
<span className="text-gray-300">Total Duration</span>
|
|
53
|
+
<span className="text-gray-100">{formatTime(duration)}</span>
|
|
54
|
+
</div>
|
|
66
55
|
</div>
|
|
67
56
|
</div>
|
|
68
57
|
</div>
|
package/src/ui/types.ts
CHANGED
|
@@ -4,14 +4,18 @@ import {
|
|
|
4
4
|
Response,
|
|
5
5
|
Initiator,
|
|
6
6
|
ResourceType,
|
|
7
|
+
HttpHeaders,
|
|
7
8
|
} from '../shared/client';
|
|
8
9
|
|
|
9
10
|
export type NetworkEntry = {
|
|
10
11
|
requestId: RequestId;
|
|
11
12
|
url: string;
|
|
12
13
|
method: string;
|
|
13
|
-
headers:
|
|
14
|
-
|
|
14
|
+
headers: HttpHeaders;
|
|
15
|
+
body?: {
|
|
16
|
+
type: string;
|
|
17
|
+
data: string;
|
|
18
|
+
};
|
|
15
19
|
status: 'pending' | 'loading' | 'finished' | 'failed';
|
|
16
20
|
startTime: number;
|
|
17
21
|
endTime?: number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HttpHeaders } from "../../shared/client";
|
|
2
|
+
|
|
3
|
+
// Utility to get header value case-insensitively
|
|
4
|
+
export function getHttpHeaderValue(headers: HttpHeaders, name: string) {
|
|
5
|
+
const lowerName = name.toLowerCase();
|
|
6
|
+
|
|
7
|
+
for (const key in headers) {
|
|
8
|
+
if (key.toLowerCase() === lowerName) {
|
|
9
|
+
return headers[key];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const idMap = new Map<string, number>();
|
|
2
|
+
|
|
3
|
+
export const getId = (namespace: string) => {
|
|
4
|
+
if (!idMap.has(namespace)) {
|
|
5
|
+
idMap.set(namespace, 0);
|
|
6
|
+
}
|
|
7
|
+
const id = idMap.get(namespace) ?? 0;
|
|
8
|
+
idMap.set(namespace, id + 1);
|
|
9
|
+
return `${namespace}-${id}`;
|
|
10
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const getStatusColor = (status: number | string): string => {
|
|
2
|
+
if (typeof status === 'string') {
|
|
3
|
+
// Handle WebSocket statuses
|
|
4
|
+
if (status === 'open') return 'text-green-400';
|
|
5
|
+
if (status === 'connecting') return 'text-yellow-400';
|
|
6
|
+
if (status === 'closed' || status === 'error') return 'text-red-400';
|
|
7
|
+
return 'text-gray-400';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Handle HTTP status codes
|
|
11
|
+
if (status >= 200 && status < 300) return 'text-green-400';
|
|
12
|
+
if (status >= 300 && status < 400) return 'text-yellow-400';
|
|
13
|
+
if (status >= 400) return 'text-red-400';
|
|
14
|
+
return 'text-gray-400';
|
|
15
|
+
};
|
|
@@ -1,348 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { RequestTab } from '../tabs/RequestTab';
|
|
7
|
-
import { ResponseTab } from '../tabs/ResponseTab';
|
|
8
|
-
import { CookiesTab } from '../tabs/CookiesTab';
|
|
9
|
-
import { TimingTab } from '../tabs/TimingTab';
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { Toolbar } from '../components/Toolbar';
|
|
3
|
+
import { RequestList } from '../components/RequestList';
|
|
4
|
+
import { SidePanel } from '../components/SidePanel';
|
|
5
|
+
import { NetworkActivityDevToolsClient } from '../../shared/client';
|
|
10
6
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from '../components/RequestList';
|
|
16
|
-
import { Circle, Square, Trash2, X } from 'lucide-react';
|
|
17
|
-
import {
|
|
18
|
-
NetworkActivityDevToolsClient,
|
|
19
|
-
NetworkActivityEventMap,
|
|
20
|
-
RequestId,
|
|
21
|
-
} from '../../shared/client';
|
|
22
|
-
import { NetworkEntry } from '../types';
|
|
7
|
+
useNetworkActivityClientManagement,
|
|
8
|
+
useHasSelectedRequest,
|
|
9
|
+
useNetworkActivityActions,
|
|
10
|
+
} from '../state/hooks';
|
|
23
11
|
|
|
24
12
|
export type InspectorViewProps = {
|
|
25
13
|
client: NetworkActivityDevToolsClient;
|
|
26
14
|
};
|
|
27
15
|
|
|
28
16
|
export const InspectorView = ({ client }: InspectorViewProps) => {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
);
|
|
33
|
-
const [networkEntries, setNetworkEntries] = useState<
|
|
34
|
-
Map<RequestId, NetworkEntry>
|
|
35
|
-
>(new Map());
|
|
36
|
-
|
|
37
|
-
const selectedRequest = useMemo(() => {
|
|
38
|
-
if (!selectedRequestId) return null;
|
|
39
|
-
const processedRequests = processNetworkEntries(networkEntries);
|
|
40
|
-
return (
|
|
41
|
-
processedRequests.find((request) => request.id === selectedRequestId) ||
|
|
42
|
-
null
|
|
43
|
-
);
|
|
44
|
-
}, [selectedRequestId, networkEntries]);
|
|
17
|
+
const actions = useNetworkActivityActions();
|
|
18
|
+
const clientManagement = useNetworkActivityClientManagement();
|
|
19
|
+
const hasSelectedRequest = useHasSelectedRequest();
|
|
45
20
|
|
|
46
21
|
useEffect(() => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const entry: NetworkEntry = {
|
|
51
|
-
requestId: data.requestId,
|
|
52
|
-
url: data.request.url,
|
|
53
|
-
method: data.request.method,
|
|
54
|
-
headers: data.request.headers,
|
|
55
|
-
postData: data.request.postData,
|
|
56
|
-
status: 'pending',
|
|
57
|
-
startTime: data.timestamp,
|
|
58
|
-
type: data.type,
|
|
59
|
-
initiator: data.initiator,
|
|
60
|
-
request: data.request,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
setNetworkEntries((prev) => new Map(prev).set(data.requestId, entry));
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const handleResponseReceived = (
|
|
67
|
-
data: NetworkActivityEventMap['response-received']
|
|
68
|
-
) => {
|
|
69
|
-
setNetworkEntries((prev) => {
|
|
70
|
-
const entry = prev.get(data.requestId);
|
|
71
|
-
if (!entry) return prev;
|
|
72
|
-
|
|
73
|
-
const updatedEntry: NetworkEntry = {
|
|
74
|
-
...entry,
|
|
75
|
-
status: 'loading',
|
|
76
|
-
response: data.response,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
return new Map(prev).set(data.requestId, updatedEntry);
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const handleRequestCompleted = (
|
|
84
|
-
data: NetworkActivityEventMap['request-completed']
|
|
85
|
-
) => {
|
|
86
|
-
setNetworkEntries((prev) => {
|
|
87
|
-
const entry = prev.get(data.requestId);
|
|
88
|
-
if (!entry) return prev;
|
|
89
|
-
|
|
90
|
-
const updatedEntry: NetworkEntry = {
|
|
91
|
-
...entry,
|
|
92
|
-
status: 'finished',
|
|
93
|
-
endTime: data.timestamp,
|
|
94
|
-
duration: data.duration,
|
|
95
|
-
ttfb: data.ttfb,
|
|
96
|
-
size: data.size,
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
return new Map(prev).set(data.requestId, updatedEntry);
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const handleRequestFailed = (
|
|
104
|
-
data: NetworkActivityEventMap['request-failed']
|
|
105
|
-
) => {
|
|
106
|
-
setNetworkEntries((prev) => {
|
|
107
|
-
const entry = prev.get(data.requestId);
|
|
108
|
-
if (!entry) return prev;
|
|
109
|
-
|
|
110
|
-
const updatedEntry: NetworkEntry = {
|
|
111
|
-
...entry,
|
|
112
|
-
status: 'failed',
|
|
113
|
-
error: data.error,
|
|
114
|
-
canceled: data.canceled,
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
return new Map(prev).set(data.requestId, updatedEntry);
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// Subscribe to network events
|
|
122
|
-
const unsubscribeRequestSent = client.onMessage(
|
|
123
|
-
'request-sent',
|
|
124
|
-
handleRequestSent
|
|
125
|
-
);
|
|
126
|
-
const unsubscribeResponseReceived = client.onMessage(
|
|
127
|
-
'response-received',
|
|
128
|
-
handleResponseReceived
|
|
129
|
-
);
|
|
130
|
-
const unsubscribeRequestCompleted = client.onMessage(
|
|
131
|
-
'request-completed',
|
|
132
|
-
handleRequestCompleted
|
|
133
|
-
);
|
|
134
|
-
const unsubscribeRequestFailed = client.onMessage(
|
|
135
|
-
'request-failed',
|
|
136
|
-
handleRequestFailed
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
const handleResponseBody = (
|
|
140
|
-
data: NetworkActivityEventMap['response-body']
|
|
141
|
-
) => {
|
|
142
|
-
setNetworkEntries((prev) => {
|
|
143
|
-
const entry = prev.get(data.requestId);
|
|
144
|
-
if (!entry) return prev;
|
|
145
|
-
|
|
146
|
-
const updatedEntry: NetworkEntry = {
|
|
147
|
-
...entry,
|
|
148
|
-
responseBody: {
|
|
149
|
-
...entry.responseBody,
|
|
150
|
-
body: data.body,
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
console.log(updatedEntry);
|
|
155
|
-
return new Map(prev).set(data.requestId, updatedEntry);
|
|
156
|
-
});
|
|
157
|
-
};
|
|
22
|
+
if (!client) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
158
25
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
handleResponseBody
|
|
162
|
-
);
|
|
26
|
+
clientManagement.setupClient(client);
|
|
27
|
+
actions.setRecording(true);
|
|
163
28
|
|
|
164
29
|
return () => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
unsubscribeRequestCompleted.remove();
|
|
168
|
-
unsubscribeRequestFailed.remove();
|
|
169
|
-
unsubscribeResponseBody.remove();
|
|
30
|
+
actions.setRecording(false);
|
|
31
|
+
clientManagement.cleanupClient();
|
|
170
32
|
};
|
|
171
|
-
}, [client]);
|
|
172
|
-
|
|
173
|
-
useEffect(() => {
|
|
174
|
-
if (isRecording) {
|
|
175
|
-
client.send('network-enable', {});
|
|
176
|
-
|
|
177
|
-
return () => {
|
|
178
|
-
client.send('network-disable', {});
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
}, [isRecording, client]);
|
|
182
|
-
|
|
183
|
-
const clearRequests = () => {
|
|
184
|
-
setNetworkEntries(new Map());
|
|
185
|
-
setSelectedRequestId(null);
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
const closeSidePanel = () => {
|
|
189
|
-
setSelectedRequestId(null);
|
|
190
|
-
};
|
|
33
|
+
}, [client, clientManagement, actions]);
|
|
191
34
|
|
|
192
35
|
return (
|
|
193
36
|
<div className="h-screen bg-gray-900 text-gray-100 flex flex-col">
|
|
194
|
-
|
|
195
|
-
<div className="flex items-center gap-2 p-2 border-b border-gray-700 bg-gray-800">
|
|
196
|
-
<Button
|
|
197
|
-
variant="ghost"
|
|
198
|
-
size="sm"
|
|
199
|
-
onClick={() => setIsRecording(!isRecording)}
|
|
200
|
-
className={`h-8 w-8 p-0 ${
|
|
201
|
-
isRecording
|
|
202
|
-
? 'text-red-400 hover:text-red-300'
|
|
203
|
-
: 'text-gray-400 hover:text-blue-400'
|
|
204
|
-
}`}
|
|
205
|
-
>
|
|
206
|
-
{isRecording ? (
|
|
207
|
-
<Circle className="h-4 w-4 fill-current" />
|
|
208
|
-
) : (
|
|
209
|
-
<Square className="h-4 w-4" />
|
|
210
|
-
)}
|
|
211
|
-
</Button>
|
|
212
|
-
<Button
|
|
213
|
-
variant="ghost"
|
|
214
|
-
size="sm"
|
|
215
|
-
onClick={clearRequests}
|
|
216
|
-
className="h-8 w-8 p-0 text-gray-400 hover:text-blue-400"
|
|
217
|
-
>
|
|
218
|
-
<Trash2 className="h-4 w-4" />
|
|
219
|
-
</Button>
|
|
220
|
-
</div>
|
|
37
|
+
<Toolbar />
|
|
221
38
|
|
|
222
39
|
<div className="flex flex-1 overflow-hidden">
|
|
223
40
|
{/* Request List */}
|
|
224
41
|
<div
|
|
225
42
|
className={`flex flex-col ${
|
|
226
|
-
|
|
43
|
+
hasSelectedRequest ? 'w-1/2' : 'w-full'
|
|
227
44
|
} border-r border-gray-700 overflow-hidden`}
|
|
228
45
|
>
|
|
229
|
-
<RequestList
|
|
230
|
-
networkEntries={networkEntries}
|
|
231
|
-
selectedRequestId={selectedRequestId}
|
|
232
|
-
onRequestSelect={setSelectedRequestId}
|
|
233
|
-
/>
|
|
46
|
+
<RequestList />
|
|
234
47
|
</div>
|
|
235
48
|
|
|
236
|
-
{
|
|
237
|
-
{selectedRequest && (
|
|
238
|
-
<div className="w-1/2 flex flex-col bg-gray-900">
|
|
239
|
-
{/* Side Panel Header */}
|
|
240
|
-
<div className="flex items-center justify-between p-3 border-b border-gray-700 bg-gray-800">
|
|
241
|
-
<div className="flex items-center gap-2">
|
|
242
|
-
<div
|
|
243
|
-
className={`w-3 h-3 rounded-full ${getTypeColor(
|
|
244
|
-
selectedRequest.type
|
|
245
|
-
)}`}
|
|
246
|
-
></div>
|
|
247
|
-
<span className="font-medium">{selectedRequest.name}</span>
|
|
248
|
-
<Badge
|
|
249
|
-
variant="outline"
|
|
250
|
-
className={`${getStatusColor(
|
|
251
|
-
selectedRequest.status
|
|
252
|
-
)} border-current`}
|
|
253
|
-
>
|
|
254
|
-
{selectedRequest.status}
|
|
255
|
-
</Badge>
|
|
256
|
-
</div>
|
|
257
|
-
<Button
|
|
258
|
-
variant="ghost"
|
|
259
|
-
size="sm"
|
|
260
|
-
onClick={closeSidePanel}
|
|
261
|
-
className="h-6 w-6 p-0 text-gray-400 hover:text-blue-400"
|
|
262
|
-
>
|
|
263
|
-
<X className="h-4 w-4" />
|
|
264
|
-
</Button>
|
|
265
|
-
</div>
|
|
266
|
-
|
|
267
|
-
{/* Side Panel Content */}
|
|
268
|
-
<div className="flex-1 overflow-hidden">
|
|
269
|
-
<Tabs defaultValue="headers" className="h-full flex flex-col">
|
|
270
|
-
<TabsList className="grid w-full grid-cols-5 bg-gray-800 rounded-none border-b border-gray-700">
|
|
271
|
-
<TabsTrigger
|
|
272
|
-
value="headers"
|
|
273
|
-
className="data-[state=active]:bg-gray-700"
|
|
274
|
-
>
|
|
275
|
-
Headers
|
|
276
|
-
</TabsTrigger>
|
|
277
|
-
<TabsTrigger
|
|
278
|
-
value="request"
|
|
279
|
-
className="data-[state=active]:bg-gray-700"
|
|
280
|
-
>
|
|
281
|
-
Request
|
|
282
|
-
</TabsTrigger>
|
|
283
|
-
<TabsTrigger
|
|
284
|
-
value="response"
|
|
285
|
-
className="data-[state=active]:bg-gray-700"
|
|
286
|
-
>
|
|
287
|
-
Response
|
|
288
|
-
</TabsTrigger>
|
|
289
|
-
<TabsTrigger
|
|
290
|
-
value="cookies"
|
|
291
|
-
className="data-[state=active]:bg-gray-700"
|
|
292
|
-
>
|
|
293
|
-
Cookies
|
|
294
|
-
</TabsTrigger>
|
|
295
|
-
<TabsTrigger
|
|
296
|
-
value="timing"
|
|
297
|
-
className="data-[state=active]:bg-gray-700"
|
|
298
|
-
>
|
|
299
|
-
Timing
|
|
300
|
-
</TabsTrigger>
|
|
301
|
-
</TabsList>
|
|
302
|
-
|
|
303
|
-
<TabsContent
|
|
304
|
-
value="headers"
|
|
305
|
-
className="flex-1 m-0 overflow-hidden"
|
|
306
|
-
>
|
|
307
|
-
<HeadersTab
|
|
308
|
-
selectedRequest={selectedRequest}
|
|
309
|
-
networkEntries={networkEntries}
|
|
310
|
-
getStatusColor={getStatusColor}
|
|
311
|
-
/>
|
|
312
|
-
</TabsContent>
|
|
313
|
-
|
|
314
|
-
<TabsContent value="request" className="flex-1 m-0">
|
|
315
|
-
<RequestTab selectedRequest={selectedRequest} />
|
|
316
|
-
</TabsContent>
|
|
317
|
-
|
|
318
|
-
<TabsContent value="response" className="flex-1 m-0">
|
|
319
|
-
<ResponseTab
|
|
320
|
-
selectedRequest={selectedRequest}
|
|
321
|
-
onRequestResponseBody={(requestId) => {
|
|
322
|
-
client.send('get-response-body', {
|
|
323
|
-
requestId,
|
|
324
|
-
});
|
|
325
|
-
}}
|
|
326
|
-
/>
|
|
327
|
-
</TabsContent>
|
|
328
|
-
|
|
329
|
-
<TabsContent value="cookies" className="flex-1 m-0">
|
|
330
|
-
<CookiesTab
|
|
331
|
-
selectedRequest={selectedRequest}
|
|
332
|
-
networkEntries={networkEntries}
|
|
333
|
-
/>
|
|
334
|
-
</TabsContent>
|
|
335
|
-
|
|
336
|
-
<TabsContent value="timing" className="flex-1 m-0">
|
|
337
|
-
<TimingTab
|
|
338
|
-
selectedRequest={selectedRequest}
|
|
339
|
-
networkEntries={networkEntries}
|
|
340
|
-
/>
|
|
341
|
-
</TabsContent>
|
|
342
|
-
</Tabs>
|
|
343
|
-
</div>
|
|
344
|
-
</div>
|
|
345
|
-
)}
|
|
49
|
+
{hasSelectedRequest && <SidePanel />}
|
|
346
50
|
</div>
|
|
347
51
|
</div>
|
|
348
52
|
);
|
package/tailwind.config.ts
CHANGED
package/vite.config.ts
CHANGED
|
@@ -12,6 +12,18 @@ export default defineConfig({
|
|
|
12
12
|
reportCompressedSize: false,
|
|
13
13
|
minify: false,
|
|
14
14
|
sourcemap: false,
|
|
15
|
+
rollupOptions: {
|
|
16
|
+
output: {
|
|
17
|
+
manualChunks: (id) => {
|
|
18
|
+
// Mitigate https://github.com/facebook/metro/issues/836
|
|
19
|
+
if (id.includes('event-source.ts')) {
|
|
20
|
+
return 'event-source';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return undefined;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
15
27
|
},
|
|
16
28
|
server: {
|
|
17
29
|
port: 3000,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/src/react-native/{network-requests-registry.ts → http/network-requests-registry.ts}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|