@rozenite/network-activity-plugin 1.0.0-alpha.5 → 1.0.0-alpha.6

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.
Files changed (75) hide show
  1. package/dist/{panel.html → App.html} +3 -3
  2. package/dist/assets/App-CIflVb88.js +24164 -0
  3. package/dist/assets/App-Czu6Vt2P.css +1233 -0
  4. package/dist/react-native.cjs +1 -1
  5. package/dist/react-native.d.ts +1 -90
  6. package/dist/rozenite.config.d.ts +7 -0
  7. package/dist/rozenite.json +1 -1
  8. package/dist/src/react-native/network-inspector.d.ts +8 -0
  9. package/dist/src/react-native/network-requests-registry.d.ts +6 -0
  10. package/dist/src/react-native/useNetworkActivityDevTools.d.ts +2 -0
  11. package/dist/src/react-native/xhr-interceptor.d.ts +38 -0
  12. package/dist/src/shared/client.d.ts +64 -0
  13. package/dist/src/ui/App.d.ts +1 -0
  14. package/dist/src/ui/components/Badge.d.ts +9 -0
  15. package/dist/src/ui/components/Button.d.ts +11 -0
  16. package/dist/src/ui/components/Input.d.ts +3 -0
  17. package/dist/src/ui/components/JsonTree.d.ts +5 -0
  18. package/dist/src/ui/components/RequestList.d.ts +45 -0
  19. package/dist/src/ui/components/ScrollArea.d.ts +4 -0
  20. package/dist/src/ui/components/Separator.d.ts +3 -0
  21. package/dist/src/ui/tabs/CookiesTab.d.ts +8 -0
  22. package/dist/src/ui/tabs/HeadersTab.d.ts +17 -0
  23. package/dist/src/ui/tabs/RequestTab.d.ts +10 -0
  24. package/dist/src/ui/tabs/ResponseTab.d.ts +12 -0
  25. package/dist/src/ui/tabs/TimingTab.d.ts +7 -0
  26. package/dist/src/ui/types.d.ts +23 -0
  27. package/dist/src/ui/utils.d.ts +2 -0
  28. package/dist/src/ui/views/InspectorView.d.ts +5 -0
  29. package/dist/src/ui/views/LoadingView.d.ts +1 -0
  30. package/dist/useNetworkActivityDevTools.cjs +360 -0
  31. package/dist/useNetworkActivityDevTools.js +108 -236
  32. package/package.json +23 -16
  33. package/postcss.config.js +6 -0
  34. package/rozenite.config.ts +1 -1
  35. package/src/react-native/network-inspector.ts +113 -260
  36. package/src/react-native/network-requests-registry.ts +7 -77
  37. package/src/react-native/useNetworkActivityDevTools.ts +1 -1
  38. package/src/react-native/xhr-interceptor.ts +2 -2
  39. package/src/react-native/xml-request.d.ts +11 -1
  40. package/src/shared/client.ts +80 -0
  41. package/src/ui/App.tsx +19 -0
  42. package/src/ui/components/Badge.tsx +36 -0
  43. package/src/ui/components/Button.tsx +56 -0
  44. package/src/ui/components/Input.tsx +22 -0
  45. package/src/ui/components/JsonTree.tsx +37 -0
  46. package/src/ui/components/RequestList.tsx +376 -0
  47. package/src/ui/components/ScrollArea.tsx +48 -0
  48. package/src/ui/components/Separator.tsx +31 -0
  49. package/src/ui/components/Tabs.tsx +55 -0
  50. package/src/ui/globals.css +90 -0
  51. package/src/ui/tabs/CookiesTab.tsx +290 -0
  52. package/src/ui/tabs/HeadersTab.tsx +117 -0
  53. package/src/ui/tabs/RequestTab.tsx +72 -0
  54. package/src/ui/tabs/ResponseTab.tsx +140 -0
  55. package/src/ui/tabs/TimingTab.tsx +71 -0
  56. package/src/ui/types.ts +30 -0
  57. package/src/ui/utils.ts +5 -97
  58. package/src/ui/views/InspectorView.tsx +349 -0
  59. package/src/ui/views/LoadingView.tsx +19 -0
  60. package/tailwind.config.ts +93 -0
  61. package/dist/assets/panel-BNxB_KsS.js +0 -16663
  62. package/dist/assets/panel-DXGMsavf.css +0 -555
  63. package/src/types/client.ts +0 -111
  64. package/src/types/network.ts +0 -32
  65. package/src/ui/components.module.css +0 -158
  66. package/src/ui/components.tsx +0 -241
  67. package/src/ui/network-details.module.css +0 -197
  68. package/src/ui/network-details.tsx +0 -345
  69. package/src/ui/network-list.module.css +0 -128
  70. package/src/ui/network-list.tsx +0 -240
  71. package/src/ui/network-toolbar.module.css +0 -9
  72. package/src/ui/network-toolbar.tsx +0 -34
  73. package/src/ui/panel.module.css +0 -67
  74. package/src/ui/panel.tsx +0 -318
  75. package/src/ui/tanstack-query.tsx +0 -204
@@ -1,9 +0,0 @@
1
- .recordingButton {
2
- margin-right: 8px;
3
- }
4
-
5
- .requestCount {
6
- margin-left: auto;
7
- font-size: 12px;
8
- color: #666;
9
- }
@@ -1,34 +0,0 @@
1
- import React from 'react';
2
- import { Button, Toolbar } from './components';
3
- import styles from './network-toolbar.module.css';
4
-
5
- interface NetworkToolbarProps {
6
- isRecording: boolean;
7
- onToggleRecording: () => void;
8
- onClear: () => void;
9
- requestCount: number;
10
- }
11
-
12
- export const NetworkToolbar: React.FC<NetworkToolbarProps> = ({
13
- isRecording,
14
- onToggleRecording,
15
- onClear,
16
- requestCount,
17
- }) => {
18
- return (
19
- <Toolbar>
20
- <Button
21
- onClick={onToggleRecording}
22
- variant={isRecording ? 'danger' : 'success'}
23
- size="small"
24
- className={styles.recordingButton}
25
- >
26
- {isRecording ? 'Stop' : 'Start'} Recording
27
- </Button>
28
- <Button onClick={onClear} variant="secondary" size="small">
29
- Clear
30
- </Button>
31
- <div className={styles.requestCount}>{requestCount} requests</div>
32
- </Toolbar>
33
- );
34
- };
@@ -1,67 +0,0 @@
1
- .container {
2
- height: 100vh;
3
- display: flex;
4
- flex-direction: column;
5
- font-family: system-ui, -apple-system, sans-serif;
6
- }
7
-
8
- .mainContent {
9
- flex: 1;
10
- display: flex;
11
- overflow: hidden;
12
- min-height: 0;
13
- }
14
-
15
- .networkListContainer {
16
- width: 60%;
17
- border-right: 1px solid #e0e0e0;
18
- display: flex;
19
- flex-direction: column;
20
- min-width: 0;
21
- }
22
-
23
- .listContent {
24
- flex: 1;
25
- }
26
-
27
- .detailsContainer {
28
- width: 40%;
29
- display: flex;
30
- flex-direction: column;
31
- min-width: 0;
32
- }
33
-
34
- .headerStatus {
35
- width: 60px;
36
- text-align: center;
37
- flex-shrink: 0;
38
- }
39
-
40
- .headerMethod {
41
- width: 80px;
42
- text-align: center;
43
- flex-shrink: 0;
44
- }
45
-
46
- .headerName {
47
- flex: 1;
48
- min-width: 0;
49
- }
50
-
51
- .headerType {
52
- width: 100px;
53
- text-align: center;
54
- flex-shrink: 0;
55
- }
56
-
57
- .headerTime {
58
- width: 80px;
59
- text-align: right;
60
- flex-shrink: 0;
61
- }
62
-
63
- .headerSize {
64
- width: 80px;
65
- text-align: right;
66
- flex-shrink: 0;
67
- }
package/src/ui/panel.tsx DELETED
@@ -1,318 +0,0 @@
1
- import React, { useState, useEffect, useMemo } from 'react';
2
- import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
3
- import {
4
- NetworkActivityEventMap,
5
- NetworkRequestId,
6
- NetworkResourceType,
7
- } from '../types/client';
8
- import { NetworkEntry } from '../types/network';
9
- import styles from './panel.module.css';
10
- import { NetworkToolbar } from './network-toolbar';
11
- import { PanelHeader } from './components';
12
- import { NetworkList } from './network-list';
13
- import { NetworkDetails } from './network-details';
14
-
15
- // Enhanced network entry with CDP data
16
- type EnhancedNetworkEntry = NetworkEntry & {
17
- // CDP specific fields
18
- loaderId?: string;
19
- documentURL?: string;
20
- type?: NetworkResourceType;
21
- initiator?: {
22
- type: string;
23
- url?: string;
24
- lineNumber?: number;
25
- columnNumber?: number;
26
- };
27
- // Request details
28
- request?: {
29
- url: string;
30
- method: string;
31
- headers: Record<string, string>;
32
- postData?: string;
33
- hasPostData?: boolean;
34
- };
35
- // Response details
36
- response?: {
37
- url: string;
38
- status: number;
39
- statusText: string;
40
- headers: Record<string, string>;
41
- mimeType: string;
42
- encodedDataLength: number;
43
- responseTime: number;
44
- };
45
- // Response body
46
- responseBody?: {
47
- body: string;
48
- base64Encoded: boolean;
49
- };
50
- // Timing and data
51
- dataLength?: number;
52
- // Error details
53
- blockedReason?: string;
54
- corsErrorStatus?: any;
55
- };
56
-
57
- export default function NetworkActivityPanel() {
58
- const client = useRozeniteDevToolsClient<NetworkActivityEventMap>({
59
- pluginId: '@rozenite/network-activity-plugin',
60
- });
61
-
62
- const [networkEntries, setNetworkEntries] = useState<
63
- Map<string, EnhancedNetworkEntry>
64
- >(new Map());
65
- const [selectedRequestId, setSelectedRequestId] = useState<string | null>(
66
- null
67
- );
68
- const [isRecording, setIsRecording] = useState(true);
69
- const [containerHeight, setContainerHeight] = useState(0);
70
- const containerRef = React.useRef<HTMLDivElement>(null);
71
-
72
- // Convert Map to sorted array for rendering
73
- const sortedEntries = useMemo(() => {
74
- return Array.from(networkEntries.values()).sort(
75
- (a, b) => b.startTime - a.startTime
76
- );
77
- }, [networkEntries]);
78
-
79
- const selectedEntry = selectedRequestId
80
- ? networkEntries.get(selectedRequestId) || null
81
- : null;
82
-
83
- useEffect(() => {
84
- if (!client) {
85
- return;
86
- }
87
-
88
- if (isRecording) {
89
- client.send('network-enable', {});
90
- } else {
91
- client.send('network-disable', {});
92
- }
93
- }, [client, isRecording]);
94
-
95
- useEffect(() => {
96
- if (!client) return;
97
-
98
- const subscriptions: Array<{ remove: () => void }> = [];
99
-
100
- // Subscribe to CDP Network events
101
- subscriptions.push(
102
- client.onMessage('Network.requestWillBeSent', (payload) => {
103
- setNetworkEntries((prev) => {
104
- const newMap = new Map(prev);
105
- const existing = newMap.get(payload.requestId);
106
-
107
- newMap.set(payload.requestId, {
108
- requestId: payload.requestId,
109
- loaderId: payload.loaderId,
110
- documentURL: payload.documentURL,
111
- url: payload.request.url,
112
- method: payload.request.method,
113
- headers: payload.request.headers,
114
- postData: payload.request.postData,
115
- hasPostData: payload.request.hasPostData,
116
- status: 'pending',
117
- startTime: payload.timestamp,
118
- type: payload.type,
119
- initiator: payload.initiator,
120
- request: payload.request,
121
- // Preserve existing response data if this is a redirect
122
- ...(existing && {
123
- response: existing.response,
124
- status: existing.status,
125
- endTime: existing.endTime,
126
- duration: existing.duration,
127
- encodedDataLength: existing.encodedDataLength,
128
- dataLength: existing.dataLength,
129
- errorText: existing.errorText,
130
- canceled: existing.canceled,
131
- }),
132
- });
133
- return newMap;
134
- });
135
- })
136
- );
137
-
138
- subscriptions.push(
139
- client.onMessage('Network.responseReceived', (payload) => {
140
- setNetworkEntries((prev) => {
141
- const newMap = new Map(prev);
142
- const entry = newMap.get(payload.requestId);
143
- if (entry) {
144
- newMap.set(payload.requestId, {
145
- ...entry,
146
- response: payload.response,
147
- status: 'loading',
148
- });
149
- }
150
- return newMap;
151
- });
152
- })
153
- );
154
-
155
- subscriptions.push(
156
- client.onMessage('Network.dataReceived', (payload) => {
157
- setNetworkEntries((prev) => {
158
- const newMap = new Map(prev);
159
- const entry = newMap.get(payload.requestId);
160
- if (entry) {
161
- newMap.set(payload.requestId, {
162
- ...entry,
163
- dataLength: payload.dataLength,
164
- encodedDataLength: payload.encodedDataLength,
165
- });
166
- }
167
- return newMap;
168
- });
169
- })
170
- );
171
-
172
- subscriptions.push(
173
- client.onMessage('Network.loadingFinished', (payload) => {
174
- setNetworkEntries((prev) => {
175
- const newMap = new Map(prev);
176
- const entry = newMap.get(payload.requestId);
177
- if (entry) {
178
- const endTime = payload.timestamp;
179
- const duration = endTime - entry.startTime;
180
-
181
- newMap.set(payload.requestId, {
182
- ...entry,
183
- status: 'finished',
184
- endTime,
185
- duration,
186
- encodedDataLength: payload.encodedDataLength,
187
- });
188
- }
189
- return newMap;
190
- });
191
- })
192
- );
193
-
194
- subscriptions.push(
195
- client.onMessage('Network.loadingFailed', (payload) => {
196
- setNetworkEntries((prev) => {
197
- const newMap = new Map(prev);
198
- const entry = newMap.get(payload.requestId);
199
- if (entry) {
200
- const endTime = payload.timestamp;
201
- const duration = endTime - entry.startTime;
202
-
203
- newMap.set(payload.requestId, {
204
- ...entry,
205
- status: 'failed',
206
- endTime,
207
- duration,
208
- errorText: payload.errorText,
209
- canceled: payload.canceled,
210
- });
211
- }
212
- return newMap;
213
- });
214
- })
215
- );
216
-
217
- subscriptions.push(
218
- client.onMessage('Network.responseBodyReceived', (payload) => {
219
- setNetworkEntries((prev) => {
220
- const newMap = new Map(prev);
221
- const entry = newMap.get(payload.requestId);
222
- if (entry) {
223
- newMap.set(payload.requestId, {
224
- ...entry,
225
- responseBody: {
226
- body: payload.body,
227
- base64Encoded: payload.base64Encoded,
228
- },
229
- });
230
- }
231
- return newMap;
232
- });
233
- })
234
- );
235
-
236
- return () => {
237
- subscriptions.forEach((sub) => sub.remove());
238
- };
239
- }, [client, isRecording]);
240
-
241
- const clearNetworkLog = () => {
242
- setNetworkEntries(new Map());
243
- setSelectedRequestId(null);
244
- };
245
-
246
- const toggleRecording = () => {
247
- setIsRecording(!isRecording);
248
- };
249
-
250
- const handleSelectRequest = (requestId: string) => {
251
- setSelectedRequestId(requestId);
252
- };
253
-
254
- const requestResponseBody = (requestId: string) => {
255
- if (client) {
256
- client.send('Network.getResponseBody', { requestId });
257
- }
258
- };
259
-
260
- // Update container height on mount and resize
261
- useEffect(() => {
262
- const updateHeight = () => {
263
- if (containerRef.current) {
264
- const rect = containerRef.current.getBoundingClientRect();
265
- setContainerHeight(rect.height - 120); // Subtract toolbar and header height
266
- }
267
- };
268
-
269
- updateHeight();
270
- window.addEventListener('resize', updateHeight);
271
- return () => window.removeEventListener('resize', updateHeight);
272
- }, []);
273
-
274
- return (
275
- <div ref={containerRef} className={styles.container}>
276
- {/* Toolbar */}
277
- <NetworkToolbar
278
- isRecording={isRecording}
279
- onToggleRecording={toggleRecording}
280
- onClear={clearNetworkLog}
281
- requestCount={sortedEntries.length}
282
- />
283
-
284
- {/* Main Content */}
285
- <div className={styles.mainContent}>
286
- {/* Network List */}
287
- <div className={styles.networkListContainer}>
288
- {/* List Header */}
289
- <PanelHeader>
290
- <div className={styles.headerStatus}>Status</div>
291
- <div className={styles.headerMethod}>Method</div>
292
- <div className={styles.headerName}>Name</div>
293
- <div className={styles.headerType}>Type</div>
294
- <div className={styles.headerTime}>Time</div>
295
- <div className={styles.headerSize}>Size</div>
296
- </PanelHeader>
297
-
298
- <div className={styles.listContent}>
299
- <NetworkList
300
- entries={sortedEntries}
301
- selectedRequestId={selectedRequestId}
302
- onSelect={handleSelectRequest}
303
- height={containerHeight}
304
- />
305
- </div>
306
- </div>
307
-
308
- {/* Details Panel */}
309
- <div className={styles.detailsContainer}>
310
- <NetworkDetails
311
- entry={selectedEntry}
312
- onRequestResponseBody={requestResponseBody}
313
- />
314
- </div>
315
- </div>
316
- </div>
317
- );
318
- }
@@ -1,204 +0,0 @@
1
- import {
2
- QueryCacheNotifyEvent,
3
- MutationCacheNotifyEvent,
4
- QueryClient,
5
- QueryClientProvider,
6
- Query,
7
- Mutation,
8
- } from '@tanstack/react-query';
9
- import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools';
10
- import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
11
- import { useEffect, useRef } from 'react';
12
-
13
- const queryClient = new QueryClient({
14
- defaultOptions: {
15
- queries: {
16
- queryFn: async () => {
17
- // Prevent refetch from throwing an error
18
- return Promise.resolve(null);
19
- },
20
- },
21
- },
22
- });
23
-
24
- type DevToolsEventMap = {
25
- DEVTOOLS_TO_DEVICE: unknown;
26
- DEVICE_TO_DEVTOOLS: QueryCacheNotifyEvent | MutationCacheNotifyEvent;
27
- DEVICE_TO_DEVTOOLS_ACK: { requestId: string; success: boolean };
28
- DEVICE_TO_DEVTOOLS_INITIAL_DATA: { queries: Query[]; mutations: Mutation[] };
29
- DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST: unknown;
30
- };
31
-
32
- const Wrapped = () => {
33
- const client = useRozeniteDevToolsClient<DevToolsEventMap>({
34
- pluginId: '@rozenite/tanstack-query-plugin',
35
- });
36
-
37
- // Track pending acknowledgments to prevent feedback loops
38
- const pendingAcknowledgment = useRef<Set<string>>(new Set());
39
-
40
- useEffect(() => {
41
- if (!client) return;
42
- client.send('DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST', null);
43
- }, [client]);
44
-
45
- useEffect(() => {
46
- if (!client) return;
47
-
48
- const handleEvent = (event: Event) => {
49
- const detail = (event as CustomEvent).detail;
50
-
51
- // Generate a unique request ID for this DevTools action
52
- const requestId = `devtools-${Date.now()}-${Math.random()
53
- .toString(36)
54
- .substr(2, 9)}`;
55
-
56
- // Mark that we're waiting for acknowledgment
57
- pendingAcknowledgment.current.add(requestId);
58
-
59
- // Add the request ID to the event detail
60
- const eventWithRequestId = {
61
- ...detail,
62
- requestId,
63
- };
64
-
65
- client.send('DEVTOOLS_TO_DEVICE', eventWithRequestId);
66
- };
67
-
68
- window.addEventListener('@tanstack/query-devtools-event', handleEvent);
69
- return () =>
70
- window.removeEventListener('@tanstack/query-devtools-event', handleEvent);
71
- }, [client]);
72
-
73
- useEffect(() => {
74
- if (!client) return;
75
-
76
- const ackSubscription = client.onMessage(
77
- 'DEVICE_TO_DEVTOOLS_ACK',
78
- (ack) => {
79
- // Remove the request from pending acknowledgments
80
- pendingAcknowledgment.current.delete(ack.requestId);
81
- }
82
- );
83
-
84
- const subscription = client.onMessage('DEVICE_TO_DEVTOOLS', (event) => {
85
- // Don't reflect events if we're waiting for acknowledgments
86
- if (pendingAcknowledgment.current.size > 0) {
87
- return;
88
- }
89
-
90
- if ('query' in event) {
91
- const { query, type } = event as QueryCacheNotifyEvent;
92
- const queryCache = queryClient.getQueryCache();
93
-
94
- if (type === 'updated') {
95
- const existingQuery = queryCache.get(query.queryHash);
96
- if (existingQuery) {
97
- existingQuery.setState(query.state);
98
- } else {
99
- queryCache.build(
100
- queryClient,
101
- {
102
- queryKey: query.queryKey,
103
- queryHash: query.queryHash,
104
- },
105
- query.state
106
- );
107
- }
108
- } else if (type === 'added') {
109
- const existingQuery = queryCache.get(query.queryHash);
110
- if (!existingQuery) {
111
- // Only add if it doesn't already exist
112
- queryCache.build(
113
- queryClient,
114
- {
115
- queryKey: query.queryKey,
116
- queryHash: query.queryHash,
117
- },
118
- query.state
119
- );
120
- }
121
- } else if (type === 'removed') {
122
- const existingQuery = queryCache.get(query.queryHash);
123
- if (existingQuery) {
124
- queryCache.remove(existingQuery);
125
- }
126
- }
127
- } else if ('mutation' in event) {
128
- const { mutation, type } = event as MutationCacheNotifyEvent;
129
- const mutationCache = queryClient.getMutationCache();
130
-
131
- if (type === 'added') {
132
- const existingMutation = mutationCache.find({
133
- mutationKey: mutation.options.mutationKey,
134
- });
135
- if (existingMutation) {
136
- mutationCache.remove(existingMutation);
137
- }
138
-
139
- mutationCache.build(queryClient, mutation.options, mutation.state);
140
- } else if (type === 'removed') {
141
- const existingMutation = mutationCache.find({
142
- mutationKey: mutation.options.mutationKey,
143
- });
144
- if (existingMutation) {
145
- mutationCache.remove(existingMutation);
146
- }
147
- } else if (type === 'updated') {
148
- const existingMutation = mutationCache.find({
149
- mutationKey: mutation.options.mutationKey,
150
- });
151
-
152
- if (existingMutation) {
153
- mutationCache.remove(existingMutation);
154
- mutationCache.build(queryClient, mutation.options, mutation.state);
155
- }
156
- }
157
- }
158
- });
159
-
160
- const initialDataSubscription = client.onMessage(
161
- 'DEVICE_TO_DEVTOOLS_INITIAL_DATA',
162
- (event) => {
163
- // Clear existing data first
164
- queryClient.clear();
165
- queryClient.getMutationCache().clear();
166
-
167
- // Restore queries
168
- const queryCache = queryClient.getQueryCache();
169
- event.queries.forEach((query) => {
170
- queryCache.build(
171
- queryClient,
172
- {
173
- queryKey: query.queryKey,
174
- queryHash: query.queryHash,
175
- },
176
- query.state
177
- );
178
- });
179
-
180
- // Restore mutations
181
- const mutationCache = queryClient.getMutationCache();
182
- event.mutations.forEach((mutation) => {
183
- mutationCache.build(queryClient, mutation.options, mutation.state);
184
- });
185
- }
186
- );
187
-
188
- return () => {
189
- subscription.remove();
190
- ackSubscription.remove();
191
- initialDataSubscription.remove();
192
- };
193
- }, [client, queryClient]);
194
-
195
- return <ReactQueryDevtoolsPanel />;
196
- };
197
-
198
- export default function TanStackQueryPanel() {
199
- return (
200
- <QueryClientProvider client={queryClient}>
201
- <Wrapped />
202
- </QueryClientProvider>
203
- );
204
- }