@rozenite/network-activity-plugin 1.0.0-alpha.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/App.html +2 -2
- package/dist/assets/{App-R2ZMH9wJ.css → App-BrSkOkws.css} +269 -2
- package/dist/assets/{App-lNMijPJ4.js → App-C6wCDVkW.js} +17485 -10814
- package/dist/event-source.cjs +22 -0
- package/dist/event-source.js +23 -0
- 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/{network-inspector.d.ts → http/network-inspector.d.ts} +1 -1
- package/dist/src/react-native/http/overrides-registry.d.ts +6 -0
- package/dist/src/react-native/{xhr-interceptor.d.ts → http/xhr-interceptor.d.ts} +7 -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/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/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 +53 -6
- package/dist/src/shared/sse-events.d.ts +38 -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 +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 +7 -0
- 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 +13 -28
- 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/SidePanel.d.ts +1 -0
- package/dist/src/ui/components/Tabs.d.ts +7 -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 +21 -0
- package/dist/src/ui/state/model.d.ts +103 -0
- package/dist/src/ui/state/store.d.ts +48 -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 +4 -1
- package/dist/src/ui/utils/assert.d.ts +1 -0
- package/dist/src/ui/utils/checkRequestBodyBinary.d.ts +2 -0
- package/dist/src/ui/utils/copyToClipboard.d.ts +1 -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/ui/utils/getId.d.ts +1 -0
- package/dist/src/ui/utils/getStatusColor.d.ts +1 -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 +724 -40
- package/dist/useNetworkActivityDevTools.js +723 -41
- package/package.json +22 -8
- package/react-native.ts +6 -1
- package/src/react-native/config.ts +43 -0
- package/src/react-native/http/network-inspector.ts +388 -0
- package/src/react-native/http/overrides-registry.ts +32 -0
- package/src/react-native/{xhr-interceptor.ts → http/xhr-interceptor.ts} +19 -2
- 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 +139 -0
- package/src/react-native/sse/sse-interceptor.ts +180 -0
- package/src/react-native/sse/types.ts +9 -0
- package/src/react-native/useNetworkActivityDevTools.ts +156 -4
- package/src/react-native/utils/getBlobName.ts +45 -0
- package/src/react-native/utils/getFormDataEntries.ts +32 -0
- 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 +79 -6
- package/src/shared/sse-events.ts +47 -0
- package/src/shared/websocket-events.ts +79 -0
- 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 +20 -0
- package/src/ui/components/JsonTreeCopyableItem.tsx +37 -0
- 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 +101 -131
- package/src/ui/components/ScrollArea.tsx +1 -0
- package/src/ui/components/Section.tsx +46 -0
- package/src/ui/components/SidePanel.tsx +333 -0
- package/src/ui/components/Tabs.tsx +1 -1
- package/src/ui/components/Toolbar.tsx +45 -0
- package/src/ui/globals.css +4 -0
- package/src/ui/hooks/useCopyToClipboard.ts +28 -0
- package/src/ui/state/derived.ts +112 -0
- package/src/ui/state/hooks.ts +52 -0
- package/src/ui/state/model.ts +140 -0
- package/src/ui/state/store.ts +669 -0
- package/src/ui/tabs/CookiesTab.tsx +61 -278
- package/src/ui/tabs/HeadersTab.tsx +85 -103
- package/src/ui/tabs/MessagesTab.tsx +276 -0
- package/src/ui/tabs/RequestTab.tsx +58 -51
- package/src/ui/tabs/ResponseTab.tsx +101 -74
- package/src/ui/tabs/SSEMessagesTab.tsx +224 -0
- package/src/ui/tabs/TimingTab.tsx +30 -43
- package/src/ui/types.ts +4 -1
- package/src/ui/utils/assert.ts +5 -0
- package/src/ui/utils/checkRequestBodyBinary.ts +7 -0
- package/src/ui/utils/copyToClipboard.ts +3 -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/utils/getId.ts +10 -0
- package/src/ui/utils/getStatusColor.ts +15 -0
- package/src/ui/views/InspectorView.tsx +35 -319
- 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/tailwind.config.ts +3 -0
- package/vite.config.ts +12 -0
- package/dist/src/ui/utils/getHttpHeaderValue.d.ts +0 -2
- package/src/react-native/network-inspector.ts +0 -247
- package/src/ui/utils/getHttpHeaderValue.ts +0 -14
- /package/dist/src/react-native/{network-requests-registry.d.ts → http/network-requests-registry.d.ts} +0 -0
- /package/src/react-native/{network-requests-registry.ts → http/network-requests-registry.ts} +0 -0
|
@@ -1,292 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import { ScrollArea } from '../components/ScrollArea';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
domain?: string;
|
|
10
|
-
path?: string;
|
|
11
|
-
expires?: string;
|
|
12
|
-
maxAge?: string;
|
|
13
|
-
secure?: boolean;
|
|
14
|
-
httpOnly?: boolean;
|
|
15
|
-
sameSite?: string;
|
|
16
|
-
};
|
|
3
|
+
import { Section } from '../components/Section';
|
|
4
|
+
import { CookieCard } from '../components/CookieCard';
|
|
5
|
+
import {
|
|
6
|
+
parseRequestCookiesFromHeaders,
|
|
7
|
+
parseResponseCookiesFromHeaders,
|
|
8
|
+
} from '../../utils/cookieParser';
|
|
9
|
+
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
17
10
|
|
|
18
11
|
export type CookiesTabProps = {
|
|
19
|
-
selectedRequest:
|
|
20
|
-
id: string;
|
|
21
|
-
};
|
|
22
|
-
networkEntries: Map<string, NetworkEntry>;
|
|
12
|
+
selectedRequest: HttpNetworkEntry | SSENetworkEntry;
|
|
23
13
|
};
|
|
24
14
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
break;
|
|
51
|
-
case 'expires':
|
|
52
|
-
cookieObj.expires = attrValue;
|
|
53
|
-
break;
|
|
54
|
-
case 'max-age':
|
|
55
|
-
cookieObj.maxAge = attrValue;
|
|
56
|
-
break;
|
|
57
|
-
case 'secure':
|
|
58
|
-
cookieObj.secure = true;
|
|
59
|
-
break;
|
|
60
|
-
case 'httponly':
|
|
61
|
-
cookieObj.httpOnly = true;
|
|
62
|
-
break;
|
|
63
|
-
case 'samesite':
|
|
64
|
-
cookieObj.sameSite = attrValue;
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return cookieObj;
|
|
70
|
-
})
|
|
71
|
-
.filter((cookieObj) => cookieObj.name); // Filter out empty cookies
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const extractCookiesFromHeaders = (
|
|
75
|
-
headers: HttpHeaders
|
|
76
|
-
): {
|
|
77
|
-
requestCookies: Cookie[];
|
|
78
|
-
responseCookies: Cookie[];
|
|
79
|
-
} => {
|
|
80
|
-
const requestCookies: Cookie[] = [];
|
|
81
|
-
const responseCookies: Cookie[] = [];
|
|
82
|
-
|
|
83
|
-
Object.entries(headers).forEach(([key, value]) => {
|
|
84
|
-
const lowerKey = key.toLowerCase();
|
|
85
|
-
|
|
86
|
-
if (lowerKey === 'cookie') {
|
|
87
|
-
// Cookie header contains all cookies in one string
|
|
88
|
-
requestCookies.push(...parseCookieString(value));
|
|
89
|
-
} else if (lowerKey === 'set-cookie') {
|
|
90
|
-
// Set-Cookie header contains one cookie with attributes
|
|
91
|
-
const cookies = parseCookieString(value);
|
|
92
|
-
responseCookies.push(...cookies);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
return { requestCookies, responseCookies };
|
|
97
|
-
};
|
|
15
|
+
export const CookiesTab = ({ selectedRequest }: CookiesTabProps) => {
|
|
16
|
+
const requestHeaders = selectedRequest.request?.headers;
|
|
17
|
+
const responseHeaders = selectedRequest.response?.headers;
|
|
18
|
+
|
|
19
|
+
const { requestCookies, responseCookies } = React.useMemo(() => {
|
|
20
|
+
return {
|
|
21
|
+
requestCookies: parseRequestCookiesFromHeaders(requestHeaders || {}),
|
|
22
|
+
responseCookies: parseResponseCookiesFromHeaders(responseHeaders || {}),
|
|
23
|
+
};
|
|
24
|
+
}, [requestHeaders, responseHeaders]);
|
|
25
|
+
|
|
26
|
+
const hasRequestCookies = requestCookies.length > 0;
|
|
27
|
+
const hasResponseCookies = responseCookies.length > 0;
|
|
28
|
+
|
|
29
|
+
if (!hasRequestCookies && !hasResponseCookies) {
|
|
30
|
+
return (
|
|
31
|
+
<ScrollArea className="h-full w-full">
|
|
32
|
+
<div className="p-4">
|
|
33
|
+
<div className="text-sm text-gray-400">
|
|
34
|
+
No cookies for this request
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</ScrollArea>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
98
40
|
|
|
99
|
-
export const CookiesTab = ({
|
|
100
|
-
selectedRequest,
|
|
101
|
-
networkEntries,
|
|
102
|
-
}: CookiesTabProps) => {
|
|
103
41
|
return (
|
|
104
42
|
<ScrollArea className="h-full w-full">
|
|
105
43
|
<div className="p-4">
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const requestHeaders = entry.request?.headers || {};
|
|
118
|
-
const responseHeaders = entry.response?.headers || {};
|
|
119
|
-
|
|
120
|
-
const { requestCookies } = extractCookiesFromHeaders(requestHeaders);
|
|
121
|
-
const { responseCookies } = extractCookiesFromHeaders(responseHeaders);
|
|
122
|
-
|
|
123
|
-
const hasRequestCookies = requestCookies.length > 0;
|
|
124
|
-
const hasResponseCookies = responseCookies.length > 0;
|
|
125
|
-
|
|
126
|
-
if (!hasRequestCookies && !hasResponseCookies) {
|
|
127
|
-
return (
|
|
128
|
-
<div className="text-sm text-gray-400">
|
|
129
|
-
No cookies for this request
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
<div className="space-y-6">
|
|
136
|
-
{/* Request Cookies */}
|
|
137
|
-
{hasRequestCookies && (
|
|
138
|
-
<div>
|
|
139
|
-
<h4 className="text-sm font-medium text-gray-300 mb-3">
|
|
140
|
-
Request Cookies ({requestCookies.length})
|
|
141
|
-
</h4>
|
|
142
|
-
<div className="space-y-2">
|
|
143
|
-
{requestCookies.map((cookie, index) => (
|
|
144
|
-
<div
|
|
145
|
-
key={`request-${index}`}
|
|
146
|
-
className="bg-gray-800 border border-gray-700 rounded p-3"
|
|
147
|
-
>
|
|
148
|
-
<div className="flex items-center justify-between mb-2">
|
|
149
|
-
<span className="text-sm font-medium text-blue-400">
|
|
150
|
-
{cookie.name}
|
|
151
|
-
</span>
|
|
152
|
-
<div className="flex items-center gap-2">
|
|
153
|
-
{cookie.secure && (
|
|
154
|
-
<Badge
|
|
155
|
-
variant="outline"
|
|
156
|
-
className="text-xs text-yellow-400 border-yellow-400"
|
|
157
|
-
>
|
|
158
|
-
Secure
|
|
159
|
-
</Badge>
|
|
160
|
-
)}
|
|
161
|
-
{cookie.httpOnly && (
|
|
162
|
-
<Badge
|
|
163
|
-
variant="outline"
|
|
164
|
-
className="text-xs text-purple-400 border-purple-400"
|
|
165
|
-
>
|
|
166
|
-
HttpOnly
|
|
167
|
-
</Badge>
|
|
168
|
-
)}
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
<div className="text-sm text-gray-300 mb-2">
|
|
172
|
-
{cookie.value}
|
|
173
|
-
</div>
|
|
174
|
-
<div className="grid grid-cols-2 gap-4 text-xs text-gray-400">
|
|
175
|
-
{cookie.domain && (
|
|
176
|
-
<div>
|
|
177
|
-
<span className="font-medium">Domain:</span>{' '}
|
|
178
|
-
{cookie.domain}
|
|
179
|
-
</div>
|
|
180
|
-
)}
|
|
181
|
-
{cookie.path && (
|
|
182
|
-
<div>
|
|
183
|
-
<span className="font-medium">Path:</span>{' '}
|
|
184
|
-
{cookie.path}
|
|
185
|
-
</div>
|
|
186
|
-
)}
|
|
187
|
-
{cookie.expires && (
|
|
188
|
-
<div>
|
|
189
|
-
<span className="font-medium">Expires:</span>{' '}
|
|
190
|
-
{cookie.expires}
|
|
191
|
-
</div>
|
|
192
|
-
)}
|
|
193
|
-
{cookie.maxAge && (
|
|
194
|
-
<div>
|
|
195
|
-
<span className="font-medium">Max-Age:</span>{' '}
|
|
196
|
-
{cookie.maxAge}
|
|
197
|
-
</div>
|
|
198
|
-
)}
|
|
199
|
-
{cookie.sameSite && (
|
|
200
|
-
<div>
|
|
201
|
-
<span className="font-medium">SameSite:</span>{' '}
|
|
202
|
-
{cookie.sameSite}
|
|
203
|
-
</div>
|
|
204
|
-
)}
|
|
205
|
-
</div>
|
|
206
|
-
</div>
|
|
207
|
-
))}
|
|
208
|
-
</div>
|
|
44
|
+
<div className="space-y-6">
|
|
45
|
+
{hasRequestCookies && (
|
|
46
|
+
<Section title={`Request Cookies (${requestCookies.length})`}>
|
|
47
|
+
<div className="space-y-2">
|
|
48
|
+
{requestCookies.map((cookie, index) => (
|
|
49
|
+
<CookieCard
|
|
50
|
+
key={`request-${index}`}
|
|
51
|
+
cookie={cookie}
|
|
52
|
+
keyClassName="text-blue-400"
|
|
53
|
+
/>
|
|
54
|
+
))}
|
|
209
55
|
</div>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
>
|
|
224
|
-
<div className="flex items-center justify-between mb-2">
|
|
225
|
-
<span className="text-sm font-medium text-green-400">
|
|
226
|
-
{cookie.name}
|
|
227
|
-
</span>
|
|
228
|
-
<div className="flex items-center gap-2">
|
|
229
|
-
{cookie.secure && (
|
|
230
|
-
<Badge
|
|
231
|
-
variant="outline"
|
|
232
|
-
className="text-xs text-yellow-400 border-yellow-400"
|
|
233
|
-
>
|
|
234
|
-
Secure
|
|
235
|
-
</Badge>
|
|
236
|
-
)}
|
|
237
|
-
{cookie.httpOnly && (
|
|
238
|
-
<Badge
|
|
239
|
-
variant="outline"
|
|
240
|
-
className="text-xs text-purple-400 border-purple-400"
|
|
241
|
-
>
|
|
242
|
-
HttpOnly
|
|
243
|
-
</Badge>
|
|
244
|
-
)}
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
<div className="text-sm text-gray-300 mb-2">
|
|
248
|
-
{cookie.value}
|
|
249
|
-
</div>
|
|
250
|
-
<div className="grid grid-cols-2 gap-4 text-xs text-gray-400">
|
|
251
|
-
{cookie.domain && (
|
|
252
|
-
<div>
|
|
253
|
-
<span className="font-medium">Domain:</span>{' '}
|
|
254
|
-
{cookie.domain}
|
|
255
|
-
</div>
|
|
256
|
-
)}
|
|
257
|
-
{cookie.path && (
|
|
258
|
-
<div>
|
|
259
|
-
<span className="font-medium">Path:</span>{' '}
|
|
260
|
-
{cookie.path}
|
|
261
|
-
</div>
|
|
262
|
-
)}
|
|
263
|
-
{cookie.expires && (
|
|
264
|
-
<div>
|
|
265
|
-
<span className="font-medium">Expires:</span>{' '}
|
|
266
|
-
{cookie.expires}
|
|
267
|
-
</div>
|
|
268
|
-
)}
|
|
269
|
-
{cookie.maxAge && (
|
|
270
|
-
<div>
|
|
271
|
-
<span className="font-medium">Max-Age:</span>{' '}
|
|
272
|
-
{cookie.maxAge}
|
|
273
|
-
</div>
|
|
274
|
-
)}
|
|
275
|
-
{cookie.sameSite && (
|
|
276
|
-
<div>
|
|
277
|
-
<span className="font-medium">SameSite:</span>{' '}
|
|
278
|
-
{cookie.sameSite}
|
|
279
|
-
</div>
|
|
280
|
-
)}
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
))}
|
|
284
|
-
</div>
|
|
56
|
+
</Section>
|
|
57
|
+
)}
|
|
58
|
+
|
|
59
|
+
{hasResponseCookies && (
|
|
60
|
+
<Section title={`Response Cookies (${responseCookies.length})`}>
|
|
61
|
+
<div className="space-y-2">
|
|
62
|
+
{responseCookies.map((cookie, index) => (
|
|
63
|
+
<CookieCard
|
|
64
|
+
key={`response-${index}`}
|
|
65
|
+
cookie={cookie}
|
|
66
|
+
keyClassName="text-green-400"
|
|
67
|
+
/>
|
|
68
|
+
))}
|
|
285
69
|
</div>
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
})()}
|
|
70
|
+
</Section>
|
|
71
|
+
)}
|
|
72
|
+
</div>
|
|
290
73
|
</div>
|
|
291
74
|
</ScrollArea>
|
|
292
75
|
);
|
|
@@ -1,116 +1,98 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
1
2
|
import { ScrollArea } from '../components/ScrollArea';
|
|
2
|
-
import {
|
|
3
|
+
import { Section } from '../components/Section';
|
|
4
|
+
import { KeyValueGrid, KeyValueItem } from '../components/KeyValueGrid';
|
|
5
|
+
import { HttpNetworkEntry, SSENetworkEntry } from '../state/model';
|
|
6
|
+
import { getStatusColor } from '../utils/getStatusColor';
|
|
7
|
+
import { CopyRequestDropdown } from '../components/CopyRequestDropdown';
|
|
8
|
+
import { HttpHeaders } from '../../shared/client';
|
|
3
9
|
|
|
4
10
|
export type HeadersTabProps = {
|
|
5
|
-
selectedRequest:
|
|
6
|
-
id: string;
|
|
7
|
-
domain: string;
|
|
8
|
-
path: string;
|
|
9
|
-
method: string;
|
|
10
|
-
status: number;
|
|
11
|
-
requestBody?: {
|
|
12
|
-
type: string;
|
|
13
|
-
data: string;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
networkEntries: Map<string, NetworkEntry>;
|
|
17
|
-
getStatusColor: (status: number) => string;
|
|
11
|
+
selectedRequest: HttpNetworkEntry | SSENetworkEntry;
|
|
18
12
|
};
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
function getHeadersItems(headers?: HttpHeaders): KeyValueItem[] {
|
|
15
|
+
if (!headers) return [];
|
|
16
|
+
|
|
17
|
+
return Object.entries(headers).reduce<KeyValueItem[]>((acc, [key, value]) => {
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
acc.push(
|
|
20
|
+
...value.map((item) => ({ key: key.toLowerCase(), value: item }))
|
|
21
|
+
);
|
|
22
|
+
} else {
|
|
23
|
+
acc.push({ key: key.toLowerCase(), value: value });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return acc;
|
|
27
|
+
}, []);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const HeadersTab = ({ selectedRequest }: HeadersTabProps) => {
|
|
31
|
+
const requestBody = selectedRequest.request.body;
|
|
32
|
+
|
|
33
|
+
const generalItems: KeyValueItem[] = useMemo(
|
|
34
|
+
() => [
|
|
35
|
+
{
|
|
36
|
+
key: 'Request URL',
|
|
37
|
+
value: selectedRequest.request.url,
|
|
38
|
+
valueClassName: 'text-blue-400',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: 'Request Method',
|
|
42
|
+
value: selectedRequest.request.method,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: 'Status Code',
|
|
46
|
+
value: selectedRequest.response?.status ?? 'Pending',
|
|
47
|
+
valueClassName: getStatusColor(selectedRequest.response?.status ?? 0),
|
|
48
|
+
},
|
|
49
|
+
...(requestBody
|
|
50
|
+
? [
|
|
51
|
+
{
|
|
52
|
+
key: 'Content-Type',
|
|
53
|
+
value: requestBody.type,
|
|
54
|
+
valueClassName: 'text-blue-400',
|
|
55
|
+
},
|
|
56
|
+
]
|
|
57
|
+
: []),
|
|
58
|
+
],
|
|
59
|
+
[selectedRequest]
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const responseHeadersItems = useMemo(
|
|
63
|
+
() => getHeadersItems(selectedRequest.response?.headers),
|
|
64
|
+
[selectedRequest]
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const requestHeadersItems = useMemo(
|
|
68
|
+
() => getHeadersItems(selectedRequest.request.headers),
|
|
69
|
+
[selectedRequest]
|
|
70
|
+
);
|
|
71
|
+
|
|
25
72
|
return (
|
|
26
73
|
<ScrollArea className="h-full w-full">
|
|
27
74
|
<div className="p-4 space-y-4">
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<span className="text-blue-400">
|
|
34
|
-
{selectedRequest.domain}
|
|
35
|
-
{selectedRequest.path}
|
|
36
|
-
</span>
|
|
37
|
-
</div>
|
|
38
|
-
<div className="flex">
|
|
39
|
-
<span className="w-32 text-gray-400">Request Method:</span>
|
|
40
|
-
<span>{selectedRequest.method}</span>
|
|
41
|
-
</div>
|
|
42
|
-
<div className="flex">
|
|
43
|
-
<span className="w-32 text-gray-400">Status Code:</span>
|
|
44
|
-
<span className={getStatusColor(selectedRequest.status)}>
|
|
45
|
-
{selectedRequest.status}
|
|
46
|
-
</span>
|
|
47
|
-
</div>
|
|
48
|
-
{selectedRequest.requestBody && (
|
|
49
|
-
<div className="flex">
|
|
50
|
-
<span className="w-32 text-gray-400">Content-Type:</span>
|
|
51
|
-
<span className="text-blue-400">
|
|
52
|
-
{selectedRequest.requestBody.type}
|
|
53
|
-
</span>
|
|
54
|
-
</div>
|
|
55
|
-
)}
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
75
|
+
<CopyRequestDropdown selectedRequest={selectedRequest} />
|
|
76
|
+
|
|
77
|
+
<Section title="General">
|
|
78
|
+
<KeyValueGrid items={generalItems} />
|
|
79
|
+
</Section>
|
|
58
80
|
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const responseHeaders = entry?.response?.headers;
|
|
67
|
-
if (responseHeaders && Object.keys(responseHeaders).length > 0) {
|
|
68
|
-
return Object.entries(responseHeaders).map(([key, value]) => (
|
|
69
|
-
<div key={key} className="flex">
|
|
70
|
-
<span className="w-32 text-gray-400">
|
|
71
|
-
{key.toLowerCase()}:
|
|
72
|
-
</span>
|
|
73
|
-
<span className="flex-1 break-all">{value}</span>
|
|
74
|
-
</div>
|
|
75
|
-
));
|
|
76
|
-
} else {
|
|
77
|
-
return (
|
|
78
|
-
<div className="text-gray-500 italic">
|
|
79
|
-
No response headers available
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
})()}
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
81
|
+
<Section title="Response Headers">
|
|
82
|
+
<KeyValueGrid
|
|
83
|
+
items={responseHeadersItems}
|
|
84
|
+
emptyMessage="No response headers available"
|
|
85
|
+
className="font-mono"
|
|
86
|
+
/>
|
|
87
|
+
</Section>
|
|
86
88
|
|
|
87
|
-
<
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const requestHeaders = entry?.request?.headers;
|
|
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>
|
|
89
|
+
<Section title="Request Headers">
|
|
90
|
+
<KeyValueGrid
|
|
91
|
+
items={requestHeadersItems}
|
|
92
|
+
emptyMessage="No request headers available"
|
|
93
|
+
className="font-mono"
|
|
94
|
+
/>
|
|
95
|
+
</Section>
|
|
114
96
|
</div>
|
|
115
97
|
</ScrollArea>
|
|
116
98
|
);
|