@rozenite/network-activity-plugin 1.5.0 → 1.6.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/CHANGELOG.md +19 -0
- package/README.md +2 -0
- package/dist/boot-recording.cjs +1 -1
- package/dist/boot-recording.js +3 -1084
- package/dist/rozenite.json +1 -1
- package/dist/src/react-native/agent/__tests__/network-activity-agent-state.test.d.ts +1 -0
- package/dist/src/react-native/agent/state.d.ts +733 -0
- package/dist/src/react-native/agent/tools.d.ts +11 -0
- package/dist/src/react-native/agent/use-network-activity-agent-tools.d.ts +13 -0
- package/dist/useNetworkActivityDevTools.cjs +931 -0
- package/dist/useNetworkActivityDevTools.js +932 -1
- package/package.json +5 -4
- package/src/react-native/agent/__tests__/network-activity-agent-state.test.ts +250 -0
- package/src/react-native/agent/state.ts +869 -0
- package/src/react-native/agent/tools.ts +146 -0
- package/src/react-native/agent/use-network-activity-agent-tools.ts +244 -0
- package/src/react-native/http/http-inspector.ts +0 -1
- package/src/react-native/useNetworkActivityDevTools.ts +11 -0
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { AgentTool } from '@rozenite/agent-bridge';
|
|
2
|
+
|
|
3
|
+
export const startRecordingTool: AgentTool = {
|
|
4
|
+
name: 'startRecording',
|
|
5
|
+
description:
|
|
6
|
+
'Start recording network activity in the fallback network activity plugin.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {},
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const stopRecordingTool: AgentTool = {
|
|
14
|
+
name: 'stopRecording',
|
|
15
|
+
description:
|
|
16
|
+
'Stop recording network activity without clearing the captured plugin buffer.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const getRecordingStatusTool: AgentTool = {
|
|
24
|
+
name: 'getRecordingStatus',
|
|
25
|
+
description:
|
|
26
|
+
'Return network activity plugin recording state and buffer metadata.',
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const listRequestsTool: AgentTool = {
|
|
34
|
+
name: 'listRequests',
|
|
35
|
+
description:
|
|
36
|
+
'List captured HTTP request summaries with cursor pagination from the fallback plugin.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
limit: {
|
|
41
|
+
type: 'number',
|
|
42
|
+
description: 'Maximum number of requests to return. Defaults to 20.',
|
|
43
|
+
},
|
|
44
|
+
cursor: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
description: 'Opaque pagination cursor from a previous listRequests call.',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getRequestDetailsTool: AgentTool = {
|
|
53
|
+
name: 'getRequestDetails',
|
|
54
|
+
description:
|
|
55
|
+
'Return detailed metadata for a captured HTTP request without fetching response body.',
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
requestId: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
description: 'Captured plugin request ID to inspect.',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
required: ['requestId'],
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const getRequestBodyTool: AgentTool = {
|
|
69
|
+
name: 'getRequestBody',
|
|
70
|
+
description:
|
|
71
|
+
'Return the captured request body for a plugin-recorded HTTP request when available.',
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
requestId: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'Captured plugin request ID to inspect.',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
required: ['requestId'],
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const getResponseBodyTool: AgentTool = {
|
|
85
|
+
name: 'getResponseBody',
|
|
86
|
+
description:
|
|
87
|
+
'Return the captured response body for a plugin-recorded HTTP request when available.',
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
requestId: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
description: 'Captured plugin request ID to inspect.',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: ['requestId'],
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const listRealtimeConnectionsTool: AgentTool = {
|
|
101
|
+
name: 'listRealtimeConnections',
|
|
102
|
+
description:
|
|
103
|
+
'List captured WebSocket and SSE connections with cursor pagination.',
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
limit: {
|
|
108
|
+
type: 'number',
|
|
109
|
+
description: 'Maximum number of realtime connections to return. Defaults to 20.',
|
|
110
|
+
},
|
|
111
|
+
cursor: {
|
|
112
|
+
type: 'string',
|
|
113
|
+
description:
|
|
114
|
+
'Opaque pagination cursor from a previous listRealtimeConnections call.',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const getRealtimeConnectionDetailsTool: AgentTool = {
|
|
121
|
+
name: 'getRealtimeConnectionDetails',
|
|
122
|
+
description:
|
|
123
|
+
'Return details for a captured WebSocket or SSE connection, including recent messages.',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
requestId: {
|
|
128
|
+
type: 'string',
|
|
129
|
+
description: 'Captured realtime request ID to inspect.',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
required: ['requestId'],
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const NETWORK_ACTIVITY_AGENT_TOOLS: AgentTool[] = [
|
|
137
|
+
startRecordingTool,
|
|
138
|
+
stopRecordingTool,
|
|
139
|
+
getRecordingStatusTool,
|
|
140
|
+
listRequestsTool,
|
|
141
|
+
getRequestDetailsTool,
|
|
142
|
+
getRequestBodyTool,
|
|
143
|
+
getResponseBodyTool,
|
|
144
|
+
listRealtimeConnectionsTool,
|
|
145
|
+
getRealtimeConnectionDetailsTool,
|
|
146
|
+
];
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useRozenitePluginAgentTool } from '@rozenite/agent-bridge';
|
|
3
|
+
import type { NetworkActivityDevToolsClient } from '../../shared/client';
|
|
4
|
+
import type { NetworkInspector } from '../network-inspector';
|
|
5
|
+
import { getResponseBody } from '../http/http-utils';
|
|
6
|
+
import {
|
|
7
|
+
getNetworkActivityAgentState,
|
|
8
|
+
type NetworkActivityAgentBodyResult,
|
|
9
|
+
} from './state';
|
|
10
|
+
import {
|
|
11
|
+
getRecordingStatusTool,
|
|
12
|
+
getRealtimeConnectionDetailsTool,
|
|
13
|
+
getRequestBodyTool,
|
|
14
|
+
getRequestDetailsTool,
|
|
15
|
+
getResponseBodyTool,
|
|
16
|
+
listRealtimeConnectionsTool,
|
|
17
|
+
listRequestsTool,
|
|
18
|
+
startRecordingTool,
|
|
19
|
+
stopRecordingTool,
|
|
20
|
+
} from './tools';
|
|
21
|
+
|
|
22
|
+
const pluginId = '@rozenite/network-activity-plugin';
|
|
23
|
+
|
|
24
|
+
type PaginationInput = {
|
|
25
|
+
limit?: number;
|
|
26
|
+
cursor?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type RequestIdInput = {
|
|
30
|
+
requestId: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type AgentToolsConfig = {
|
|
34
|
+
client: NetworkActivityDevToolsClient | null;
|
|
35
|
+
networkInspector: NetworkInspector;
|
|
36
|
+
enabledInspectors: {
|
|
37
|
+
http: boolean;
|
|
38
|
+
websocket: boolean;
|
|
39
|
+
sse: boolean;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const useNetworkActivityAgentTools = ({
|
|
44
|
+
client,
|
|
45
|
+
networkInspector,
|
|
46
|
+
enabledInspectors,
|
|
47
|
+
}: AgentToolsConfig) => {
|
|
48
|
+
const state = getNetworkActivityAgentState();
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const unsubscribe = [
|
|
52
|
+
networkInspector.http.on('request-sent', (event) =>
|
|
53
|
+
state.onRequestSent(event)
|
|
54
|
+
),
|
|
55
|
+
networkInspector.http.on('request-progress', (event) =>
|
|
56
|
+
state.onRequestProgress(event)
|
|
57
|
+
),
|
|
58
|
+
networkInspector.http.on('response-received', (event) =>
|
|
59
|
+
state.onResponseReceived(event)
|
|
60
|
+
),
|
|
61
|
+
networkInspector.http.on('request-completed', (event) =>
|
|
62
|
+
state.onRequestCompleted(event)
|
|
63
|
+
),
|
|
64
|
+
networkInspector.http.on('request-failed', (event) =>
|
|
65
|
+
state.onRequestFailed(event)
|
|
66
|
+
),
|
|
67
|
+
networkInspector.websocket.on('websocket-connect', (event) =>
|
|
68
|
+
state.onWebSocketConnect(event)
|
|
69
|
+
),
|
|
70
|
+
networkInspector.websocket.on('websocket-open', (event) =>
|
|
71
|
+
state.onWebSocketOpen(event)
|
|
72
|
+
),
|
|
73
|
+
networkInspector.websocket.on('websocket-close', (event) =>
|
|
74
|
+
state.onWebSocketClose(event)
|
|
75
|
+
),
|
|
76
|
+
networkInspector.websocket.on('websocket-message-sent', (event) =>
|
|
77
|
+
state.onWebSocketMessageSent(event)
|
|
78
|
+
),
|
|
79
|
+
networkInspector.websocket.on('websocket-message-received', (event) =>
|
|
80
|
+
state.onWebSocketMessageReceived(event)
|
|
81
|
+
),
|
|
82
|
+
networkInspector.websocket.on('websocket-error', (event) =>
|
|
83
|
+
state.onWebSocketError(event)
|
|
84
|
+
),
|
|
85
|
+
networkInspector.websocket.on('websocket-connection-status-changed', (event) =>
|
|
86
|
+
state.onWebSocketConnectionStatusChanged(event)
|
|
87
|
+
),
|
|
88
|
+
networkInspector.sse.on('sse-open', (event) => state.onSSEOpen(event)),
|
|
89
|
+
networkInspector.sse.on('sse-message', (event) => state.onSSEMessage(event)),
|
|
90
|
+
networkInspector.sse.on('sse-error', (event) => state.onSSEError(event)),
|
|
91
|
+
networkInspector.sse.on('sse-close', (event) => state.onSSEClose(event)),
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
unsubscribe.forEach((remove) => remove());
|
|
96
|
+
};
|
|
97
|
+
}, [networkInspector, state]);
|
|
98
|
+
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (!client) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const subscriptions = [
|
|
105
|
+
client.onMessage('network-enable', () => {
|
|
106
|
+
state.startRecording({ enabledInspectors });
|
|
107
|
+
}),
|
|
108
|
+
client.onMessage('network-disable', () => {
|
|
109
|
+
if (state.getStatus().recording.isRecording) {
|
|
110
|
+
state.stopRecording();
|
|
111
|
+
}
|
|
112
|
+
}),
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
return () => {
|
|
116
|
+
subscriptions.forEach((subscription) => subscription.remove());
|
|
117
|
+
};
|
|
118
|
+
}, [client, enabledInspectors, state]);
|
|
119
|
+
|
|
120
|
+
useRozenitePluginAgentTool({
|
|
121
|
+
pluginId,
|
|
122
|
+
tool: startRecordingTool,
|
|
123
|
+
handler: () => {
|
|
124
|
+
networkInspector.http.getNetworkRequestsRegistry().clear();
|
|
125
|
+
const result = state.startRecording({ enabledInspectors });
|
|
126
|
+
networkInspector.enable(enabledInspectors);
|
|
127
|
+
return {
|
|
128
|
+
started: true,
|
|
129
|
+
...result,
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
useRozenitePluginAgentTool({
|
|
135
|
+
pluginId,
|
|
136
|
+
tool: stopRecordingTool,
|
|
137
|
+
handler: () => {
|
|
138
|
+
const result = state.stopRecording();
|
|
139
|
+
networkInspector.disable();
|
|
140
|
+
return {
|
|
141
|
+
stopped: true,
|
|
142
|
+
...result,
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
useRozenitePluginAgentTool({
|
|
148
|
+
pluginId,
|
|
149
|
+
tool: getRecordingStatusTool,
|
|
150
|
+
handler: () => state.getStatus(),
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
useRozenitePluginAgentTool<PaginationInput>({
|
|
154
|
+
pluginId,
|
|
155
|
+
tool: listRequestsTool,
|
|
156
|
+
handler: (input = {}) => state.listRequests(input),
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
useRozenitePluginAgentTool<RequestIdInput>({
|
|
160
|
+
pluginId,
|
|
161
|
+
tool: getRequestDetailsTool,
|
|
162
|
+
handler: ({ requestId }: RequestIdInput) => state.getRequestDetails(requestId),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
useRozenitePluginAgentTool<RequestIdInput>({
|
|
166
|
+
pluginId,
|
|
167
|
+
tool: getRequestBodyTool,
|
|
168
|
+
handler: ({ requestId }: RequestIdInput) => state.getRequestBody(requestId),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
useRozenitePluginAgentTool<
|
|
172
|
+
RequestIdInput,
|
|
173
|
+
Promise<NetworkActivityAgentBodyResult>
|
|
174
|
+
>({
|
|
175
|
+
pluginId,
|
|
176
|
+
tool: getResponseBodyTool,
|
|
177
|
+
handler: async ({ requestId }: RequestIdInput) => {
|
|
178
|
+
const record = state.getHttpRecord(requestId);
|
|
179
|
+
if (!record) {
|
|
180
|
+
throw new Error(`Unknown request "${requestId}"`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (record.status === 'failed') {
|
|
184
|
+
return {
|
|
185
|
+
requestId,
|
|
186
|
+
available: false,
|
|
187
|
+
reason: 'Response body is unavailable because the request failed.',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (record.status !== 'finished') {
|
|
192
|
+
return {
|
|
193
|
+
requestId,
|
|
194
|
+
available: false,
|
|
195
|
+
reason:
|
|
196
|
+
'Response body is unavailable until the request finishes loading.',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const request =
|
|
201
|
+
networkInspector.http.getNetworkRequestsRegistry().getEntry(requestId);
|
|
202
|
+
if (!request) {
|
|
203
|
+
return {
|
|
204
|
+
requestId,
|
|
205
|
+
available: false,
|
|
206
|
+
reason:
|
|
207
|
+
'Response body is unavailable because the request object is no longer in the plugin registry.',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const body = await getResponseBody(request);
|
|
212
|
+
if (body === null) {
|
|
213
|
+
return {
|
|
214
|
+
requestId,
|
|
215
|
+
available: false,
|
|
216
|
+
reason:
|
|
217
|
+
'The plugin could not extract a text response body for this request.',
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
requestId,
|
|
223
|
+
available: true,
|
|
224
|
+
body,
|
|
225
|
+
base64Encoded: false,
|
|
226
|
+
decoded: false,
|
|
227
|
+
mimeType: record.response?.contentType,
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
useRozenitePluginAgentTool<PaginationInput>({
|
|
233
|
+
pluginId,
|
|
234
|
+
tool: listRealtimeConnectionsTool,
|
|
235
|
+
handler: (input = {}) => state.listRealtimeConnections(input),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
useRozenitePluginAgentTool<RequestIdInput>({
|
|
239
|
+
pluginId,
|
|
240
|
+
tool: getRealtimeConnectionDetailsTool,
|
|
241
|
+
handler: ({ requestId }: RequestIdInput) =>
|
|
242
|
+
state.getRealtimeConnectionDetails(requestId),
|
|
243
|
+
});
|
|
244
|
+
};
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
validateConfig,
|
|
11
11
|
} from './config';
|
|
12
12
|
import { createNetworkInspectorsConfiguration } from './boot-recording';
|
|
13
|
+
import { useNetworkActivityAgentTools } from './agent/use-network-activity-agent-tools';
|
|
13
14
|
import { useHttpInspector } from './useHttpInspector';
|
|
14
15
|
import { useWebSocketInspector } from './useWebSocketInspector';
|
|
15
16
|
import { useSSEInspector } from './useSSEInspector';
|
|
@@ -31,6 +32,16 @@ export const useNetworkActivityDevTools = (
|
|
|
31
32
|
|
|
32
33
|
const { eventsListener, networkInspector } = inspectorsConfig;
|
|
33
34
|
|
|
35
|
+
useNetworkActivityAgentTools({
|
|
36
|
+
client,
|
|
37
|
+
networkInspector,
|
|
38
|
+
enabledInspectors: {
|
|
39
|
+
http: isHttpInspectorEnabled,
|
|
40
|
+
websocket: isWebSocketInspectorEnabled,
|
|
41
|
+
sse: isSSEInspectorEnabled,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
34
45
|
useEffect(() => {
|
|
35
46
|
if (!client) {
|
|
36
47
|
return;
|