chrome-cdp-cli 1.0.1 → 1.1.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 +333 -37
- package/dist/cli/CLIApplication.js +2 -0
- package/dist/handlers/GetConsoleMessageHandler.js +91 -0
- package/dist/handlers/GetNetworkRequestHandler.js +50 -0
- package/dist/handlers/ListConsoleMessagesHandler.js +114 -0
- package/dist/handlers/ListNetworkRequestsHandler.js +51 -0
- package/dist/handlers/index.js +4 -0
- package/dist/monitors/ConsoleMonitor.js +121 -0
- package/dist/monitors/NetworkMonitor.js +162 -0
- package/dist/monitors/index.js +18 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -2,17 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
A powerful command-line tool for controlling Chrome browser instances via the Chrome DevTools Protocol (CDP). This tool provides programmatic access to browser automation, debugging, and inspection capabilities without requiring a graphical interface.
|
|
4
4
|
|
|
5
|
+
## Implementation Status
|
|
6
|
+
|
|
7
|
+
### ✅ Fully Implemented Features
|
|
8
|
+
|
|
9
|
+
- 🔗 **Connection Management**: Connect to local or remote Chrome instances with auto-discovery
|
|
10
|
+
- ⚡ **JavaScript Execution**: Execute JavaScript code in browser context with full async support and file execution
|
|
11
|
+
- 📸 **Visual Capture**: Take screenshots and capture complete DOM snapshots with layout information
|
|
12
|
+
- 📊 **Console Monitoring**: Real-time console message capture with filtering and storage
|
|
13
|
+
- 🌐 **Network Monitoring**: Real-time network request/response monitoring with comprehensive filtering
|
|
14
|
+
- 🔧 **CLI Interface**: Full command-line interface with argument parsing and routing
|
|
15
|
+
- 📦 **Build System**: Complete TypeScript build pipeline with testing framework
|
|
16
|
+
|
|
17
|
+
### 🚧 Eval Workaround Available
|
|
18
|
+
|
|
19
|
+
These features are not directly implemented but can be achieved using the `eval` command:
|
|
20
|
+
|
|
21
|
+
- 📄 **Page Navigation**: `eval "window.location.href = 'https://example.com'"`
|
|
22
|
+
- 🖱️ **Element Interaction**: `eval "document.querySelector('#btn').click()"`
|
|
23
|
+
- 📝 **Form Filling**: `eval "document.querySelector('#input').value = 'text'"`
|
|
24
|
+
- 📄 **HTML Content**: `eval "document.documentElement.outerHTML"`
|
|
25
|
+
- 🚀 **Performance Data**: `eval "performance.now()"` or `eval "performance.getEntriesByType('navigation')"`
|
|
26
|
+
- 📱 **User Agent**: `eval "navigator.userAgent"`
|
|
27
|
+
- 🌐 **Network Requests**: `eval "fetch('/api').then(r => r.json())"`
|
|
28
|
+
|
|
29
|
+
### ⏳ Not Yet Implemented
|
|
30
|
+
|
|
31
|
+
- 📄 **Direct Page Management**: Native commands for creating, closing, listing, and selecting tabs
|
|
32
|
+
- 🖱️ **Direct Element Interaction**: Native click, hover, drag, and form filling commands
|
|
33
|
+
- 🚀 **Performance Analysis**: Native performance profiling and metrics collection
|
|
34
|
+
- 📱 **Device Emulation**: Native device and network condition simulation
|
|
35
|
+
- 📊 **Output Formatting**: Advanced JSON/text formatting with quiet/verbose modes
|
|
36
|
+
|
|
5
37
|
## Features
|
|
6
38
|
|
|
7
39
|
- 🔗 **Connection Management**: Connect to local or remote Chrome instances
|
|
8
|
-
- 📄 **Page Management**: Navigate, create, close, and manage browser tabs
|
|
9
40
|
- ⚡ **JavaScript Execution**: Execute JavaScript code in browser context with full async support
|
|
10
41
|
- 📸 **Visual Capture**: Take screenshots and capture HTML content
|
|
11
|
-
- 🖱️ **Element Interaction**: Click, hover, fill forms, and interact with page elements
|
|
12
42
|
- 📊 **Monitoring**: Monitor console messages and network requests in real-time
|
|
13
|
-
- 🚀 **Performance Analysis**: Profile page performance and analyze metrics
|
|
14
|
-
- 📱 **Device Emulation**: Simulate different devices and network conditions
|
|
15
43
|
- 🔧 **Flexible Output**: Support for JSON and human-readable text output formats
|
|
44
|
+
- 🚧 **Eval Workarounds**: Many advanced features available through JavaScript execution
|
|
16
45
|
|
|
17
46
|
## Installation
|
|
18
47
|
|
|
@@ -77,17 +106,26 @@ chrome-cdp-cli eval "document.title"
|
|
|
77
106
|
# Or use with npx (no installation needed)
|
|
78
107
|
npx chrome-cdp-cli eval "document.title"
|
|
79
108
|
|
|
80
|
-
# Navigate to a website
|
|
81
|
-
chrome-cdp-cli
|
|
109
|
+
# Navigate to a website (via eval)
|
|
110
|
+
chrome-cdp-cli eval "window.location.href = 'https://example.com'"
|
|
82
111
|
|
|
83
112
|
# Take a screenshot
|
|
84
113
|
chrome-cdp-cli screenshot --filename screenshot.png
|
|
85
114
|
|
|
86
|
-
#
|
|
87
|
-
chrome-cdp-cli
|
|
115
|
+
# Capture DOM snapshot
|
|
116
|
+
chrome-cdp-cli snapshot --filename dom-snapshot.json
|
|
117
|
+
|
|
118
|
+
# Click an element (via eval)
|
|
119
|
+
chrome-cdp-cli eval "document.querySelector('#submit-button').click()"
|
|
88
120
|
|
|
89
|
-
# Fill a form field
|
|
90
|
-
chrome-cdp-cli
|
|
121
|
+
# Fill a form field (via eval)
|
|
122
|
+
chrome-cdp-cli eval "document.querySelector('#email').value = 'user@example.com'"
|
|
123
|
+
|
|
124
|
+
# Monitor console messages
|
|
125
|
+
chrome-cdp-cli get_console_message
|
|
126
|
+
|
|
127
|
+
# Monitor network requests
|
|
128
|
+
chrome-cdp-cli get_network_request
|
|
91
129
|
|
|
92
130
|
# Get help for all commands
|
|
93
131
|
chrome-cdp-cli --help
|
|
@@ -112,7 +150,23 @@ All commands support these connection options:
|
|
|
112
150
|
- `--quiet`: Suppress non-essential output
|
|
113
151
|
- `--verbose`: Enable detailed logging
|
|
114
152
|
|
|
115
|
-
|
|
153
|
+
## Command Reference
|
|
154
|
+
|
|
155
|
+
### Connection Options
|
|
156
|
+
|
|
157
|
+
All commands support these connection options:
|
|
158
|
+
|
|
159
|
+
- `--host <host>`: Chrome host (default: localhost)
|
|
160
|
+
- `--port <port>`: DevTools port (default: 9222)
|
|
161
|
+
- `--timeout <ms>`: Command timeout in milliseconds (default: 30000)
|
|
162
|
+
|
|
163
|
+
### Output Options
|
|
164
|
+
|
|
165
|
+
- `--format <format>`: Output format - 'json' or 'text' (default: text)
|
|
166
|
+
- `--quiet`: Suppress non-essential output
|
|
167
|
+
- `--verbose`: Enable detailed logging
|
|
168
|
+
|
|
169
|
+
### ✅ Implemented Commands
|
|
116
170
|
|
|
117
171
|
#### JavaScript Execution
|
|
118
172
|
```bash
|
|
@@ -130,57 +184,299 @@ npx chrome-cdp-cli eval "document.title"
|
|
|
130
184
|
npx chrome-cdp-cli eval --file script.js
|
|
131
185
|
```
|
|
132
186
|
|
|
187
|
+
#### Visual Capture
|
|
188
|
+
```bash
|
|
189
|
+
# Take screenshot
|
|
190
|
+
chrome-cdp-cli screenshot --filename screenshot.png
|
|
191
|
+
|
|
192
|
+
# Full page screenshot
|
|
193
|
+
chrome-cdp-cli screenshot --full-page --filename fullpage.png
|
|
194
|
+
|
|
195
|
+
# DOM snapshot with complete layout information
|
|
196
|
+
chrome-cdp-cli snapshot --filename dom-snapshot.json
|
|
197
|
+
|
|
198
|
+
# Custom dimensions
|
|
199
|
+
chrome-cdp-cli screenshot --width 1920 --height 1080 --filename custom.png
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### Console Monitoring
|
|
203
|
+
```bash
|
|
204
|
+
# Get latest console message
|
|
205
|
+
chrome-cdp-cli get_console_message
|
|
206
|
+
|
|
207
|
+
# List all console messages
|
|
208
|
+
chrome-cdp-cli list_console_messages
|
|
209
|
+
|
|
210
|
+
# Filter console messages
|
|
211
|
+
chrome-cdp-cli list_console_messages --filter '{"types":["error","warn"]}'
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Network Monitoring
|
|
215
|
+
```bash
|
|
216
|
+
# Get latest network request
|
|
217
|
+
chrome-cdp-cli get_network_request
|
|
218
|
+
|
|
219
|
+
# List all network requests
|
|
220
|
+
chrome-cdp-cli list_network_requests
|
|
221
|
+
|
|
222
|
+
# Filter network requests
|
|
223
|
+
chrome-cdp-cli list_network_requests --filter '{"methods":["POST"],"statusCodes":[200,201]}'
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 🚧 Available via Eval Workarounds
|
|
227
|
+
|
|
133
228
|
#### Page Management
|
|
134
229
|
```bash
|
|
135
230
|
# Navigate to URL
|
|
136
|
-
chrome-cdp-cli
|
|
231
|
+
chrome-cdp-cli eval "window.location.href = 'https://example.com'"
|
|
137
232
|
|
|
138
|
-
#
|
|
139
|
-
chrome-cdp-cli
|
|
233
|
+
# Get current URL
|
|
234
|
+
chrome-cdp-cli eval "window.location.href"
|
|
140
235
|
|
|
141
|
-
#
|
|
142
|
-
chrome-cdp-cli
|
|
236
|
+
# Reload page
|
|
237
|
+
chrome-cdp-cli eval "window.location.reload()"
|
|
143
238
|
|
|
144
|
-
#
|
|
145
|
-
chrome-cdp-cli
|
|
239
|
+
# Go back
|
|
240
|
+
chrome-cdp-cli eval "window.history.back()"
|
|
146
241
|
|
|
147
|
-
#
|
|
148
|
-
chrome-cdp-cli
|
|
242
|
+
# Go forward
|
|
243
|
+
chrome-cdp-cli eval "window.history.forward()"
|
|
149
244
|
```
|
|
150
245
|
|
|
151
246
|
#### Element Interaction
|
|
152
247
|
```bash
|
|
153
248
|
# Click element
|
|
154
|
-
chrome-cdp-cli
|
|
249
|
+
chrome-cdp-cli eval "document.querySelector('#button').click()"
|
|
155
250
|
|
|
156
251
|
# Fill input field
|
|
157
|
-
chrome-cdp-cli
|
|
252
|
+
chrome-cdp-cli eval "document.querySelector('#email').value = 'user@example.com'"
|
|
253
|
+
|
|
254
|
+
# Hover over element (trigger mouseover event)
|
|
255
|
+
chrome-cdp-cli eval "document.querySelector('.menu-item').dispatchEvent(new MouseEvent('mouseover'))"
|
|
158
256
|
|
|
159
|
-
#
|
|
160
|
-
chrome-cdp-cli
|
|
257
|
+
# Check if element exists
|
|
258
|
+
chrome-cdp-cli eval "!!document.querySelector('#element')"
|
|
161
259
|
|
|
162
|
-
#
|
|
163
|
-
chrome-cdp-cli
|
|
260
|
+
# Get element text
|
|
261
|
+
chrome-cdp-cli eval "document.querySelector('#element').textContent"
|
|
262
|
+
|
|
263
|
+
# Get element attributes
|
|
264
|
+
chrome-cdp-cli eval "document.querySelector('#element').getAttribute('class')"
|
|
164
265
|
```
|
|
165
266
|
|
|
166
|
-
####
|
|
267
|
+
#### Form Handling
|
|
167
268
|
```bash
|
|
168
|
-
#
|
|
169
|
-
chrome-cdp-cli
|
|
269
|
+
# Fill multiple form fields
|
|
270
|
+
chrome-cdp-cli eval "
|
|
271
|
+
document.querySelector('#name').value = 'John Doe';
|
|
272
|
+
document.querySelector('#email').value = 'john@example.com';
|
|
273
|
+
document.querySelector('#phone').value = '123-456-7890';
|
|
274
|
+
"
|
|
170
275
|
|
|
171
|
-
#
|
|
172
|
-
chrome-cdp-cli
|
|
276
|
+
# Submit form
|
|
277
|
+
chrome-cdp-cli eval "document.querySelector('#myform').submit()"
|
|
173
278
|
|
|
174
|
-
#
|
|
175
|
-
chrome-cdp-cli
|
|
279
|
+
# Select dropdown option
|
|
280
|
+
chrome-cdp-cli eval "document.querySelector('#dropdown').value = 'option1'"
|
|
176
281
|
|
|
177
|
-
#
|
|
178
|
-
chrome-cdp-cli
|
|
282
|
+
# Check checkbox
|
|
283
|
+
chrome-cdp-cli eval "document.querySelector('#checkbox').checked = true"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
#### Content Extraction
|
|
287
|
+
```bash
|
|
288
|
+
# Get page HTML
|
|
289
|
+
chrome-cdp-cli eval "document.documentElement.outerHTML"
|
|
290
|
+
|
|
291
|
+
# Get page title
|
|
292
|
+
chrome-cdp-cli eval "document.title"
|
|
293
|
+
|
|
294
|
+
# Get all links
|
|
295
|
+
chrome-cdp-cli eval "Array.from(document.querySelectorAll('a')).map(a => a.href)"
|
|
296
|
+
|
|
297
|
+
# Get all images
|
|
298
|
+
chrome-cdp-cli eval "Array.from(document.querySelectorAll('img')).map(img => img.src)"
|
|
299
|
+
|
|
300
|
+
# Extract table data
|
|
301
|
+
chrome-cdp-cli eval "Array.from(document.querySelectorAll('table tr')).map(row => Array.from(row.cells).map(cell => cell.textContent))"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Performance Monitoring
|
|
305
|
+
```bash
|
|
306
|
+
# Get performance timing
|
|
307
|
+
chrome-cdp-cli eval "performance.timing"
|
|
308
|
+
|
|
309
|
+
# Get navigation entries
|
|
310
|
+
chrome-cdp-cli eval "performance.getEntriesByType('navigation')"
|
|
311
|
+
|
|
312
|
+
# Get resource entries
|
|
313
|
+
chrome-cdp-cli eval "performance.getEntriesByType('resource')"
|
|
314
|
+
|
|
315
|
+
# Get current timestamp
|
|
316
|
+
chrome-cdp-cli eval "performance.now()"
|
|
317
|
+
|
|
318
|
+
# Measure performance
|
|
319
|
+
chrome-cdp-cli eval "
|
|
320
|
+
performance.mark('start');
|
|
321
|
+
// ... some operation ...
|
|
322
|
+
performance.mark('end');
|
|
323
|
+
performance.measure('operation', 'start', 'end');
|
|
324
|
+
performance.getEntriesByName('operation')[0].duration;
|
|
325
|
+
"
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### Network Operations
|
|
329
|
+
```bash
|
|
330
|
+
# Make HTTP request
|
|
331
|
+
chrome-cdp-cli eval "fetch('/api/data').then(r => r.json())"
|
|
332
|
+
|
|
333
|
+
# POST data
|
|
334
|
+
chrome-cdp-cli eval "
|
|
335
|
+
fetch('/api/users', {
|
|
336
|
+
method: 'POST',
|
|
337
|
+
headers: {'Content-Type': 'application/json'},
|
|
338
|
+
body: JSON.stringify({name: 'John', email: 'john@example.com'})
|
|
339
|
+
}).then(r => r.json())
|
|
340
|
+
"
|
|
341
|
+
|
|
342
|
+
# Check network connectivity
|
|
343
|
+
chrome-cdp-cli eval "navigator.onLine"
|
|
344
|
+
```
|
|
179
345
|
|
|
180
|
-
|
|
181
|
-
|
|
346
|
+
#### Browser Information
|
|
347
|
+
```bash
|
|
348
|
+
# Get user agent
|
|
349
|
+
chrome-cdp-cli eval "navigator.userAgent"
|
|
350
|
+
|
|
351
|
+
# Get viewport size
|
|
352
|
+
chrome-cdp-cli eval "{width: window.innerWidth, height: window.innerHeight}"
|
|
353
|
+
|
|
354
|
+
# Get screen resolution
|
|
355
|
+
chrome-cdp-cli eval "{width: screen.width, height: screen.height}"
|
|
356
|
+
|
|
357
|
+
# Get browser language
|
|
358
|
+
chrome-cdp-cli eval "navigator.language"
|
|
359
|
+
|
|
360
|
+
# Get cookies
|
|
361
|
+
chrome-cdp-cli eval "document.cookie"
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### ⏳ Not Yet Implemented
|
|
365
|
+
|
|
366
|
+
These features require dedicated handlers and are not yet available:
|
|
367
|
+
|
|
368
|
+
- Native page management commands (new_page, close_page, list_pages, select_page)
|
|
369
|
+
- Native element interaction commands (click, hover, fill, drag)
|
|
370
|
+
- Native performance profiling commands
|
|
371
|
+
- Native device emulation commands
|
|
372
|
+
- Advanced output formatting options
|
|
373
|
+
|
|
374
|
+
## The Power of Eval
|
|
375
|
+
|
|
376
|
+
The `eval` command is the most powerful feature of this CLI tool. It allows you to execute any JavaScript code in the browser context, making it possible to achieve almost any browser automation task. Here are some advanced examples:
|
|
377
|
+
|
|
378
|
+
### Advanced Automation Examples
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
# Wait for element to appear
|
|
382
|
+
chrome-cdp-cli eval "
|
|
383
|
+
new Promise(resolve => {
|
|
384
|
+
const check = () => {
|
|
385
|
+
const element = document.querySelector('#dynamic-content');
|
|
386
|
+
if (element) resolve(element.textContent);
|
|
387
|
+
else setTimeout(check, 100);
|
|
388
|
+
};
|
|
389
|
+
check();
|
|
390
|
+
})
|
|
391
|
+
"
|
|
392
|
+
|
|
393
|
+
# Scroll to element
|
|
394
|
+
chrome-cdp-cli eval "
|
|
395
|
+
document.querySelector('#target').scrollIntoView({behavior: 'smooth'});
|
|
396
|
+
"
|
|
397
|
+
|
|
398
|
+
# Take element screenshot (get element bounds for screenshot)
|
|
399
|
+
chrome-cdp-cli eval "
|
|
400
|
+
const element = document.querySelector('#target');
|
|
401
|
+
const rect = element.getBoundingClientRect();
|
|
402
|
+
({x: rect.x, y: rect.y, width: rect.width, height: rect.height})
|
|
403
|
+
"
|
|
404
|
+
|
|
405
|
+
# Simulate complex user interactions
|
|
406
|
+
chrome-cdp-cli eval "
|
|
407
|
+
const element = document.querySelector('#button');
|
|
408
|
+
element.dispatchEvent(new MouseEvent('mousedown'));
|
|
409
|
+
setTimeout(() => element.dispatchEvent(new MouseEvent('mouseup')), 100);
|
|
410
|
+
"
|
|
411
|
+
|
|
412
|
+
# Extract structured data
|
|
413
|
+
chrome-cdp-cli eval "
|
|
414
|
+
Array.from(document.querySelectorAll('.product')).map(product => ({
|
|
415
|
+
name: product.querySelector('.name').textContent,
|
|
416
|
+
price: product.querySelector('.price').textContent,
|
|
417
|
+
image: product.querySelector('img').src
|
|
418
|
+
}))
|
|
419
|
+
"
|
|
420
|
+
|
|
421
|
+
# Monitor page changes
|
|
422
|
+
chrome-cdp-cli eval "
|
|
423
|
+
new Promise(resolve => {
|
|
424
|
+
const observer = new MutationObserver(mutations => {
|
|
425
|
+
resolve(mutations.length + ' changes detected');
|
|
426
|
+
observer.disconnect();
|
|
427
|
+
});
|
|
428
|
+
observer.observe(document.body, {childList: true, subtree: true});
|
|
429
|
+
setTimeout(() => {
|
|
430
|
+
observer.disconnect();
|
|
431
|
+
resolve('No changes in 5 seconds');
|
|
432
|
+
}, 5000);
|
|
433
|
+
})
|
|
434
|
+
"
|
|
182
435
|
```
|
|
183
436
|
|
|
437
|
+
## Current Limitations & Roadmap
|
|
438
|
+
|
|
439
|
+
### Current Limitations
|
|
440
|
+
|
|
441
|
+
- **No native page management**: Creating, closing, and switching between tabs requires manual implementation
|
|
442
|
+
- **No native element interaction**: Clicking, hovering, and form filling must be done via eval
|
|
443
|
+
- **No performance profiling**: Advanced performance analysis requires manual JavaScript
|
|
444
|
+
- **No device emulation**: Mobile/tablet simulation not yet implemented
|
|
445
|
+
- **Basic output formatting**: Advanced JSON/text formatting options not available
|
|
446
|
+
|
|
447
|
+
### Upcoming Features
|
|
448
|
+
|
|
449
|
+
1. **Native Page Management Commands**
|
|
450
|
+
- `new_page`, `close_page`, `list_pages`, `select_page`
|
|
451
|
+
- Direct CDP Target domain integration
|
|
452
|
+
|
|
453
|
+
2. **Native Element Interaction**
|
|
454
|
+
- `click`, `hover`, `fill`, `drag` commands
|
|
455
|
+
- CSS selector-based element targeting
|
|
456
|
+
|
|
457
|
+
3. **Performance Analysis**
|
|
458
|
+
- `performance_start_trace`, `performance_stop_trace`
|
|
459
|
+
- Built-in performance metrics and analysis
|
|
460
|
+
|
|
461
|
+
4. **Device Emulation**
|
|
462
|
+
- `emulate` command for device simulation
|
|
463
|
+
- Network condition simulation
|
|
464
|
+
|
|
465
|
+
5. **Advanced Output Formatting**
|
|
466
|
+
- Enhanced JSON/text formatting
|
|
467
|
+
- Quiet and verbose modes
|
|
468
|
+
- Custom output templates
|
|
469
|
+
|
|
470
|
+
### Why Use Eval Workarounds?
|
|
471
|
+
|
|
472
|
+
The eval approach offers several advantages:
|
|
473
|
+
|
|
474
|
+
- **Immediate availability**: No waiting for feature implementation
|
|
475
|
+
- **Maximum flexibility**: Any JavaScript operation is possible
|
|
476
|
+
- **Learning opportunity**: Better understanding of browser APIs
|
|
477
|
+
- **Custom solutions**: Tailor automation to specific needs
|
|
478
|
+
- **Future-proof**: Works with any web technology
|
|
479
|
+
|
|
184
480
|
## Configuration
|
|
185
481
|
|
|
186
482
|
### Configuration File
|
|
@@ -17,6 +17,8 @@ class CLIApplication {
|
|
|
17
17
|
this.cli.registerHandler(new handlers_1.EvaluateScriptHandler());
|
|
18
18
|
this.cli.registerHandler(new handlers_1.TakeScreenshotHandler());
|
|
19
19
|
this.cli.registerHandler(new handlers_1.TakeSnapshotHandler());
|
|
20
|
+
this.cli.registerHandler(new handlers_1.GetConsoleMessageHandler());
|
|
21
|
+
this.cli.registerHandler(new handlers_1.ListConsoleMessagesHandler());
|
|
20
22
|
}
|
|
21
23
|
async run(argv) {
|
|
22
24
|
try {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetConsoleMessageHandler = void 0;
|
|
4
|
+
const ConsoleMonitor_1 = require("../monitors/ConsoleMonitor");
|
|
5
|
+
class GetConsoleMessageHandler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'get_console_message';
|
|
8
|
+
this.consoleMonitor = null;
|
|
9
|
+
}
|
|
10
|
+
async execute(client, args) {
|
|
11
|
+
try {
|
|
12
|
+
const params = args;
|
|
13
|
+
if (!this.consoleMonitor) {
|
|
14
|
+
this.consoleMonitor = new ConsoleMonitor_1.ConsoleMonitor(client);
|
|
15
|
+
}
|
|
16
|
+
if (params.startMonitoring || !this.consoleMonitor.isActive()) {
|
|
17
|
+
await this.consoleMonitor.startMonitoring();
|
|
18
|
+
}
|
|
19
|
+
const filter = {};
|
|
20
|
+
if (params.type) {
|
|
21
|
+
filter.types = [params.type];
|
|
22
|
+
}
|
|
23
|
+
if (params.textPattern) {
|
|
24
|
+
filter.textPattern = params.textPattern;
|
|
25
|
+
}
|
|
26
|
+
const latestMessage = this.consoleMonitor.getLatestMessage(filter);
|
|
27
|
+
if (!latestMessage) {
|
|
28
|
+
return {
|
|
29
|
+
success: true,
|
|
30
|
+
data: null
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
success: true,
|
|
35
|
+
data: {
|
|
36
|
+
type: latestMessage.type,
|
|
37
|
+
text: latestMessage.text,
|
|
38
|
+
args: latestMessage.args,
|
|
39
|
+
timestamp: latestMessage.timestamp,
|
|
40
|
+
stackTrace: latestMessage.stackTrace
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
validateArgs(args) {
|
|
52
|
+
if (!args || typeof args !== 'object') {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
const params = args;
|
|
56
|
+
if (params.type !== undefined) {
|
|
57
|
+
if (typeof params.type !== 'string') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const validTypes = ['log', 'info', 'warn', 'error', 'debug'];
|
|
61
|
+
if (!validTypes.includes(params.type)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (params.textPattern !== undefined && typeof params.textPattern !== 'string') {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (params.startMonitoring !== undefined && typeof params.startMonitoring !== 'boolean') {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
getHelp() {
|
|
74
|
+
return `get_console_message - Get the latest console message
|
|
75
|
+
|
|
76
|
+
Usage:
|
|
77
|
+
get_console_message [options]
|
|
78
|
+
|
|
79
|
+
Options:
|
|
80
|
+
--type <type> Filter by message type (log, info, warn, error, debug)
|
|
81
|
+
--textPattern <pattern> Filter by text pattern (regex)
|
|
82
|
+
--startMonitoring Start monitoring if not already active
|
|
83
|
+
|
|
84
|
+
Examples:
|
|
85
|
+
get_console_message
|
|
86
|
+
get_console_message --type error
|
|
87
|
+
get_console_message --textPattern "API"
|
|
88
|
+
get_console_message --startMonitoring`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.GetConsoleMessageHandler = GetConsoleMessageHandler;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetNetworkRequestHandler = void 0;
|
|
4
|
+
const NetworkMonitor_1 = require("../monitors/NetworkMonitor");
|
|
5
|
+
class GetNetworkRequestHandler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'get_network_request';
|
|
8
|
+
this.networkMonitor = null;
|
|
9
|
+
}
|
|
10
|
+
async execute(client, args) {
|
|
11
|
+
try {
|
|
12
|
+
const params = args;
|
|
13
|
+
if (!this.networkMonitor) {
|
|
14
|
+
this.networkMonitor = new NetworkMonitor_1.NetworkMonitor(client);
|
|
15
|
+
}
|
|
16
|
+
if (!this.networkMonitor.isActive()) {
|
|
17
|
+
await this.networkMonitor.startMonitoring();
|
|
18
|
+
}
|
|
19
|
+
const filter = params.filter ? {
|
|
20
|
+
methods: params.filter.methods,
|
|
21
|
+
urlPattern: params.filter.urlPattern,
|
|
22
|
+
statusCodes: params.filter.statusCodes,
|
|
23
|
+
} : undefined;
|
|
24
|
+
const latestRequest = this.networkMonitor.getLatestRequest(filter);
|
|
25
|
+
if (!latestRequest) {
|
|
26
|
+
return {
|
|
27
|
+
success: true,
|
|
28
|
+
data: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
data: latestRequest
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
getNetworkMonitor() {
|
|
44
|
+
return this.networkMonitor;
|
|
45
|
+
}
|
|
46
|
+
setNetworkMonitor(monitor) {
|
|
47
|
+
this.networkMonitor = monitor;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.GetNetworkRequestHandler = GetNetworkRequestHandler;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ListConsoleMessagesHandler = void 0;
|
|
4
|
+
const ConsoleMonitor_1 = require("../monitors/ConsoleMonitor");
|
|
5
|
+
class ListConsoleMessagesHandler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'list_console_messages';
|
|
8
|
+
this.consoleMonitor = null;
|
|
9
|
+
}
|
|
10
|
+
async execute(client, args) {
|
|
11
|
+
try {
|
|
12
|
+
const params = args;
|
|
13
|
+
if (!this.consoleMonitor) {
|
|
14
|
+
this.consoleMonitor = new ConsoleMonitor_1.ConsoleMonitor(client);
|
|
15
|
+
}
|
|
16
|
+
if (params.startMonitoring || !this.consoleMonitor.isActive()) {
|
|
17
|
+
await this.consoleMonitor.startMonitoring();
|
|
18
|
+
}
|
|
19
|
+
const filter = {};
|
|
20
|
+
if (params.types && params.types.length > 0) {
|
|
21
|
+
filter.types = params.types;
|
|
22
|
+
}
|
|
23
|
+
if (params.textPattern) {
|
|
24
|
+
filter.textPattern = params.textPattern;
|
|
25
|
+
}
|
|
26
|
+
if (params.maxMessages && params.maxMessages > 0) {
|
|
27
|
+
filter.maxMessages = params.maxMessages;
|
|
28
|
+
}
|
|
29
|
+
if (params.startTime) {
|
|
30
|
+
filter.startTime = params.startTime;
|
|
31
|
+
}
|
|
32
|
+
if (params.endTime) {
|
|
33
|
+
filter.endTime = params.endTime;
|
|
34
|
+
}
|
|
35
|
+
const messages = this.consoleMonitor.getMessages(filter);
|
|
36
|
+
return {
|
|
37
|
+
success: true,
|
|
38
|
+
data: {
|
|
39
|
+
messages: messages.map(msg => ({
|
|
40
|
+
type: msg.type,
|
|
41
|
+
text: msg.text,
|
|
42
|
+
args: msg.args,
|
|
43
|
+
timestamp: msg.timestamp,
|
|
44
|
+
stackTrace: msg.stackTrace
|
|
45
|
+
})),
|
|
46
|
+
totalCount: messages.length,
|
|
47
|
+
isMonitoring: this.consoleMonitor.isActive()
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
validateArgs(args) {
|
|
59
|
+
if (!args || typeof args !== 'object') {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const params = args;
|
|
63
|
+
if (params.types !== undefined) {
|
|
64
|
+
if (!Array.isArray(params.types)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const validTypes = ['log', 'info', 'warn', 'error', 'debug'];
|
|
68
|
+
for (const type of params.types) {
|
|
69
|
+
if (typeof type !== 'string' || !validTypes.includes(type)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (params.textPattern !== undefined && typeof params.textPattern !== 'string') {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (params.maxMessages !== undefined) {
|
|
78
|
+
if (typeof params.maxMessages !== 'number' || params.maxMessages <= 0) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (params.startTime !== undefined && typeof params.startTime !== 'number') {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
if (params.endTime !== undefined && typeof params.endTime !== 'number') {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (params.startMonitoring !== undefined && typeof params.startMonitoring !== 'boolean') {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
getHelp() {
|
|
94
|
+
return `list_console_messages - List all captured console messages
|
|
95
|
+
|
|
96
|
+
Usage:
|
|
97
|
+
list_console_messages [options]
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
--types <types> Filter by message types (comma-separated: log,info,warn,error,debug)
|
|
101
|
+
--textPattern <pattern> Filter by text pattern (regex)
|
|
102
|
+
--maxMessages <count> Maximum number of messages to return
|
|
103
|
+
--startTime <timestamp> Filter messages after this timestamp
|
|
104
|
+
--endTime <timestamp> Filter messages before this timestamp
|
|
105
|
+
--startMonitoring Start monitoring if not already active
|
|
106
|
+
|
|
107
|
+
Examples:
|
|
108
|
+
list_console_messages
|
|
109
|
+
list_console_messages --types error,warn
|
|
110
|
+
list_console_messages --textPattern "API" --maxMessages 10
|
|
111
|
+
list_console_messages --startTime 1640995200000`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.ListConsoleMessagesHandler = ListConsoleMessagesHandler;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ListNetworkRequestsHandler = void 0;
|
|
4
|
+
const NetworkMonitor_1 = require("../monitors/NetworkMonitor");
|
|
5
|
+
class ListNetworkRequestsHandler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'list_network_requests';
|
|
8
|
+
this.networkMonitor = null;
|
|
9
|
+
}
|
|
10
|
+
async execute(client, args) {
|
|
11
|
+
try {
|
|
12
|
+
const params = args;
|
|
13
|
+
if (!this.networkMonitor) {
|
|
14
|
+
this.networkMonitor = new NetworkMonitor_1.NetworkMonitor(client);
|
|
15
|
+
}
|
|
16
|
+
if (!this.networkMonitor.isActive()) {
|
|
17
|
+
await this.networkMonitor.startMonitoring();
|
|
18
|
+
}
|
|
19
|
+
const filter = params.filter ? {
|
|
20
|
+
methods: params.filter.methods,
|
|
21
|
+
urlPattern: params.filter.urlPattern,
|
|
22
|
+
statusCodes: params.filter.statusCodes,
|
|
23
|
+
maxRequests: params.filter.maxRequests,
|
|
24
|
+
startTime: params.filter.startTime,
|
|
25
|
+
endTime: params.filter.endTime,
|
|
26
|
+
} : undefined;
|
|
27
|
+
const requests = this.networkMonitor.getRequests(filter);
|
|
28
|
+
return {
|
|
29
|
+
success: true,
|
|
30
|
+
data: {
|
|
31
|
+
requests,
|
|
32
|
+
count: requests.length,
|
|
33
|
+
isMonitoring: this.networkMonitor.isActive()
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
getNetworkMonitor() {
|
|
45
|
+
return this.networkMonitor;
|
|
46
|
+
}
|
|
47
|
+
setNetworkMonitor(monitor) {
|
|
48
|
+
this.networkMonitor = monitor;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ListNetworkRequestsHandler = ListNetworkRequestsHandler;
|
package/dist/handlers/index.js
CHANGED
|
@@ -17,3 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./EvaluateScriptHandler"), exports);
|
|
18
18
|
__exportStar(require("./TakeScreenshotHandler"), exports);
|
|
19
19
|
__exportStar(require("./TakeSnapshotHandler"), exports);
|
|
20
|
+
__exportStar(require("./GetConsoleMessageHandler"), exports);
|
|
21
|
+
__exportStar(require("./ListConsoleMessagesHandler"), exports);
|
|
22
|
+
__exportStar(require("./GetNetworkRequestHandler"), exports);
|
|
23
|
+
__exportStar(require("./ListNetworkRequestsHandler"), exports);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsoleMonitor = void 0;
|
|
4
|
+
class ConsoleMonitor {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.messages = [];
|
|
7
|
+
this.isMonitoring = false;
|
|
8
|
+
this.messageHandler = null;
|
|
9
|
+
this.client = client;
|
|
10
|
+
}
|
|
11
|
+
async startMonitoring() {
|
|
12
|
+
if (this.isMonitoring) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
await this.client.send('Runtime.enable');
|
|
16
|
+
this.messageHandler = (params) => {
|
|
17
|
+
this.handleConsoleMessage(params);
|
|
18
|
+
};
|
|
19
|
+
this.client.on('Runtime.consoleAPICalled', this.messageHandler);
|
|
20
|
+
this.isMonitoring = true;
|
|
21
|
+
}
|
|
22
|
+
async stopMonitoring() {
|
|
23
|
+
if (!this.isMonitoring || !this.messageHandler) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.client.off('Runtime.consoleAPICalled', this.messageHandler);
|
|
27
|
+
this.messageHandler = null;
|
|
28
|
+
this.isMonitoring = false;
|
|
29
|
+
}
|
|
30
|
+
getMessages(filter) {
|
|
31
|
+
let filteredMessages = [...this.messages];
|
|
32
|
+
if (filter) {
|
|
33
|
+
if (filter.types && filter.types.length > 0) {
|
|
34
|
+
filteredMessages = filteredMessages.filter(msg => filter.types.includes(msg.type));
|
|
35
|
+
}
|
|
36
|
+
if (filter.textPattern) {
|
|
37
|
+
const pattern = new RegExp(filter.textPattern, 'i');
|
|
38
|
+
filteredMessages = filteredMessages.filter(msg => pattern.test(msg.text));
|
|
39
|
+
}
|
|
40
|
+
if (filter.startTime) {
|
|
41
|
+
filteredMessages = filteredMessages.filter(msg => msg.timestamp >= filter.startTime);
|
|
42
|
+
}
|
|
43
|
+
if (filter.endTime) {
|
|
44
|
+
filteredMessages = filteredMessages.filter(msg => msg.timestamp <= filter.endTime);
|
|
45
|
+
}
|
|
46
|
+
if (filter.maxMessages && filter.maxMessages > 0) {
|
|
47
|
+
filteredMessages = filteredMessages.slice(-filter.maxMessages);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return filteredMessages;
|
|
51
|
+
}
|
|
52
|
+
getLatestMessage(filter) {
|
|
53
|
+
const messages = this.getMessages(filter);
|
|
54
|
+
return messages.length > 0 ? messages[messages.length - 1] : null;
|
|
55
|
+
}
|
|
56
|
+
clearMessages() {
|
|
57
|
+
this.messages = [];
|
|
58
|
+
}
|
|
59
|
+
getMessageCount(filter) {
|
|
60
|
+
return this.getMessages(filter).length;
|
|
61
|
+
}
|
|
62
|
+
isActive() {
|
|
63
|
+
return this.isMonitoring;
|
|
64
|
+
}
|
|
65
|
+
handleConsoleMessage(params) {
|
|
66
|
+
try {
|
|
67
|
+
const consoleParams = params;
|
|
68
|
+
const message = {
|
|
69
|
+
type: this.mapConsoleType(consoleParams.type),
|
|
70
|
+
text: this.formatConsoleArgs(consoleParams.args),
|
|
71
|
+
args: consoleParams.args.map(arg => arg.value || arg.description || ''),
|
|
72
|
+
timestamp: consoleParams.timestamp,
|
|
73
|
+
stackTrace: consoleParams.stackTrace ?
|
|
74
|
+
this.convertStackTrace(consoleParams.stackTrace.callFrames) : undefined
|
|
75
|
+
};
|
|
76
|
+
this.messages.push(message);
|
|
77
|
+
if (this.messages.length > 1000) {
|
|
78
|
+
this.messages = this.messages.slice(-1000);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error('Error handling console message:', error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
mapConsoleType(cdpType) {
|
|
86
|
+
switch (cdpType) {
|
|
87
|
+
case 'log':
|
|
88
|
+
return 'log';
|
|
89
|
+
case 'info':
|
|
90
|
+
return 'info';
|
|
91
|
+
case 'warning':
|
|
92
|
+
return 'warn';
|
|
93
|
+
case 'error':
|
|
94
|
+
return 'error';
|
|
95
|
+
case 'debug':
|
|
96
|
+
return 'debug';
|
|
97
|
+
default:
|
|
98
|
+
return 'log';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
formatConsoleArgs(args) {
|
|
102
|
+
return args.map(arg => {
|
|
103
|
+
if (arg.value !== undefined) {
|
|
104
|
+
if (typeof arg.value === 'string') {
|
|
105
|
+
return arg.value;
|
|
106
|
+
}
|
|
107
|
+
return JSON.stringify(arg.value);
|
|
108
|
+
}
|
|
109
|
+
return arg.description || '';
|
|
110
|
+
}).join(' ');
|
|
111
|
+
}
|
|
112
|
+
convertStackTrace(callFrames) {
|
|
113
|
+
return callFrames.map(frame => ({
|
|
114
|
+
functionName: frame.functionName || '<anonymous>',
|
|
115
|
+
url: frame.url,
|
|
116
|
+
lineNumber: frame.lineNumber,
|
|
117
|
+
columnNumber: frame.columnNumber
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.ConsoleMonitor = ConsoleMonitor;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NetworkMonitor = void 0;
|
|
4
|
+
class NetworkMonitor {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.requests = new Map();
|
|
7
|
+
this.completedRequests = [];
|
|
8
|
+
this.isMonitoring = false;
|
|
9
|
+
this.requestWillBeSentHandler = null;
|
|
10
|
+
this.responseReceivedHandler = null;
|
|
11
|
+
this.loadingFinishedHandler = null;
|
|
12
|
+
this.loadingFailedHandler = null;
|
|
13
|
+
this.client = client;
|
|
14
|
+
}
|
|
15
|
+
async startMonitoring() {
|
|
16
|
+
if (this.isMonitoring) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
await this.client.send('Network.enable');
|
|
20
|
+
this.requestWillBeSentHandler = (params) => {
|
|
21
|
+
this.handleRequestWillBeSent(params);
|
|
22
|
+
};
|
|
23
|
+
this.responseReceivedHandler = (params) => {
|
|
24
|
+
this.handleResponseReceived(params);
|
|
25
|
+
};
|
|
26
|
+
this.loadingFinishedHandler = (params) => {
|
|
27
|
+
this.handleLoadingFinished(params);
|
|
28
|
+
};
|
|
29
|
+
this.loadingFailedHandler = (params) => {
|
|
30
|
+
this.handleLoadingFailed(params);
|
|
31
|
+
};
|
|
32
|
+
this.client.on('Network.requestWillBeSent', this.requestWillBeSentHandler);
|
|
33
|
+
this.client.on('Network.responseReceived', this.responseReceivedHandler);
|
|
34
|
+
this.client.on('Network.loadingFinished', this.loadingFinishedHandler);
|
|
35
|
+
this.client.on('Network.loadingFailed', this.loadingFailedHandler);
|
|
36
|
+
this.isMonitoring = true;
|
|
37
|
+
}
|
|
38
|
+
async stopMonitoring() {
|
|
39
|
+
if (!this.isMonitoring) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (this.requestWillBeSentHandler) {
|
|
43
|
+
this.client.off('Network.requestWillBeSent', this.requestWillBeSentHandler);
|
|
44
|
+
this.requestWillBeSentHandler = null;
|
|
45
|
+
}
|
|
46
|
+
if (this.responseReceivedHandler) {
|
|
47
|
+
this.client.off('Network.responseReceived', this.responseReceivedHandler);
|
|
48
|
+
this.responseReceivedHandler = null;
|
|
49
|
+
}
|
|
50
|
+
if (this.loadingFinishedHandler) {
|
|
51
|
+
this.client.off('Network.loadingFinished', this.loadingFinishedHandler);
|
|
52
|
+
this.loadingFinishedHandler = null;
|
|
53
|
+
}
|
|
54
|
+
if (this.loadingFailedHandler) {
|
|
55
|
+
this.client.off('Network.loadingFailed', this.loadingFailedHandler);
|
|
56
|
+
this.loadingFailedHandler = null;
|
|
57
|
+
}
|
|
58
|
+
this.isMonitoring = false;
|
|
59
|
+
}
|
|
60
|
+
getRequests(filter) {
|
|
61
|
+
let filteredRequests = [...this.completedRequests];
|
|
62
|
+
if (filter) {
|
|
63
|
+
if (filter.methods && filter.methods.length > 0) {
|
|
64
|
+
filteredRequests = filteredRequests.filter(req => filter.methods.includes(req.method.toUpperCase()));
|
|
65
|
+
}
|
|
66
|
+
if (filter.urlPattern) {
|
|
67
|
+
const pattern = new RegExp(filter.urlPattern, 'i');
|
|
68
|
+
filteredRequests = filteredRequests.filter(req => pattern.test(req.url));
|
|
69
|
+
}
|
|
70
|
+
if (filter.statusCodes && filter.statusCodes.length > 0) {
|
|
71
|
+
filteredRequests = filteredRequests.filter(req => req.status && filter.statusCodes.includes(req.status));
|
|
72
|
+
}
|
|
73
|
+
if (filter.startTime) {
|
|
74
|
+
filteredRequests = filteredRequests.filter(req => req.timestamp >= filter.startTime);
|
|
75
|
+
}
|
|
76
|
+
if (filter.endTime) {
|
|
77
|
+
filteredRequests = filteredRequests.filter(req => req.timestamp <= filter.endTime);
|
|
78
|
+
}
|
|
79
|
+
if (filter.maxRequests && filter.maxRequests > 0) {
|
|
80
|
+
filteredRequests = filteredRequests.slice(-filter.maxRequests);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return filteredRequests;
|
|
84
|
+
}
|
|
85
|
+
getLatestRequest(filter) {
|
|
86
|
+
const requests = this.getRequests(filter);
|
|
87
|
+
return requests.length > 0 ? requests[requests.length - 1] : null;
|
|
88
|
+
}
|
|
89
|
+
clearRequests() {
|
|
90
|
+
this.requests.clear();
|
|
91
|
+
this.completedRequests = [];
|
|
92
|
+
}
|
|
93
|
+
getRequestCount(filter) {
|
|
94
|
+
return this.getRequests(filter).length;
|
|
95
|
+
}
|
|
96
|
+
isActive() {
|
|
97
|
+
return this.isMonitoring;
|
|
98
|
+
}
|
|
99
|
+
handleRequestWillBeSent(params) {
|
|
100
|
+
try {
|
|
101
|
+
const requestParams = params;
|
|
102
|
+
const networkRequest = {
|
|
103
|
+
requestId: requestParams.requestId,
|
|
104
|
+
url: requestParams.request.url,
|
|
105
|
+
method: requestParams.request.method,
|
|
106
|
+
headers: requestParams.request.headers,
|
|
107
|
+
timestamp: requestParams.wallTime * 1000,
|
|
108
|
+
};
|
|
109
|
+
this.requests.set(requestParams.requestId, networkRequest);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error('Error handling requestWillBeSent:', error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
handleResponseReceived(params) {
|
|
116
|
+
try {
|
|
117
|
+
const responseParams = params;
|
|
118
|
+
const request = this.requests.get(responseParams.requestId);
|
|
119
|
+
if (request) {
|
|
120
|
+
request.status = responseParams.response.status;
|
|
121
|
+
request.responseHeaders = responseParams.response.headers;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error('Error handling responseReceived:', error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
handleLoadingFinished(params) {
|
|
129
|
+
try {
|
|
130
|
+
const loadingParams = params;
|
|
131
|
+
const request = this.requests.get(loadingParams.requestId);
|
|
132
|
+
if (request) {
|
|
133
|
+
this.completedRequests.push(request);
|
|
134
|
+
this.requests.delete(loadingParams.requestId);
|
|
135
|
+
if (this.completedRequests.length > 1000) {
|
|
136
|
+
this.completedRequests = this.completedRequests.slice(-1000);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error('Error handling loadingFinished:', error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
handleLoadingFailed(params) {
|
|
145
|
+
try {
|
|
146
|
+
const failedParams = params;
|
|
147
|
+
const request = this.requests.get(failedParams.requestId);
|
|
148
|
+
if (request) {
|
|
149
|
+
request.status = 0;
|
|
150
|
+
this.completedRequests.push(request);
|
|
151
|
+
this.requests.delete(failedParams.requestId);
|
|
152
|
+
if (this.completedRequests.length > 1000) {
|
|
153
|
+
this.completedRequests = this.completedRequests.slice(-1000);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
console.error('Error handling loadingFailed:', error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.NetworkMonitor = NetworkMonitor;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./ConsoleMonitor"), exports);
|
|
18
|
+
__exportStar(require("./NetworkMonitor"), exports);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-cdp-cli",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Command-line tool for controlling Chrome browser instances via the Chrome DevTools Protocol",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Command-line tool for controlling Chrome browser instances via the Chrome DevTools Protocol. Core features: JavaScript execution, screenshot capture, DOM snapshots, console/network monitoring. Additional features available via eval workarounds.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"license": "MIT",
|
|
52
52
|
"repository": {
|
|
53
53
|
"type": "git",
|
|
54
|
-
"url": "https://github.com/
|
|
54
|
+
"url": "git+https://github.com/nicoster/chrome-devtools-cli.git"
|
|
55
55
|
},
|
|
56
56
|
"bugs": {
|
|
57
|
-
"url": "https://github.com/
|
|
57
|
+
"url": "https://github.com/nicoster/chrome-devtools-cli/issues"
|
|
58
58
|
},
|
|
59
|
-
"homepage": "https://github.com/
|
|
59
|
+
"homepage": "https://github.com/nicoster/chrome-devtools-cli#readme",
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"commander": "^11.1.0",
|
|
62
62
|
"node-fetch": "^2.7.0",
|