@rozenite/network-activity-plugin 1.0.0-alpha.1 → 1.0.0-alpha.10

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 (134) hide show
  1. package/README.md +3 -5
  2. package/dist/{panel.html → App.html} +3 -3
  3. package/dist/assets/App-CA1Fbh0I.js +25364 -0
  4. package/dist/assets/App-DoHQsY5s.css +1276 -0
  5. package/dist/event-source.cjs +22 -0
  6. package/dist/event-source.js +23 -0
  7. package/dist/react-native.cjs +8 -1
  8. package/dist/react-native.d.ts +1 -5
  9. package/dist/react-native.js +6 -171
  10. package/dist/rozenite.config.d.ts +7 -0
  11. package/dist/rozenite.json +1 -1
  12. package/dist/src/react-native/http/network-inspector.d.ts +8 -0
  13. package/dist/src/react-native/http/network-requests-registry.d.ts +6 -0
  14. package/dist/src/react-native/http/xhr-interceptor.d.ts +38 -0
  15. package/dist/src/react-native/sse/event-source.d.ts +2 -0
  16. package/dist/src/react-native/sse/sse-inspector.d.ts +9 -0
  17. package/dist/src/react-native/sse/sse-interceptor.d.ts +36 -0
  18. package/dist/src/react-native/sse/types.d.ts +6 -0
  19. package/dist/src/react-native/useNetworkActivityDevTools.d.ts +2 -0
  20. package/dist/src/react-native/utils.d.ts +6 -0
  21. package/dist/src/react-native/websocket/websocket-inspector.d.ts +9 -0
  22. package/dist/src/react-native/websocket/websocket-interceptor.d.ts +74 -0
  23. package/dist/src/shared/client.d.ts +68 -0
  24. package/dist/src/shared/sse-events.d.ts +35 -0
  25. package/dist/src/shared/websocket-events.d.ts +60 -0
  26. package/dist/src/ui/App.d.ts +1 -0
  27. package/dist/src/ui/components/Badge.d.ts +9 -0
  28. package/dist/src/ui/components/Button.d.ts +11 -0
  29. package/dist/src/ui/components/Input.d.ts +3 -0
  30. package/dist/src/ui/components/JsonTree.d.ts +5 -0
  31. package/dist/src/ui/components/JsonTreeCopyableItem.d.ts +7 -0
  32. package/dist/src/ui/components/RequestList.d.ts +25 -0
  33. package/dist/src/ui/components/ScrollArea.d.ts +4 -0
  34. package/dist/src/ui/components/Separator.d.ts +3 -0
  35. package/dist/src/ui/components/SidePanel.d.ts +1 -0
  36. package/dist/src/ui/components/Toolbar.d.ts +1 -0
  37. package/dist/src/ui/hooks/useCopyToClipboard.d.ts +4 -0
  38. package/dist/src/ui/state/derived.d.ts +5 -0
  39. package/dist/src/ui/state/hooks.d.ts +17 -0
  40. package/dist/src/ui/state/model.d.ts +98 -0
  41. package/dist/src/ui/state/store.d.ts +24 -0
  42. package/dist/src/ui/tabs/CookiesTab.d.ts +5 -0
  43. package/dist/src/ui/tabs/HeadersTab.d.ts +5 -0
  44. package/dist/src/ui/tabs/MessagesTab.d.ts +5 -0
  45. package/dist/src/ui/tabs/RequestTab.d.ts +5 -0
  46. package/dist/src/ui/tabs/ResponseTab.d.ts +6 -0
  47. package/dist/src/ui/tabs/SSEMessagesTab.d.ts +5 -0
  48. package/dist/src/ui/tabs/TimingTab.d.ts +5 -0
  49. package/dist/src/ui/types.d.ts +26 -0
  50. package/dist/src/ui/utils/assert.d.ts +1 -0
  51. package/dist/src/ui/utils/cn.d.ts +2 -0
  52. package/dist/src/ui/utils/copyToClipboard.d.ts +1 -0
  53. package/dist/src/ui/utils/getHttpHeaderValue.d.ts +2 -0
  54. package/dist/src/ui/utils/getId.d.ts +1 -0
  55. package/dist/src/ui/utils/getStatusColor.d.ts +1 -0
  56. package/dist/src/ui/views/InspectorView.d.ts +5 -0
  57. package/dist/src/ui/views/LoadingView.d.ts +1 -0
  58. package/dist/useNetworkActivityDevTools.cjs +759 -0
  59. package/dist/useNetworkActivityDevTools.js +757 -0
  60. package/package.json +31 -10
  61. package/postcss.config.js +6 -0
  62. package/project.json +12 -0
  63. package/react-native.ts +2 -1
  64. package/rozenite.config.ts +2 -2
  65. package/src/css-modules.d.ts +1 -1
  66. package/src/react-native/http/network-inspector.ts +226 -0
  67. package/src/react-native/http/network-requests-registry.ts +52 -0
  68. package/src/react-native/http/xhr-interceptor.ts +211 -0
  69. package/src/react-native/http/xml-request.d.ts +34 -0
  70. package/src/react-native/sse/event-source.ts +25 -0
  71. package/src/react-native/sse/sse-inspector.ts +117 -0
  72. package/src/react-native/sse/sse-interceptor.ts +162 -0
  73. package/src/react-native/sse/types.ts +9 -0
  74. package/src/react-native/useNetworkActivityDevTools.ts +73 -210
  75. package/src/react-native/utils.ts +43 -0
  76. package/src/react-native/websocket/websocket-inspector.ts +180 -0
  77. package/src/react-native/websocket/websocket-interceptor.d.ts +4 -0
  78. package/src/react-native/websocket/websocket-interceptor.ts +166 -0
  79. package/src/shared/client.ts +86 -0
  80. package/src/shared/sse-events.ts +44 -0
  81. package/src/shared/websocket-events.ts +79 -0
  82. package/src/ui/App.tsx +19 -0
  83. package/src/ui/components/Badge.tsx +36 -0
  84. package/src/ui/components/Button.tsx +56 -0
  85. package/src/ui/components/Input.tsx +22 -0
  86. package/src/ui/components/JsonTree.tsx +50 -0
  87. package/src/ui/components/JsonTreeCopyableItem.tsx +33 -0
  88. package/src/ui/components/RequestList.tsx +295 -0
  89. package/src/ui/components/ScrollArea.tsx +48 -0
  90. package/src/ui/components/Separator.tsx +31 -0
  91. package/src/ui/components/SidePanel.tsx +323 -0
  92. package/src/ui/components/Tabs.tsx +55 -0
  93. package/src/ui/components/Toolbar.tsx +45 -0
  94. package/src/ui/globals.css +90 -0
  95. package/src/ui/hooks/useCopyToClipboard.ts +28 -0
  96. package/src/ui/state/derived.ts +112 -0
  97. package/src/ui/state/hooks.ts +44 -0
  98. package/src/ui/state/model.ts +129 -0
  99. package/src/ui/state/store.ts +559 -0
  100. package/src/ui/tabs/CookiesTab.tsx +279 -0
  101. package/src/ui/tabs/HeadersTab.tsx +110 -0
  102. package/src/ui/tabs/MessagesTab.tsx +276 -0
  103. package/src/ui/tabs/RequestTab.tsx +69 -0
  104. package/src/ui/tabs/ResponseTab.tsx +138 -0
  105. package/src/ui/tabs/SSEMessagesTab.tsx +213 -0
  106. package/src/ui/tabs/TimingTab.tsx +60 -0
  107. package/src/ui/types.ts +34 -0
  108. package/src/ui/utils/assert.ts +5 -0
  109. package/src/ui/utils/cn.ts +6 -0
  110. package/src/ui/utils/copyToClipboard.ts +3 -0
  111. package/src/ui/utils/getHttpHeaderValue.ts +14 -0
  112. package/src/ui/utils/getId.ts +10 -0
  113. package/src/ui/utils/getStatusColor.ts +15 -0
  114. package/src/ui/views/InspectorView.tsx +53 -0
  115. package/src/ui/views/LoadingView.tsx +19 -0
  116. package/tailwind.config.ts +96 -0
  117. package/tsconfig.json +13 -6
  118. package/tsconfig.tsbuildinfo +1 -0
  119. package/vite.config.ts +13 -1
  120. package/dist/assets/panel-C5YgUUj5.js +0 -54
  121. package/dist/assets/panel-NCVczPb1.css +0 -1
  122. package/src/types/network.ts +0 -153
  123. package/src/ui/components.module.css +0 -158
  124. package/src/ui/components.tsx +0 -219
  125. package/src/ui/network-details.module.css +0 -57
  126. package/src/ui/network-details.tsx +0 -134
  127. package/src/ui/network-list.module.css +0 -122
  128. package/src/ui/network-list.tsx +0 -145
  129. package/src/ui/network-toolbar.module.css +0 -9
  130. package/src/ui/network-toolbar.tsx +0 -40
  131. package/src/ui/panel.module.css +0 -61
  132. package/src/ui/panel.tsx +0 -201
  133. package/src/ui/tanstack-query.tsx +0 -197
  134. package/src/ui/utils.ts +0 -89
@@ -0,0 +1,180 @@
1
+ import { createNanoEvents } from 'nanoevents';
2
+ import { getWebSocketInterceptor } from './websocket-interceptor';
3
+ import {
4
+ WebSocketEvent,
5
+ WebSocketEventMap,
6
+ } from '../../shared/websocket-events';
7
+
8
+ type NanoEventsMap = {
9
+ [K in keyof WebSocketEventMap]: (data: WebSocketEventMap[K]) => void;
10
+ };
11
+
12
+ export type WebSocketInspector = {
13
+ enable: () => void;
14
+ disable: () => void;
15
+ isEnabled: () => boolean;
16
+ dispose: () => void;
17
+ on: <TEventType extends keyof WebSocketEventMap>(
18
+ event: TEventType,
19
+ callback: (data: WebSocketEventMap[TEventType]) => void
20
+ ) => () => void;
21
+ };
22
+
23
+ export const getWebSocketInspector = (): WebSocketInspector => {
24
+ const eventEmitter = createNanoEvents<NanoEventsMap>();
25
+ const socketUrlMap = new Map<number, string>();
26
+ const webSocketInterceptor = getWebSocketInterceptor();
27
+
28
+ return {
29
+ enable: () => {
30
+ webSocketInterceptor.setConnectCallback(
31
+ (
32
+ url: string,
33
+ protocols: string[] | null,
34
+ options: string[],
35
+ socketId: number
36
+ ) => {
37
+ socketUrlMap.set(socketId, url);
38
+ const event: WebSocketEvent = {
39
+ type: 'websocket-connect',
40
+ url,
41
+ socketId,
42
+ timestamp: Date.now(),
43
+ protocols,
44
+ options,
45
+ };
46
+ eventEmitter.emit('websocket-connect', event);
47
+ }
48
+ );
49
+
50
+ webSocketInterceptor.setCloseCallback(
51
+ (code: number | null, reason: string | null, socketId: number) => {
52
+ const url = socketUrlMap.get(socketId);
53
+
54
+ if (!url) {
55
+ return;
56
+ }
57
+
58
+ const event: WebSocketEvent = {
59
+ type: 'websocket-close',
60
+ url,
61
+ socketId,
62
+ timestamp: Date.now(),
63
+ code: code || 0,
64
+ reason: reason || undefined,
65
+ };
66
+ eventEmitter.emit('websocket-close', event);
67
+ socketUrlMap.delete(socketId);
68
+ }
69
+ );
70
+
71
+ webSocketInterceptor.setOnMessageCallback(
72
+ (data: string, socketId: number) => {
73
+ const url = socketUrlMap.get(socketId);
74
+
75
+ if (!url) {
76
+ return;
77
+ }
78
+
79
+ const event: WebSocketEvent = {
80
+ type: 'websocket-message-received',
81
+ url,
82
+ socketId,
83
+ timestamp: Date.now(),
84
+ data,
85
+ messageType: typeof data === 'string' ? 'text' : 'binary',
86
+ };
87
+ eventEmitter.emit('websocket-message-received', event);
88
+ }
89
+ );
90
+
91
+ webSocketInterceptor.setOnErrorCallback(
92
+ (error: string, socketId: number) => {
93
+ const url = socketUrlMap.get(socketId);
94
+
95
+ if (!url) {
96
+ return;
97
+ }
98
+
99
+ const event: WebSocketEvent = {
100
+ type: 'websocket-error',
101
+ url,
102
+ socketId,
103
+ timestamp: Date.now(),
104
+ error,
105
+ };
106
+ eventEmitter.emit('websocket-error', event);
107
+ }
108
+ );
109
+
110
+ webSocketInterceptor.setSendCallback((data: string, socketId: number) => {
111
+ const url = socketUrlMap.get(socketId);
112
+
113
+ if (!url) {
114
+ return;
115
+ }
116
+
117
+ const event: WebSocketEvent = {
118
+ type: 'websocket-message-sent',
119
+ url,
120
+ socketId,
121
+ timestamp: Date.now(),
122
+ data,
123
+ messageType: typeof data === 'string' ? 'text' : 'binary',
124
+ };
125
+ eventEmitter.emit('websocket-message-sent', event);
126
+ });
127
+
128
+ webSocketInterceptor.setOnOpenCallback((socketId: number) => {
129
+ const url = socketUrlMap.get(socketId);
130
+
131
+ if (!url) {
132
+ return;
133
+ }
134
+
135
+ const event: WebSocketEvent = {
136
+ type: 'websocket-open',
137
+ url,
138
+ socketId,
139
+ timestamp: Date.now(),
140
+ };
141
+ eventEmitter.emit('websocket-open', event);
142
+ });
143
+
144
+ webSocketInterceptor.setOnCloseCallback(
145
+ (error: { code: number; reason?: string }, socketId: number) => {
146
+ const url = socketUrlMap.get(socketId);
147
+
148
+ if (!url) {
149
+ return;
150
+ }
151
+
152
+ const event: WebSocketEvent = {
153
+ type: 'websocket-close',
154
+ url,
155
+ socketId,
156
+ timestamp: Date.now(),
157
+ code: error.code,
158
+ reason: error.reason,
159
+ };
160
+ eventEmitter.emit('websocket-close', event);
161
+ socketUrlMap.delete(socketId);
162
+ }
163
+ );
164
+
165
+ webSocketInterceptor.enableInterception();
166
+ },
167
+ disable: () => {
168
+ webSocketInterceptor.disableInterception();
169
+ },
170
+ isEnabled: () => webSocketInterceptor.isInterceptorEnabled(),
171
+ dispose: () => {
172
+ eventEmitter.events = {};
173
+ socketUrlMap.clear();
174
+ },
175
+ on: <TEventType extends keyof WebSocketEventMap>(
176
+ event: TEventType,
177
+ callback: (data: WebSocketEventMap[TEventType]) => void
178
+ ) => eventEmitter.on(event, callback as NanoEventsMap[TEventType]),
179
+ };
180
+ };
@@ -0,0 +1,4 @@
1
+ declare module 'react-native/Libraries/WebSocket/WebSocketInterceptor' {
2
+ const WebSocketInterceptor: unknown;
3
+ export default WebSocketInterceptor;
4
+ }
@@ -0,0 +1,166 @@
1
+ import { Platform } from 'react-native';
2
+ import WebSocketInterceptor from 'react-native/Libraries/WebSocket/WebSocketInterceptor';
3
+
4
+ export interface WebSocketInterceptor {
5
+ /**
6
+ * Invoked when RCTWebSocketModule.close(...) is called.
7
+ */
8
+ setCloseCallback(
9
+ callback: (
10
+ code: number | null,
11
+ reason: string | null,
12
+ socketId: number
13
+ ) => void
14
+ ): void;
15
+
16
+ /**
17
+ * Invoked when RCTWebSocketModule.send(...) or sendBinary(...) is called.
18
+ */
19
+ setSendCallback(callback: (data: string, socketId: number) => void): void;
20
+
21
+ /**
22
+ * Invoked when RCTWebSocketModule.connect(...) is called.
23
+ */
24
+ setConnectCallback(
25
+ callback: (
26
+ url: string,
27
+ protocols: string[] | null,
28
+ options: string[],
29
+ socketId: number
30
+ ) => void
31
+ ): void;
32
+
33
+ /**
34
+ * Invoked when event "websocketOpen" happens.
35
+ */
36
+ setOnOpenCallback(callback: (socketId: number) => void): void;
37
+
38
+ /**
39
+ * Invoked when event "websocketMessage" happens.
40
+ */
41
+ setOnMessageCallback(
42
+ callback: (data: string, socketId: number) => void
43
+ ): void;
44
+
45
+ /**
46
+ * Invoked when event "websocketFailed" happens.
47
+ */
48
+ setOnErrorCallback(callback: (error: string, socketId: number) => void): void;
49
+
50
+ /**
51
+ * Invoked when event "websocketClosed" happens.
52
+ */
53
+ setOnCloseCallback(
54
+ callback: (
55
+ error: { code: number; reason?: string },
56
+ socketId: number
57
+ ) => void
58
+ ): void;
59
+
60
+ isInterceptorEnabled(): boolean;
61
+ enableInterception(): void;
62
+ disableInterception(): void;
63
+ }
64
+
65
+ export interface WebSocketInterceptorPreRN079 {
66
+ /**
67
+ * Invoked when RCTWebSocketModule.close(...) is called.
68
+ */
69
+ setCloseCallback(
70
+ callback: (
71
+ code: number | null,
72
+ reason: string | null,
73
+ socketId: number
74
+ ) => void
75
+ ): void;
76
+
77
+ /**
78
+ * Invoked when RCTWebSocketModule.send(...) or sendBinary(...) is called.
79
+ */
80
+ setSendCallback(callback: (data: string, socketId: number) => void): void;
81
+
82
+ /**
83
+ * Invoked when RCTWebSocketModule.connect(...) is called.
84
+ */
85
+ setConnectCallback(
86
+ callback: (
87
+ url: string,
88
+ protocols: string[] | null,
89
+ options: string[],
90
+ socketId: number
91
+ ) => void
92
+ ): void;
93
+
94
+ /**
95
+ * Invoked when event "websocketOpen" happens.
96
+ */
97
+ setOnOpenCallback(callback: (socketId: number) => void): void;
98
+
99
+ /**
100
+ * Invoked when event "websocketMessage" happens.
101
+ */
102
+ setOnMessageCallback(
103
+ callback: (socketId: number, data: string) => void
104
+ ): void;
105
+
106
+ /**
107
+ * Invoked when event "websocketFailed" happens.
108
+ */
109
+ setOnErrorCallback(callback: (socketId: number, error: string) => void): void;
110
+
111
+ /**
112
+ * Invoked when event "websocketClosed" happens.
113
+ */
114
+ setOnCloseCallback(
115
+ callback: (
116
+ socketId: number,
117
+ error: { code: number; reason?: string }
118
+ ) => void
119
+ ): void;
120
+
121
+ isInterceptorEnabled(): boolean;
122
+ enableInterception(): void;
123
+ disableInterception(): void;
124
+ }
125
+
126
+ export const getWebSocketInterceptor = (): WebSocketInterceptor => {
127
+ /**
128
+ * Note: RN 0.79 changed the order of the arguments.
129
+ * @see https://github.com/facebook/react-native/commit/d2adb976abebcb0f38750903d98fbb5a3f50924b
130
+ */
131
+
132
+ if (Platform.constants.reactNativeVersion.minor >= 79) {
133
+ return WebSocketInterceptor as WebSocketInterceptor;
134
+ } else {
135
+ const WebSocketInterceptorPreRN079 =
136
+ WebSocketInterceptor as WebSocketInterceptorPreRN079;
137
+
138
+ return {
139
+ ...WebSocketInterceptorPreRN079,
140
+ setOnMessageCallback: (
141
+ callback: (data: string, socketId: number) => void
142
+ ) => {
143
+ WebSocketInterceptorPreRN079.setOnMessageCallback((socketId, data) => {
144
+ callback(data, socketId);
145
+ });
146
+ },
147
+ setOnCloseCallback: (
148
+ callback: (
149
+ error: { code: number; reason?: string },
150
+ socketId: number
151
+ ) => void
152
+ ) => {
153
+ WebSocketInterceptorPreRN079.setOnCloseCallback((error, socketId) => {
154
+ callback(socketId, error);
155
+ });
156
+ },
157
+ setOnErrorCallback: (
158
+ callback: (error: string, socketId: number) => void
159
+ ) => {
160
+ WebSocketInterceptorPreRN079.setOnErrorCallback((error, socketId) => {
161
+ callback(socketId, error);
162
+ });
163
+ },
164
+ } as WebSocketInterceptor;
165
+ }
166
+ };
@@ -0,0 +1,86 @@
1
+ import { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+ import { WebSocketEventMap } from './websocket-events';
3
+ import { SSEEventMap } from './sse-events';
4
+
5
+ export type HttpHeaders = Record<string, string>;
6
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
7
+
8
+ export type RequestId = string;
9
+ export type Timestamp = number;
10
+
11
+ export type Request = {
12
+ url: string;
13
+ method: HttpMethod;
14
+ headers: HttpHeaders;
15
+ postData?: string;
16
+ };
17
+
18
+ export type Response = {
19
+ url: string;
20
+ status: number;
21
+ statusText: string;
22
+ headers: HttpHeaders;
23
+ contentType: string;
24
+ size: number;
25
+ responseTime: Timestamp;
26
+ };
27
+
28
+ export type Initiator = {
29
+ type: string;
30
+ url?: string;
31
+ lineNumber?: number;
32
+ columnNumber?: number;
33
+ };
34
+
35
+ export type ResourceType = 'XHR' | 'Fetch' | 'Other';
36
+
37
+ export type NetworkActivityEventMap = {
38
+ // Control events
39
+ 'network-enable': unknown;
40
+ 'network-disable': unknown;
41
+
42
+ // Network request events
43
+ 'request-sent': {
44
+ requestId: RequestId;
45
+ request: Request;
46
+ timestamp: Timestamp;
47
+ initiator: Initiator;
48
+ type: ResourceType;
49
+ };
50
+
51
+ 'response-received': {
52
+ requestId: RequestId;
53
+ timestamp: Timestamp;
54
+ type: ResourceType;
55
+ response: Response;
56
+ };
57
+
58
+ 'request-completed': {
59
+ requestId: RequestId;
60
+ timestamp: Timestamp;
61
+ duration: number;
62
+ size: number;
63
+ ttfb: number;
64
+ };
65
+
66
+ 'request-failed': {
67
+ requestId: RequestId;
68
+ timestamp: Timestamp;
69
+ type: ResourceType;
70
+ error: string;
71
+ canceled: boolean;
72
+ };
73
+
74
+ 'get-response-body': {
75
+ requestId: RequestId;
76
+ };
77
+
78
+ 'response-body': {
79
+ requestId: RequestId;
80
+ body: string | null;
81
+ };
82
+ } & WebSocketEventMap &
83
+ SSEEventMap;
84
+
85
+ export type NetworkActivityDevToolsClient =
86
+ RozeniteDevToolsClient<NetworkActivityEventMap>;
@@ -0,0 +1,44 @@
1
+ import type { Response } from './client';
2
+
3
+ export type SSEConnectionStatus = 'connecting' | 'open' | 'closed';
4
+ export type SSERequestId = string;
5
+
6
+ export type SSEOpenEvent = {
7
+ type: 'sse-open';
8
+ requestId: SSERequestId;
9
+ timestamp: number;
10
+ response: Response;
11
+ };
12
+
13
+ export type SSEMessageEvent = {
14
+ type: 'sse-message';
15
+ requestId: SSERequestId;
16
+ timestamp: number;
17
+ data: string;
18
+ };
19
+
20
+ export type SSEErrorEvent = {
21
+ type: 'sse-error';
22
+ requestId: SSERequestId;
23
+ timestamp: number;
24
+ error: {
25
+ type: 'error' | 'timeout' | 'exception';
26
+ message: string;
27
+ };
28
+ };
29
+
30
+ export type SSECloseEvent = {
31
+ type: 'sse-close';
32
+ requestId: SSERequestId;
33
+ timestamp: number;
34
+ };
35
+
36
+ export type SSEEvent =
37
+ | SSEOpenEvent
38
+ | SSEMessageEvent
39
+ | SSEErrorEvent
40
+ | SSECloseEvent;
41
+
42
+ export type SSEEventMap = {
43
+ [K in SSEEvent['type']]: Extract<SSEEvent, { type: K }>;
44
+ };
@@ -0,0 +1,79 @@
1
+ export type WebSocketMessageType = 'text' | 'binary';
2
+
3
+ export type WebSocketConnectionStatus =
4
+ | 'connecting'
5
+ | 'open'
6
+ | 'closing'
7
+ | 'closed';
8
+
9
+ export type WebSocketConnectEvent = {
10
+ type: 'websocket-connect';
11
+ url: string;
12
+ socketId: number;
13
+ timestamp: number;
14
+ protocols: string[] | null;
15
+ options: string[];
16
+ };
17
+
18
+ export type WebSocketOpenEvent = {
19
+ type: 'websocket-open';
20
+ url: string;
21
+ socketId: number;
22
+ timestamp: number;
23
+ };
24
+
25
+ export type WebSocketCloseEvent = {
26
+ type: 'websocket-close';
27
+ url: string;
28
+ socketId: number;
29
+ timestamp: number;
30
+ code: number;
31
+ reason?: string;
32
+ };
33
+
34
+ export type WebSocketMessageSentEvent = {
35
+ type: 'websocket-message-sent';
36
+ url: string;
37
+ socketId: number;
38
+ timestamp: number;
39
+ data: string;
40
+ messageType: WebSocketMessageType;
41
+ };
42
+
43
+ export type WebSocketMessageReceivedEvent = {
44
+ type: 'websocket-message-received';
45
+ url: string;
46
+ socketId: number;
47
+ timestamp: number;
48
+ data: string;
49
+ messageType: WebSocketMessageType;
50
+ };
51
+
52
+ export type WebSocketErrorEvent = {
53
+ type: 'websocket-error';
54
+ url: string;
55
+ socketId: number;
56
+ timestamp: number;
57
+ error: string;
58
+ };
59
+
60
+ export type WebSocketConnectionStatusChangedEvent = {
61
+ type: 'websocket-connection-status-changed';
62
+ url: string;
63
+ socketId: number;
64
+ timestamp: number;
65
+ status: WebSocketConnectionStatus;
66
+ };
67
+
68
+ export type WebSocketEvent =
69
+ | WebSocketConnectEvent
70
+ | WebSocketOpenEvent
71
+ | WebSocketCloseEvent
72
+ | WebSocketMessageSentEvent
73
+ | WebSocketMessageReceivedEvent
74
+ | WebSocketErrorEvent
75
+ | WebSocketConnectionStatusChangedEvent;
76
+
77
+ export type WebSocketEventMap = {
78
+ [K in WebSocketEvent['type']]: Extract<WebSocketEvent, { type: K }>;
79
+ };
package/src/ui/App.tsx ADDED
@@ -0,0 +1,19 @@
1
+ import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+ import { NetworkActivityEventMap } from '../shared/client';
3
+
4
+ import { InspectorView } from './views/InspectorView';
5
+ import { LoadingView } from './views/LoadingView';
6
+
7
+ import './globals.css';
8
+
9
+ export default function NetworkActivityPanel() {
10
+ const client = useRozeniteDevToolsClient<NetworkActivityEventMap>({
11
+ pluginId: '@rozenite/network-activity-plugin',
12
+ });
13
+
14
+ if (!client) {
15
+ return <LoadingView />;
16
+ }
17
+
18
+ return <InspectorView client={client} />;
19
+ }
@@ -0,0 +1,36 @@
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+
4
+ import { cn } from '../utils/cn';
5
+
6
+ const badgeVariants = cva(
7
+ 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
13
+ secondary:
14
+ 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
15
+ destructive:
16
+ 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
17
+ outline: 'text-foreground',
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: 'default',
22
+ },
23
+ }
24
+ );
25
+
26
+ export interface BadgeProps
27
+ extends React.HTMLAttributes<HTMLDivElement>,
28
+ VariantProps<typeof badgeVariants> {}
29
+
30
+ function Badge({ className, variant, ...props }: BadgeProps) {
31
+ return (
32
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
33
+ );
34
+ }
35
+
36
+ export { Badge, badgeVariants };
@@ -0,0 +1,56 @@
1
+ import * as React from 'react';
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva, type VariantProps } from 'class-variance-authority';
4
+
5
+ import { cn } from '../utils/cn';
6
+
7
+ const buttonVariants = cva(
8
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
13
+ destructive:
14
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
15
+ outline:
16
+ 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
17
+ secondary:
18
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19
+ ghost: 'hover:bg-gray-700 hover:text-gray-100',
20
+ link: 'text-primary underline-offset-4 hover:underline',
21
+ },
22
+ size: {
23
+ default: 'h-10 px-4 py-2',
24
+ sm: 'h-9 rounded-md px-3',
25
+ lg: 'h-11 rounded-md px-8',
26
+ icon: 'h-10 w-10',
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: 'default',
31
+ size: 'default',
32
+ },
33
+ }
34
+ );
35
+
36
+ export interface ButtonProps
37
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38
+ VariantProps<typeof buttonVariants> {
39
+ asChild?: boolean;
40
+ }
41
+
42
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
44
+ const Comp = asChild ? Slot : 'button';
45
+ return (
46
+ <Comp
47
+ className={cn(buttonVariants({ variant, size, className }))}
48
+ ref={ref}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+ );
54
+ Button.displayName = 'Button';
55
+
56
+ export { Button, buttonVariants };
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '../utils/cn';
4
+
5
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
6
+ ({ className, type, ...props }, ref) => {
7
+ return (
8
+ <input
9
+ type={type}
10
+ className={cn(
11
+ 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
12
+ className
13
+ )}
14
+ ref={ref}
15
+ {...props}
16
+ />
17
+ );
18
+ }
19
+ );
20
+ Input.displayName = 'Input';
21
+
22
+ export { Input };