chrome-cdp-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +411 -0
- package/dist/cli/CLIApplication.js +92 -0
- package/dist/cli/CLIInterface.js +327 -0
- package/dist/cli/CommandRegistry.js +33 -0
- package/dist/cli/CommandRouter.js +256 -0
- package/dist/cli/index.js +12 -0
- package/dist/client/CDPClient.js +159 -0
- package/dist/client/index.js +17 -0
- package/dist/connection/ConnectionManager.js +164 -0
- package/dist/connection/index.js +5 -0
- package/dist/handlers/EvaluateScriptHandler.js +205 -0
- package/dist/handlers/index.js +17 -0
- package/dist/index.js +44 -0
- package/dist/interfaces/CDPClient.js +2 -0
- package/dist/interfaces/CLIInterface.js +11 -0
- package/dist/interfaces/CommandHandler.js +2 -0
- package/dist/interfaces/ConnectionManager.js +2 -0
- package/dist/interfaces/index.js +20 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/constants.js +31 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/logger.js +44 -0
- package/package.json +81 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CDPClient = void 0;
|
|
7
|
+
const ws_1 = __importDefault(require("ws"));
|
|
8
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
|
+
class CDPClient {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.ws = null;
|
|
12
|
+
this.messageId = 0;
|
|
13
|
+
this.pendingRequests = new Map();
|
|
14
|
+
this.eventListeners = new Map();
|
|
15
|
+
this.connectionStatus = 'disconnected';
|
|
16
|
+
}
|
|
17
|
+
async connect(host, port, targetId) {
|
|
18
|
+
this.connectionStatus = 'connecting';
|
|
19
|
+
try {
|
|
20
|
+
if (!targetId) {
|
|
21
|
+
const targets = await this.discoverTargets(host, port);
|
|
22
|
+
const pageTarget = targets.find(t => t.type === 'page');
|
|
23
|
+
if (!pageTarget) {
|
|
24
|
+
throw new Error('No page targets found');
|
|
25
|
+
}
|
|
26
|
+
targetId = pageTarget.id;
|
|
27
|
+
}
|
|
28
|
+
const wsUrl = await this.getWebSocketUrl(host, port, targetId);
|
|
29
|
+
this.ws = new ws_1.default(wsUrl);
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
if (!this.ws) {
|
|
32
|
+
reject(new Error('WebSocket not initialized'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.ws.on('open', async () => {
|
|
36
|
+
this.connectionStatus = 'connected';
|
|
37
|
+
try {
|
|
38
|
+
await this.send('Runtime.enable');
|
|
39
|
+
resolve();
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('Failed to enable Runtime domain:', error);
|
|
43
|
+
reject(error);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
this.ws.on('message', (data) => {
|
|
47
|
+
this.handleMessage(data.toString());
|
|
48
|
+
});
|
|
49
|
+
this.ws.on('error', (error) => {
|
|
50
|
+
this.connectionStatus = 'error';
|
|
51
|
+
console.error('WebSocket error:', error);
|
|
52
|
+
reject(error);
|
|
53
|
+
});
|
|
54
|
+
this.ws.on('close', () => {
|
|
55
|
+
this.connectionStatus = 'disconnected';
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
this.connectionStatus = 'error';
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async disconnect() {
|
|
65
|
+
if (this.ws) {
|
|
66
|
+
this.ws.close();
|
|
67
|
+
this.ws = null;
|
|
68
|
+
}
|
|
69
|
+
this.connectionStatus = 'disconnected';
|
|
70
|
+
this.pendingRequests.clear();
|
|
71
|
+
}
|
|
72
|
+
async send(method, params) {
|
|
73
|
+
if (!this.ws || this.connectionStatus !== 'connected') {
|
|
74
|
+
throw new Error('Not connected to CDP endpoint');
|
|
75
|
+
}
|
|
76
|
+
const id = ++this.messageId;
|
|
77
|
+
const message = { id, method, params };
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
80
|
+
if (this.ws) {
|
|
81
|
+
this.ws.send(JSON.stringify(message));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
reject(new Error('WebSocket connection lost'));
|
|
85
|
+
}
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
if (this.pendingRequests.has(id)) {
|
|
88
|
+
this.pendingRequests.delete(id);
|
|
89
|
+
reject(new Error(`Request timeout for method: ${method}`));
|
|
90
|
+
}
|
|
91
|
+
}, 30000);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
on(event, callback) {
|
|
95
|
+
if (!this.eventListeners.has(event)) {
|
|
96
|
+
this.eventListeners.set(event, []);
|
|
97
|
+
}
|
|
98
|
+
this.eventListeners.get(event).push(callback);
|
|
99
|
+
}
|
|
100
|
+
off(event, callback) {
|
|
101
|
+
const listeners = this.eventListeners.get(event);
|
|
102
|
+
if (listeners) {
|
|
103
|
+
const index = listeners.indexOf(callback);
|
|
104
|
+
if (index !== -1) {
|
|
105
|
+
listeners.splice(index, 1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
isConnected() {
|
|
110
|
+
return this.connectionStatus === 'connected';
|
|
111
|
+
}
|
|
112
|
+
getConnectionStatus() {
|
|
113
|
+
return this.connectionStatus;
|
|
114
|
+
}
|
|
115
|
+
handleMessage(data) {
|
|
116
|
+
try {
|
|
117
|
+
const message = JSON.parse(data);
|
|
118
|
+
if (message.id !== undefined) {
|
|
119
|
+
const response = message;
|
|
120
|
+
const pending = this.pendingRequests.get(response.id);
|
|
121
|
+
if (pending) {
|
|
122
|
+
this.pendingRequests.delete(response.id);
|
|
123
|
+
if (response.error) {
|
|
124
|
+
pending.reject(new Error(`CDP Error: ${response.error.message}`));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
pending.resolve(response.result);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (message.method) {
|
|
132
|
+
const event = message;
|
|
133
|
+
const listeners = this.eventListeners.get(event.method);
|
|
134
|
+
if (listeners) {
|
|
135
|
+
listeners.forEach(callback => callback(event.params));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
console.error('Error parsing CDP message:', error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async discoverTargets(host, port) {
|
|
144
|
+
const response = await (0, node_fetch_1.default)(`http://${host}:${port}/json/list`);
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
throw new Error(`Failed to discover targets: ${response.statusText}`);
|
|
147
|
+
}
|
|
148
|
+
return (await response.json());
|
|
149
|
+
}
|
|
150
|
+
async getWebSocketUrl(host, port, targetId) {
|
|
151
|
+
const targets = await this.discoverTargets(host, port);
|
|
152
|
+
const target = targets.find(t => t.id === targetId);
|
|
153
|
+
if (!target) {
|
|
154
|
+
throw new Error(`Target not found: ${targetId}`);
|
|
155
|
+
}
|
|
156
|
+
return target.webSocketDebuggerUrl;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.CDPClient = CDPClient;
|
|
@@ -0,0 +1,17 @@
|
|
|
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("./CDPClient"), exports);
|
|
@@ -0,0 +1,164 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ConnectionManager = void 0;
|
|
37
|
+
const logger_1 = require("../utils/logger");
|
|
38
|
+
class ConnectionManager {
|
|
39
|
+
constructor(logger) {
|
|
40
|
+
this.activeConnections = [];
|
|
41
|
+
this.DEFAULT_RETRY_DELAY = 1000;
|
|
42
|
+
this.MAX_RETRY_DELAY = 30000;
|
|
43
|
+
this.RETRY_MULTIPLIER = 2;
|
|
44
|
+
this.logger = logger || new logger_1.Logger();
|
|
45
|
+
}
|
|
46
|
+
async discoverTargets(host, port) {
|
|
47
|
+
const url = `http://${host}:${port}/json/list`;
|
|
48
|
+
try {
|
|
49
|
+
this.logger.debug(`Discovering targets at ${url}`);
|
|
50
|
+
const http = await Promise.resolve().then(() => __importStar(require('http')));
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const request = http.get(url, (response) => {
|
|
53
|
+
let data = '';
|
|
54
|
+
response.on('data', (chunk) => {
|
|
55
|
+
data += chunk;
|
|
56
|
+
});
|
|
57
|
+
response.on('end', () => {
|
|
58
|
+
try {
|
|
59
|
+
if (response.statusCode !== 200) {
|
|
60
|
+
reject(new Error(`HTTP ${response.statusCode}: Failed to discover targets`));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const targets = JSON.parse(data);
|
|
64
|
+
this.logger.debug(`Discovered ${targets.length} targets`);
|
|
65
|
+
const validTargets = targets.filter(target => target.webSocketDebuggerUrl &&
|
|
66
|
+
target.id &&
|
|
67
|
+
target.type);
|
|
68
|
+
resolve(validTargets);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
reject(new Error(`Failed to parse targets response: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
request.on('error', (error) => {
|
|
76
|
+
reject(new Error(`Failed to connect to Chrome DevTools at ${url}: ${error.message}`));
|
|
77
|
+
});
|
|
78
|
+
request.setTimeout(5000, () => {
|
|
79
|
+
request.destroy();
|
|
80
|
+
reject(new Error(`Timeout connecting to Chrome DevTools at ${url}`));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw new Error(`Target discovery failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async connectToTarget(target) {
|
|
89
|
+
try {
|
|
90
|
+
this.logger.debug(`Connecting to target: ${target.id} (${target.title})`);
|
|
91
|
+
const client = await this.createCDPClient(target);
|
|
92
|
+
this.activeConnections.push(client);
|
|
93
|
+
this.logger.info(`Successfully connected to target: ${target.id}`);
|
|
94
|
+
return client;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new Error(`Failed to connect to target ${target.id}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async reconnect(client, maxRetries) {
|
|
101
|
+
let retryCount = 0;
|
|
102
|
+
let delay = this.DEFAULT_RETRY_DELAY;
|
|
103
|
+
while (retryCount < maxRetries) {
|
|
104
|
+
try {
|
|
105
|
+
this.logger.debug(`Reconnection attempt ${retryCount + 1}/${maxRetries}`);
|
|
106
|
+
await this.attemptReconnection(client);
|
|
107
|
+
this.logger.info(`Successfully reconnected after ${retryCount + 1} attempts`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
retryCount++;
|
|
112
|
+
if (retryCount >= maxRetries) {
|
|
113
|
+
throw new Error(`Failed to reconnect after ${maxRetries} attempts: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
114
|
+
}
|
|
115
|
+
this.logger.warn(`Reconnection attempt ${retryCount} failed, retrying in ${delay}ms: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
116
|
+
await this.sleep(delay);
|
|
117
|
+
delay = Math.min(delay * this.RETRY_MULTIPLIER, this.MAX_RETRY_DELAY);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
getActiveConnections() {
|
|
122
|
+
return [...this.activeConnections];
|
|
123
|
+
}
|
|
124
|
+
async closeAllConnections() {
|
|
125
|
+
this.logger.debug(`Closing ${this.activeConnections.length} active connections`);
|
|
126
|
+
const closePromises = this.activeConnections.map(async (client) => {
|
|
127
|
+
try {
|
|
128
|
+
await client.disconnect();
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
this.logger.warn(`Error closing connection: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
await Promise.allSettled(closePromises);
|
|
135
|
+
this.activeConnections = [];
|
|
136
|
+
this.logger.info('All connections closed');
|
|
137
|
+
}
|
|
138
|
+
async createCDPClient(target) {
|
|
139
|
+
const { CDPClient } = await Promise.resolve().then(() => __importStar(require('../client/CDPClient')));
|
|
140
|
+
const client = new CDPClient();
|
|
141
|
+
const wsUrl = target.webSocketDebuggerUrl;
|
|
142
|
+
if (!wsUrl) {
|
|
143
|
+
throw new Error(`Target ${target.id} does not have a WebSocket URL`);
|
|
144
|
+
}
|
|
145
|
+
const urlMatch = wsUrl.match(/ws:\/\/([^:]+):(\d+)/);
|
|
146
|
+
if (!urlMatch) {
|
|
147
|
+
throw new Error(`Invalid WebSocket URL format: ${wsUrl}`);
|
|
148
|
+
}
|
|
149
|
+
const host = urlMatch[1];
|
|
150
|
+
const port = parseInt(urlMatch[2], 10);
|
|
151
|
+
await client.connect(host, port, target.id);
|
|
152
|
+
return client;
|
|
153
|
+
}
|
|
154
|
+
async attemptReconnection(client) {
|
|
155
|
+
if (client.isConnected()) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
throw new Error('Reconnection not yet implemented - depends on CDPClient');
|
|
159
|
+
}
|
|
160
|
+
sleep(ms) {
|
|
161
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.ConnectionManager = ConnectionManager;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectionManager = void 0;
|
|
4
|
+
var ConnectionManager_1 = require("./ConnectionManager");
|
|
5
|
+
Object.defineProperty(exports, "ConnectionManager", { enumerable: true, get: function () { return ConnectionManager_1.ConnectionManager; } });
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EvaluateScriptHandler = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
class EvaluateScriptHandler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'eval';
|
|
8
|
+
}
|
|
9
|
+
async execute(client, args) {
|
|
10
|
+
const scriptArgs = args;
|
|
11
|
+
if (!scriptArgs.expression && !scriptArgs.file) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
error: 'Either "expression" or "file" argument is required'
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (scriptArgs.expression && scriptArgs.file) {
|
|
18
|
+
return {
|
|
19
|
+
success: false,
|
|
20
|
+
error: 'Cannot specify both "expression" and "file" arguments'
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
let expression;
|
|
25
|
+
if (scriptArgs.file) {
|
|
26
|
+
expression = await this.readScriptFile(scriptArgs.file);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
expression = scriptArgs.expression;
|
|
30
|
+
}
|
|
31
|
+
const result = await this.executeWithTimeout(client, expression, scriptArgs);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
error: error instanceof Error ? error.message : String(error)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async readScriptFile(filePath) {
|
|
42
|
+
try {
|
|
43
|
+
const content = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
44
|
+
return content;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
throw new Error(`Failed to read script file "${filePath}": ${error instanceof Error ? error.message : String(error)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async executeWithTimeout(client, expression, args) {
|
|
51
|
+
const timeout = args.timeout || 30000;
|
|
52
|
+
const awaitPromise = args.awaitPromise ?? true;
|
|
53
|
+
const returnByValue = args.returnByValue ?? true;
|
|
54
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
reject(new Error(`Script execution timeout after ${timeout}ms`));
|
|
57
|
+
}, timeout);
|
|
58
|
+
});
|
|
59
|
+
const executionPromise = this.executeScript(client, expression, awaitPromise, returnByValue);
|
|
60
|
+
try {
|
|
61
|
+
const result = await Promise.race([executionPromise, timeoutPromise]);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: error instanceof Error ? error.message : String(error)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async executeScript(client, expression, awaitPromise, returnByValue) {
|
|
72
|
+
try {
|
|
73
|
+
const response = (await client.send('Runtime.evaluate', {
|
|
74
|
+
expression,
|
|
75
|
+
awaitPromise,
|
|
76
|
+
returnByValue,
|
|
77
|
+
userGesture: true,
|
|
78
|
+
generatePreview: false
|
|
79
|
+
}));
|
|
80
|
+
if (!response) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: 'CDP returned empty response'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (response.exceptionDetails) {
|
|
87
|
+
return this.formatException(response.exceptionDetails);
|
|
88
|
+
}
|
|
89
|
+
if (!response.result) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: 'CDP response missing result field'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
data: this.formatResult(response.result)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: `CDP command failed: ${error instanceof Error ? error.message : String(error)}`
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
formatException(exceptionDetails) {
|
|
108
|
+
if (!exceptionDetails) {
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
error: 'Unknown JavaScript error'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const exception = exceptionDetails.exception;
|
|
115
|
+
const errorMessage = exception?.description || exceptionDetails.text;
|
|
116
|
+
let stackTrace = '';
|
|
117
|
+
if (exceptionDetails.stackTrace?.callFrames) {
|
|
118
|
+
stackTrace = '\nStack trace:\n' +
|
|
119
|
+
exceptionDetails.stackTrace.callFrames
|
|
120
|
+
.map(frame => ` at ${frame.functionName || '<anonymous>'} (${frame.url}:${frame.lineNumber}:${frame.columnNumber})`)
|
|
121
|
+
.join('\n');
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
error: `JavaScript error at line ${exceptionDetails.lineNumber}, column ${exceptionDetails.columnNumber}: ${errorMessage}${stackTrace}`
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
formatResult(result) {
|
|
129
|
+
if (!result) {
|
|
130
|
+
return 'undefined';
|
|
131
|
+
}
|
|
132
|
+
if (result.value !== undefined) {
|
|
133
|
+
return result.value;
|
|
134
|
+
}
|
|
135
|
+
if (result.objectId) {
|
|
136
|
+
return {
|
|
137
|
+
type: result.type,
|
|
138
|
+
description: result.description,
|
|
139
|
+
objectId: result.objectId
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return result.description || result.type;
|
|
143
|
+
}
|
|
144
|
+
validateArgs(args) {
|
|
145
|
+
if (typeof args !== 'object' || args === null) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const scriptArgs = args;
|
|
149
|
+
if (!scriptArgs.expression && !scriptArgs.file) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
if (scriptArgs.expression && scriptArgs.file) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (scriptArgs.expression && typeof scriptArgs.expression !== 'string') {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
if (scriptArgs.file && typeof scriptArgs.file !== 'string') {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
if (scriptArgs.awaitPromise !== undefined && typeof scriptArgs.awaitPromise !== 'boolean') {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (scriptArgs.timeout !== undefined && typeof scriptArgs.timeout !== 'number') {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
getHelp() {
|
|
170
|
+
return `
|
|
171
|
+
eval - Execute JavaScript code in the browser context
|
|
172
|
+
|
|
173
|
+
Usage:
|
|
174
|
+
eval "console.log('Hello')"
|
|
175
|
+
eval --file script.js
|
|
176
|
+
eval "fetch('/api')" --await-promise
|
|
177
|
+
eval "longRunning()" --timeout 60000
|
|
178
|
+
|
|
179
|
+
Arguments:
|
|
180
|
+
<expression> JavaScript code to execute (direct argument)
|
|
181
|
+
--expression <code> JavaScript code to execute (explicit flag)
|
|
182
|
+
--file <path> Path to JavaScript file to execute
|
|
183
|
+
--await-promise Wait for Promise resolution (default: true)
|
|
184
|
+
--timeout <ms> Execution timeout in milliseconds (default: 30000)
|
|
185
|
+
--return-by-value Return result by value (default: true)
|
|
186
|
+
|
|
187
|
+
Examples:
|
|
188
|
+
# Execute simple expression (recommended)
|
|
189
|
+
eval "2 + 2"
|
|
190
|
+
|
|
191
|
+
# Execute with explicit flag
|
|
192
|
+
eval --expression "2 + 2"
|
|
193
|
+
|
|
194
|
+
# Execute async code
|
|
195
|
+
eval "await fetch('/api').then(r => r.json())"
|
|
196
|
+
|
|
197
|
+
# Execute from file
|
|
198
|
+
eval --file ./scripts/init.js
|
|
199
|
+
|
|
200
|
+
# Set custom timeout
|
|
201
|
+
eval "heavyComputation()" --timeout 120000
|
|
202
|
+
`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.EvaluateScriptHandler = EvaluateScriptHandler;
|
|
@@ -0,0 +1,17 @@
|
|
|
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("./EvaluateScriptHandler"), exports);
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const CLIApplication_1 = require("./cli/CLIApplication");
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
20
|
+
__exportStar(require("./interfaces"), exports);
|
|
21
|
+
__exportStar(require("./utils"), exports);
|
|
22
|
+
__exportStar(require("./connection"), exports);
|
|
23
|
+
__exportStar(require("./handlers"), exports);
|
|
24
|
+
__exportStar(require("./cli"), exports);
|
|
25
|
+
async function main() {
|
|
26
|
+
const app = new CLIApplication_1.CLIApplication();
|
|
27
|
+
process.on('SIGINT', async () => {
|
|
28
|
+
console.log('\nShutting down...');
|
|
29
|
+
await app.shutdown();
|
|
30
|
+
process.exit(0);
|
|
31
|
+
});
|
|
32
|
+
process.on('SIGTERM', async () => {
|
|
33
|
+
await app.shutdown();
|
|
34
|
+
process.exit(0);
|
|
35
|
+
});
|
|
36
|
+
const exitCode = await app.run(process.argv);
|
|
37
|
+
process.exit(exitCode);
|
|
38
|
+
}
|
|
39
|
+
if (require.main === module) {
|
|
40
|
+
main().catch((error) => {
|
|
41
|
+
console.error('Fatal error:', error);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_CLI_CONFIG = void 0;
|
|
4
|
+
exports.DEFAULT_CLI_CONFIG = {
|
|
5
|
+
host: 'localhost',
|
|
6
|
+
port: 9222,
|
|
7
|
+
outputFormat: 'text',
|
|
8
|
+
verbose: false,
|
|
9
|
+
quiet: false,
|
|
10
|
+
timeout: 30000
|
|
11
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
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("./CLIInterface"), exports);
|
|
18
|
+
__exportStar(require("./CDPClient"), exports);
|
|
19
|
+
__exportStar(require("./ConnectionManager"), exports);
|
|
20
|
+
__exportStar(require("./CommandHandler"), exports);
|