@canaryai/cli 0.2.1 → 0.2.3
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/dist/{chunk-TO66FC4R.js → chunk-JMI7WWPF.js} +2 -2
- package/dist/chunk-OE6O7H45.js +92 -0
- package/dist/chunk-OE6O7H45.js.map +1 -0
- package/dist/chunk-PLDDJCW6.js +49 -0
- package/dist/chunk-ZTWHPIXU.js +42798 -0
- package/dist/chunk-ZTWHPIXU.js.map +1 -0
- package/dist/debug-workflow-PMLMWKWI.js +241 -0
- package/dist/debug-workflow-PMLMWKWI.js.map +1 -0
- package/dist/dist-6NXLJYRZ.js +335 -0
- package/dist/dist-6NXLJYRZ.js.map +1 -0
- package/dist/{feature-flag-ZDLDYRSF.js → feature-flag-D3QTHGL6.js} +2 -2
- package/dist/index.js +41 -9
- package/dist/index.js.map +1 -1
- package/dist/issues-6MHRFKTU.js +362 -0
- package/dist/issues-6MHRFKTU.js.map +1 -0
- package/dist/{knobs-3MKMOXIV.js → knobs-ED6LXBVM.js} +2 -2
- package/dist/{local-browser-GG5GUXDS.js → local-browser-YSE3XCUW.js} +4 -3
- package/dist/{local-browser-GG5GUXDS.js.map → local-browser-YSE3XCUW.js.map} +1 -1
- package/dist/{mcp-AD67OLQM.js → mcp-LKHFYMA6.js} +4 -3
- package/dist/{mcp-AD67OLQM.js.map → mcp-LKHFYMA6.js.map} +1 -1
- package/dist/pdf-extract-YIDRKYUD.js +12 -0
- package/dist/pdf-extract-YIDRKYUD.js.map +1 -0
- package/dist/pdfjs-44AOKLEM.js +35242 -0
- package/dist/pdfjs-44AOKLEM.js.map +1 -0
- package/dist/{psql-IVAPNYZV.js → psql-U5LF6ELS.js} +2 -2
- package/dist/{redis-LWY7L6AS.js → redis-PBQZGU6T.js} +2 -2
- package/dist/{release-KQFCTAXA.js → release-QBSP474D.js} +2 -2
- package/dist/runner/preload.js +2 -2
- package/dist/test.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-UEOXNF5X.js +0 -371
- package/dist/chunk-UEOXNF5X.js.map +0 -1
- /package/dist/{chunk-TO66FC4R.js.map → chunk-JMI7WWPF.js.map} +0 -0
- /package/dist/{chunk-DGUM43GV.js.map → chunk-PLDDJCW6.js.map} +0 -0
- /package/dist/{feature-flag-ZDLDYRSF.js.map → feature-flag-D3QTHGL6.js.map} +0 -0
- /package/dist/{knobs-3MKMOXIV.js.map → knobs-ED6LXBVM.js.map} +0 -0
- /package/dist/{psql-IVAPNYZV.js.map → psql-U5LF6ELS.js.map} +0 -0
- /package/dist/{redis-LWY7L6AS.js.map → redis-PBQZGU6T.js.map} +0 -0
- /package/dist/{release-KQFCTAXA.js.map → release-QBSP474D.js.map} +0 -0
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
readStoredApiUrl,
|
|
3
3
|
readStoredToken
|
|
4
4
|
} from "./chunk-7R4YFGP6.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-PLDDJCW6.js";
|
|
6
6
|
|
|
7
7
|
// src/psql.ts
|
|
8
8
|
import process from "process";
|
|
@@ -121,4 +121,4 @@ Time: ${json.durationMs}ms`);
|
|
|
121
121
|
export {
|
|
122
122
|
runPsql
|
|
123
123
|
};
|
|
124
|
-
//# sourceMappingURL=psql-
|
|
124
|
+
//# sourceMappingURL=psql-U5LF6ELS.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
readStoredApiUrl,
|
|
3
3
|
readStoredToken
|
|
4
4
|
} from "./chunk-7R4YFGP6.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-PLDDJCW6.js";
|
|
6
6
|
|
|
7
7
|
// src/redis.ts
|
|
8
8
|
import process from "process";
|
|
@@ -127,4 +127,4 @@ Time: ${json_response.durationMs}ms`);
|
|
|
127
127
|
export {
|
|
128
128
|
runRedis
|
|
129
129
|
};
|
|
130
|
-
//# sourceMappingURL=redis-
|
|
130
|
+
//# sourceMappingURL=redis-PBQZGU6T.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
hasFlag,
|
|
4
4
|
resolveConfig
|
|
5
5
|
} from "./chunk-7R4YFGP6.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-PLDDJCW6.js";
|
|
7
7
|
|
|
8
8
|
// src/release.ts
|
|
9
9
|
import process from "process";
|
|
@@ -216,4 +216,4 @@ async function runRelease(argv) {
|
|
|
216
216
|
export {
|
|
217
217
|
runRelease
|
|
218
218
|
};
|
|
219
|
-
//# sourceMappingURL=release-
|
|
219
|
+
//# sourceMappingURL=release-QBSP474D.js.map
|
package/dist/runner/preload.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
setEventLogPath,
|
|
8
8
|
wrapExpect,
|
|
9
9
|
wrapPage
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-JMI7WWPF.js";
|
|
11
11
|
import {
|
|
12
12
|
__require
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-PLDDJCW6.js";
|
|
14
14
|
|
|
15
15
|
// src/runner/instrumentation.ts
|
|
16
16
|
import Module from "module";
|
package/dist/test.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canaryai/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"ai": "^5.0.60",
|
|
46
46
|
"dotenv": "^17.2.3",
|
|
47
47
|
"eventsource-parser": "^3.0.0",
|
|
48
|
-
"@chatsdet/browser-core": "workspace:*",
|
|
49
48
|
"zod": "^4.1.12"
|
|
50
49
|
},
|
|
51
50
|
"devDependencies": {
|
|
51
|
+
"@chatsdet/browser-core": "workspace:*",
|
|
52
52
|
"@playwright/test": "1.57.0-alpha-2025-10-16",
|
|
53
53
|
"@types/node": "^20.12.12",
|
|
54
54
|
"playwright": "1.57.0-alpha-2025-10-16",
|
package/dist/chunk-DGUM43GV.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
__require
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=chunk-DGUM43GV.js.map
|
package/dist/chunk-UEOXNF5X.js
DELETED
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
// src/local-browser/host.ts
|
|
2
|
-
import {
|
|
3
|
-
PlaywrightClient
|
|
4
|
-
} from "@chatsdet/browser-core";
|
|
5
|
-
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
6
|
-
var RECONNECT_DELAY_MS = 1e3;
|
|
7
|
-
var MAX_RECONNECT_DELAY_MS = 3e4;
|
|
8
|
-
var MAX_RECONNECT_ATTEMPTS = 10;
|
|
9
|
-
var LocalBrowserHost = class {
|
|
10
|
-
options;
|
|
11
|
-
ws = null;
|
|
12
|
-
client;
|
|
13
|
-
heartbeatTimer = null;
|
|
14
|
-
reconnectAttempts = 0;
|
|
15
|
-
isShuttingDown = false;
|
|
16
|
-
constructor(options) {
|
|
17
|
-
this.options = options;
|
|
18
|
-
const logger = {
|
|
19
|
-
debug: (msg, data) => this.log("debug", msg, data),
|
|
20
|
-
info: (msg, data) => this.log("info", msg, data),
|
|
21
|
-
warn: (msg, data) => this.log("warn", msg, data),
|
|
22
|
-
error: (msg, data) => this.log("error", msg, data)
|
|
23
|
-
};
|
|
24
|
-
this.client = new PlaywrightClient({ logger });
|
|
25
|
-
}
|
|
26
|
-
log(level, message, data) {
|
|
27
|
-
if (this.options.onLog) {
|
|
28
|
-
this.options.onLog(level, message, data);
|
|
29
|
-
} else {
|
|
30
|
-
const fn = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
31
|
-
fn(`[LocalBrowserHost] ${message}`, data ?? "");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
// =========================================================================
|
|
35
|
-
// Lifecycle
|
|
36
|
-
// =========================================================================
|
|
37
|
-
async start() {
|
|
38
|
-
this.log("info", "Starting local browser host", {
|
|
39
|
-
browserMode: this.options.browserMode,
|
|
40
|
-
sessionId: this.options.sessionId
|
|
41
|
-
});
|
|
42
|
-
await this.connectWebSocket();
|
|
43
|
-
const { browserMode, cdpUrl, headless = true, storageStatePath } = this.options;
|
|
44
|
-
await this.client.connect({
|
|
45
|
-
browserMode: headless ? "headless" : "headed",
|
|
46
|
-
cdpUrl: browserMode === "cdp" ? cdpUrl : void 0,
|
|
47
|
-
storageStatePath
|
|
48
|
-
});
|
|
49
|
-
this.sendSessionEvent("browser_ready");
|
|
50
|
-
}
|
|
51
|
-
async stop() {
|
|
52
|
-
this.isShuttingDown = true;
|
|
53
|
-
this.log("info", "Stopping local browser host");
|
|
54
|
-
this.stopHeartbeat();
|
|
55
|
-
if (this.ws) {
|
|
56
|
-
try {
|
|
57
|
-
this.ws.close(1e3, "Shutdown");
|
|
58
|
-
} catch {
|
|
59
|
-
}
|
|
60
|
-
this.ws = null;
|
|
61
|
-
}
|
|
62
|
-
await this.client.disconnect();
|
|
63
|
-
this.log("info", "Local browser host stopped");
|
|
64
|
-
}
|
|
65
|
-
// =========================================================================
|
|
66
|
-
// WebSocket Connection
|
|
67
|
-
// =========================================================================
|
|
68
|
-
async connectWebSocket() {
|
|
69
|
-
return new Promise((resolve, reject) => {
|
|
70
|
-
const wsUrl = `${this.options.apiUrl.replace("http", "ws")}/local-browser/sessions/${this.options.sessionId}/connect?token=${this.options.wsToken}`;
|
|
71
|
-
this.log("info", "Connecting to cloud API", { url: wsUrl.replace(/token=.*/, "token=***") });
|
|
72
|
-
const ws = new WebSocket(wsUrl);
|
|
73
|
-
ws.onopen = () => {
|
|
74
|
-
this.log("info", "Connected to cloud API");
|
|
75
|
-
this.ws = ws;
|
|
76
|
-
this.reconnectAttempts = 0;
|
|
77
|
-
this.startHeartbeat();
|
|
78
|
-
resolve();
|
|
79
|
-
};
|
|
80
|
-
ws.onmessage = (event) => {
|
|
81
|
-
this.handleMessage(event.data);
|
|
82
|
-
};
|
|
83
|
-
ws.onerror = (event) => {
|
|
84
|
-
this.log("error", "WebSocket error", event);
|
|
85
|
-
};
|
|
86
|
-
ws.onclose = () => {
|
|
87
|
-
this.log("info", "WebSocket closed");
|
|
88
|
-
this.stopHeartbeat();
|
|
89
|
-
this.ws = null;
|
|
90
|
-
if (!this.isShuttingDown) {
|
|
91
|
-
this.scheduleReconnect();
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
setTimeout(() => {
|
|
95
|
-
if (!this.ws) {
|
|
96
|
-
reject(new Error("WebSocket connection timeout"));
|
|
97
|
-
}
|
|
98
|
-
}, 3e4);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
scheduleReconnect() {
|
|
102
|
-
if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
103
|
-
this.log("error", "Max reconnection attempts reached, giving up");
|
|
104
|
-
this.stop();
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const delay = Math.min(
|
|
108
|
-
RECONNECT_DELAY_MS * Math.pow(2, this.reconnectAttempts),
|
|
109
|
-
MAX_RECONNECT_DELAY_MS
|
|
110
|
-
);
|
|
111
|
-
this.reconnectAttempts++;
|
|
112
|
-
this.log("info", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
113
|
-
setTimeout(async () => {
|
|
114
|
-
try {
|
|
115
|
-
await this.connectWebSocket();
|
|
116
|
-
this.sendSessionEvent("connected");
|
|
117
|
-
this.sendSessionEvent("browser_ready");
|
|
118
|
-
} catch (error) {
|
|
119
|
-
this.log("error", "Reconnection failed", error);
|
|
120
|
-
this.scheduleReconnect();
|
|
121
|
-
}
|
|
122
|
-
}, delay);
|
|
123
|
-
}
|
|
124
|
-
// =========================================================================
|
|
125
|
-
// Heartbeat
|
|
126
|
-
// =========================================================================
|
|
127
|
-
startHeartbeat() {
|
|
128
|
-
this.stopHeartbeat();
|
|
129
|
-
this.heartbeatTimer = setInterval(() => {
|
|
130
|
-
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
131
|
-
const ping = {
|
|
132
|
-
type: "heartbeat",
|
|
133
|
-
id: crypto.randomUUID(),
|
|
134
|
-
timestamp: Date.now(),
|
|
135
|
-
direction: "pong"
|
|
136
|
-
};
|
|
137
|
-
this.ws.send(JSON.stringify(ping));
|
|
138
|
-
}
|
|
139
|
-
}, HEARTBEAT_INTERVAL_MS);
|
|
140
|
-
}
|
|
141
|
-
stopHeartbeat() {
|
|
142
|
-
if (this.heartbeatTimer) {
|
|
143
|
-
clearInterval(this.heartbeatTimer);
|
|
144
|
-
this.heartbeatTimer = null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
// =========================================================================
|
|
148
|
-
// Message Handling
|
|
149
|
-
// =========================================================================
|
|
150
|
-
handleMessage(data) {
|
|
151
|
-
try {
|
|
152
|
-
const message = JSON.parse(data);
|
|
153
|
-
if (message.type === "heartbeat" && message.direction === "ping") {
|
|
154
|
-
const pong = {
|
|
155
|
-
type: "heartbeat",
|
|
156
|
-
id: crypto.randomUUID(),
|
|
157
|
-
timestamp: Date.now(),
|
|
158
|
-
direction: "pong"
|
|
159
|
-
};
|
|
160
|
-
this.ws?.send(JSON.stringify(pong));
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
if (message.type === "command") {
|
|
164
|
-
this.handleCommand(message);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
this.log("debug", "Received unknown message type", message);
|
|
168
|
-
} catch (error) {
|
|
169
|
-
this.log("error", "Failed to parse message", { error, data });
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
async handleCommand(command) {
|
|
173
|
-
const startTime = Date.now();
|
|
174
|
-
this.log("debug", `Executing command: ${command.method}`, { id: command.id });
|
|
175
|
-
try {
|
|
176
|
-
const result = await this.executeMethod(command.method, command.args);
|
|
177
|
-
const response = {
|
|
178
|
-
type: "response",
|
|
179
|
-
id: crypto.randomUUID(),
|
|
180
|
-
timestamp: Date.now(),
|
|
181
|
-
requestId: command.id,
|
|
182
|
-
success: true,
|
|
183
|
-
result,
|
|
184
|
-
contextId: command.contextId
|
|
185
|
-
};
|
|
186
|
-
this.ws?.send(JSON.stringify(response));
|
|
187
|
-
this.log("debug", `Command completed: ${command.method}`, {
|
|
188
|
-
id: command.id,
|
|
189
|
-
durationMs: Date.now() - startTime
|
|
190
|
-
});
|
|
191
|
-
} catch (error) {
|
|
192
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
193
|
-
const response = {
|
|
194
|
-
type: "response",
|
|
195
|
-
id: crypto.randomUUID(),
|
|
196
|
-
timestamp: Date.now(),
|
|
197
|
-
requestId: command.id,
|
|
198
|
-
success: false,
|
|
199
|
-
error: errorMessage,
|
|
200
|
-
stack: error instanceof Error ? error.stack : void 0,
|
|
201
|
-
contextId: command.contextId
|
|
202
|
-
};
|
|
203
|
-
this.ws?.send(JSON.stringify(response));
|
|
204
|
-
this.log("error", `Command failed: ${command.method}`, {
|
|
205
|
-
id: command.id,
|
|
206
|
-
error: errorMessage
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
sendSessionEvent(event, error) {
|
|
211
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
|
212
|
-
const message = {
|
|
213
|
-
type: "session",
|
|
214
|
-
id: crypto.randomUUID(),
|
|
215
|
-
timestamp: Date.now(),
|
|
216
|
-
event,
|
|
217
|
-
browserMode: this.options.browserMode,
|
|
218
|
-
error
|
|
219
|
-
};
|
|
220
|
-
this.ws.send(JSON.stringify(message));
|
|
221
|
-
}
|
|
222
|
-
// =========================================================================
|
|
223
|
-
// Method Execution — Delegate to PlaywrightClient
|
|
224
|
-
// =========================================================================
|
|
225
|
-
/**
|
|
226
|
-
* Maps incoming WebSocket command method names to PlaywrightClient methods.
|
|
227
|
-
* The client implements IBrowserClient, so all standard browser operations
|
|
228
|
-
* are available and behave identically to the cloud environment.
|
|
229
|
-
*/
|
|
230
|
-
async executeMethod(method, args) {
|
|
231
|
-
const client = this.client;
|
|
232
|
-
switch (method) {
|
|
233
|
-
// Lifecycle
|
|
234
|
-
case "connect":
|
|
235
|
-
return client.connect(args[0]);
|
|
236
|
-
case "disconnect":
|
|
237
|
-
return client.disconnect();
|
|
238
|
-
// Navigation
|
|
239
|
-
case "navigate":
|
|
240
|
-
return client.navigate(args[0], args[1]);
|
|
241
|
-
case "navigateBack":
|
|
242
|
-
return client.navigateBack(args[0]);
|
|
243
|
-
// Page Inspection
|
|
244
|
-
case "snapshot":
|
|
245
|
-
return client.snapshot(args[0]);
|
|
246
|
-
case "takeScreenshot":
|
|
247
|
-
return client.takeScreenshot(args[0]);
|
|
248
|
-
case "evaluate":
|
|
249
|
-
return client.evaluate(args[0], args[1]);
|
|
250
|
-
case "runCode":
|
|
251
|
-
return client.runCode(args[0], args[1]);
|
|
252
|
-
case "consoleMessages":
|
|
253
|
-
return client.consoleMessages(args[0]);
|
|
254
|
-
case "networkRequests":
|
|
255
|
-
return client.networkRequests(args[0]);
|
|
256
|
-
// Interaction
|
|
257
|
-
case "click":
|
|
258
|
-
return client.click(args[0], args[1], args[2]);
|
|
259
|
-
case "clickAtCoordinates":
|
|
260
|
-
return client.clickAtCoordinates(
|
|
261
|
-
args[0],
|
|
262
|
-
args[1],
|
|
263
|
-
args[2],
|
|
264
|
-
args[3]
|
|
265
|
-
);
|
|
266
|
-
case "moveToCoordinates":
|
|
267
|
-
return client.moveToCoordinates(
|
|
268
|
-
args[0],
|
|
269
|
-
args[1],
|
|
270
|
-
args[2],
|
|
271
|
-
args[3]
|
|
272
|
-
);
|
|
273
|
-
case "dragCoordinates":
|
|
274
|
-
return client.dragCoordinates(
|
|
275
|
-
args[0],
|
|
276
|
-
args[1],
|
|
277
|
-
args[2],
|
|
278
|
-
args[3],
|
|
279
|
-
args[4],
|
|
280
|
-
args[5]
|
|
281
|
-
);
|
|
282
|
-
case "hover":
|
|
283
|
-
return client.hover(args[0], args[1], args[2]);
|
|
284
|
-
case "drag":
|
|
285
|
-
return client.drag(
|
|
286
|
-
args[0],
|
|
287
|
-
args[1],
|
|
288
|
-
args[2],
|
|
289
|
-
args[3],
|
|
290
|
-
args[4]
|
|
291
|
-
);
|
|
292
|
-
case "type":
|
|
293
|
-
return client.type(
|
|
294
|
-
args[0],
|
|
295
|
-
args[1],
|
|
296
|
-
args[2],
|
|
297
|
-
args[3],
|
|
298
|
-
args[4]
|
|
299
|
-
);
|
|
300
|
-
case "pressKey":
|
|
301
|
-
return client.pressKey(args[0], args[1]);
|
|
302
|
-
case "fillForm":
|
|
303
|
-
return client.fillForm(args[0], args[1]);
|
|
304
|
-
case "selectOption":
|
|
305
|
-
return client.selectOption(
|
|
306
|
-
args[0],
|
|
307
|
-
args[1],
|
|
308
|
-
args[2],
|
|
309
|
-
args[3]
|
|
310
|
-
);
|
|
311
|
-
case "fileUpload":
|
|
312
|
-
return client.fileUpload(args[0], args[1]);
|
|
313
|
-
// Scroll
|
|
314
|
-
case "scroll":
|
|
315
|
-
return client.scroll(args[0], args[1], args[2], args[3], args[4]);
|
|
316
|
-
// Dialogs
|
|
317
|
-
case "handleDialog":
|
|
318
|
-
return client.handleDialog(args[0], args[1], args[2]);
|
|
319
|
-
// Waiting
|
|
320
|
-
case "waitFor":
|
|
321
|
-
return client.waitFor(args[0]);
|
|
322
|
-
// Browser Management
|
|
323
|
-
case "close":
|
|
324
|
-
return client.close(args[0]);
|
|
325
|
-
case "resize":
|
|
326
|
-
return client.resize(args[0], args[1], args[2]);
|
|
327
|
-
case "tabs":
|
|
328
|
-
return client.tabs(args[0], args[1], args[2]);
|
|
329
|
-
// Context Management
|
|
330
|
-
case "swapContext":
|
|
331
|
-
return client.swapContext?.(args[0]);
|
|
332
|
-
// Storage & Page Info
|
|
333
|
-
case "getStorageState":
|
|
334
|
-
return client.getStorageState(args[0]);
|
|
335
|
-
case "getCurrentUrl":
|
|
336
|
-
return client.getCurrentUrl(args[0]);
|
|
337
|
-
case "getTitle":
|
|
338
|
-
return client.getTitle(args[0]);
|
|
339
|
-
case "getLinks":
|
|
340
|
-
return client.getLinks(args[0]);
|
|
341
|
-
case "getElementBoundingBox":
|
|
342
|
-
return client.getElementBoundingBox(args[0], args[1]);
|
|
343
|
-
// Tracing
|
|
344
|
-
case "startTracing":
|
|
345
|
-
return client.startTracing?.(args[0]);
|
|
346
|
-
case "stopTracing":
|
|
347
|
-
return client.stopTracing?.(args[0]);
|
|
348
|
-
// Video
|
|
349
|
-
case "isVideoRecordingEnabled":
|
|
350
|
-
return client.isVideoRecordingEnabled?.() ?? false;
|
|
351
|
-
case "saveVideo":
|
|
352
|
-
return client.saveVideo?.() ?? null;
|
|
353
|
-
case "getVideoPath":
|
|
354
|
-
return null;
|
|
355
|
-
// Screencast
|
|
356
|
-
case "startScreencast":
|
|
357
|
-
return client.startScreencast?.(args[0], args[1]);
|
|
358
|
-
case "stopScreencast":
|
|
359
|
-
return client.stopScreencast?.();
|
|
360
|
-
case "isScreencastActive":
|
|
361
|
-
return client.isScreencastActive?.() ?? false;
|
|
362
|
-
default:
|
|
363
|
-
throw new Error(`Unknown method: ${method}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
export {
|
|
369
|
-
LocalBrowserHost
|
|
370
|
-
};
|
|
371
|
-
//# sourceMappingURL=chunk-UEOXNF5X.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/local-browser/host.ts"],"sourcesContent":["/**\n * Local Browser Host\n *\n * Manages a local browser instance and handles commands from the cloud API\n * via WebSocket. Delegates all browser automation to PlaywrightClient from\n * @chatsdet/browser-core, ensuring the agent experience is identical\n * regardless of whether the browser is local or cloud.\n *\n * @module local-browser-host\n */\n\nimport {\n PlaywrightClient,\n type IBrowserClient,\n type BrowserLogger,\n} from \"@chatsdet/browser-core\";\nimport type {\n BrowserCommand,\n BrowserResponse,\n HeartbeatMessage,\n SessionMessage,\n LocalBrowserMode,\n} from \"./protocol\";\n\nconst HEARTBEAT_INTERVAL_MS = 30_000;\nconst RECONNECT_DELAY_MS = 1000;\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst MAX_RECONNECT_ATTEMPTS = 10;\n\nexport interface LocalBrowserHostOptions {\n apiUrl: string;\n wsToken: string;\n sessionId: string;\n browserMode: LocalBrowserMode;\n cdpUrl?: string;\n headless?: boolean;\n storageStatePath?: string;\n onLog?: (level: \"info\" | \"warn\" | \"error\" | \"debug\", message: string, data?: unknown) => void;\n}\n\n/**\n * LocalBrowserHost manages the WebSocket connection to the cloud API and\n * delegates all browser operations to a shared PlaywrightClient instance.\n */\nexport class LocalBrowserHost {\n private options: LocalBrowserHostOptions;\n private ws: WebSocket | null = null;\n private client: PlaywrightClient;\n private heartbeatTimer: NodeJS.Timeout | null = null;\n private reconnectAttempts = 0;\n private isShuttingDown = false;\n\n constructor(options: LocalBrowserHostOptions) {\n this.options = options;\n const logger: BrowserLogger = {\n debug: (msg: string, data?: Record<string, unknown>) => this.log(\"debug\", msg, data),\n info: (msg: string, data?: Record<string, unknown>) => this.log(\"info\", msg, data),\n warn: (msg: string, data?: Record<string, unknown>) => this.log(\"warn\", msg, data),\n error: (msg: string, data?: Record<string, unknown>) => this.log(\"error\", msg, data),\n };\n this.client = new PlaywrightClient({ logger });\n }\n\n private log(level: \"info\" | \"warn\" | \"error\" | \"debug\", message: string, data?: unknown) {\n if (this.options.onLog) {\n this.options.onLog(level, message, data);\n } else {\n const fn = level === \"error\" ? console.error : level === \"warn\" ? console.warn : console.log;\n fn(`[LocalBrowserHost] ${message}`, data ?? \"\");\n }\n }\n\n // =========================================================================\n // Lifecycle\n // =========================================================================\n\n async start(): Promise<void> {\n this.log(\"info\", \"Starting local browser host\", {\n browserMode: this.options.browserMode,\n sessionId: this.options.sessionId,\n });\n\n // Connect to WebSocket first\n await this.connectWebSocket();\n\n // Launch browser via PlaywrightClient\n const { browserMode, cdpUrl, headless = true, storageStatePath } = this.options;\n await this.client.connect({\n browserMode: headless ? \"headless\" : \"headed\",\n cdpUrl: browserMode === \"cdp\" ? cdpUrl : undefined,\n storageStatePath,\n });\n\n // Notify cloud that browser is ready\n this.sendSessionEvent(\"browser_ready\");\n }\n\n async stop(): Promise<void> {\n this.isShuttingDown = true;\n this.log(\"info\", \"Stopping local browser host\");\n\n this.stopHeartbeat();\n\n if (this.ws) {\n try {\n this.ws.close(1000, \"Shutdown\");\n } catch {}\n this.ws = null;\n }\n\n await this.client.disconnect();\n this.log(\"info\", \"Local browser host stopped\");\n }\n\n // =========================================================================\n // WebSocket Connection\n // =========================================================================\n\n private async connectWebSocket(): Promise<void> {\n return new Promise((resolve, reject) => {\n const wsUrl = `${this.options.apiUrl.replace(\"http\", \"ws\")}/local-browser/sessions/${this.options.sessionId}/connect?token=${this.options.wsToken}`;\n\n this.log(\"info\", \"Connecting to cloud API\", { url: wsUrl.replace(/token=.*/, \"token=***\") });\n\n const ws = new WebSocket(wsUrl);\n\n ws.onopen = () => {\n this.log(\"info\", \"Connected to cloud API\");\n this.ws = ws;\n this.reconnectAttempts = 0;\n this.startHeartbeat();\n resolve();\n };\n\n ws.onmessage = (event) => {\n this.handleMessage(event.data as string);\n };\n\n ws.onerror = (event) => {\n this.log(\"error\", \"WebSocket error\", event);\n };\n\n ws.onclose = () => {\n this.log(\"info\", \"WebSocket closed\");\n this.stopHeartbeat();\n this.ws = null;\n\n if (!this.isShuttingDown) {\n this.scheduleReconnect();\n }\n };\n\n // Timeout after 30 seconds\n setTimeout(() => {\n if (!this.ws) {\n reject(new Error(\"WebSocket connection timeout\"));\n }\n }, 30_000);\n });\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n this.log(\"error\", \"Max reconnection attempts reached, giving up\");\n this.stop();\n return;\n }\n\n const delay = Math.min(\n RECONNECT_DELAY_MS * Math.pow(2, this.reconnectAttempts),\n MAX_RECONNECT_DELAY_MS\n );\n\n this.reconnectAttempts++;\n this.log(\"info\", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);\n\n setTimeout(async () => {\n try {\n await this.connectWebSocket();\n this.sendSessionEvent(\"connected\");\n this.sendSessionEvent(\"browser_ready\");\n } catch (error) {\n this.log(\"error\", \"Reconnection failed\", error);\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n // =========================================================================\n // Heartbeat\n // =========================================================================\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n if (this.ws?.readyState === WebSocket.OPEN) {\n const ping: HeartbeatMessage = {\n type: \"heartbeat\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n direction: \"pong\",\n };\n this.ws.send(JSON.stringify(ping));\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n // =========================================================================\n // Message Handling\n // =========================================================================\n\n private handleMessage(data: string): void {\n try {\n const message = JSON.parse(data);\n\n if (message.type === \"heartbeat\" && message.direction === \"ping\") {\n const pong: HeartbeatMessage = {\n type: \"heartbeat\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n direction: \"pong\",\n };\n this.ws?.send(JSON.stringify(pong));\n return;\n }\n\n if (message.type === \"command\") {\n this.handleCommand(message as BrowserCommand);\n return;\n }\n\n this.log(\"debug\", \"Received unknown message type\", message);\n } catch (error) {\n this.log(\"error\", \"Failed to parse message\", { error, data });\n }\n }\n\n private async handleCommand(command: BrowserCommand): Promise<void> {\n const startTime = Date.now();\n this.log(\"debug\", `Executing command: ${command.method}`, { id: command.id });\n\n try {\n const result = await this.executeMethod(command.method, command.args);\n const response: BrowserResponse = {\n type: \"response\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n requestId: command.id,\n success: true,\n result,\n contextId: command.contextId,\n };\n this.ws?.send(JSON.stringify(response));\n\n this.log(\"debug\", `Command completed: ${command.method}`, {\n id: command.id,\n durationMs: Date.now() - startTime,\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const response: BrowserResponse = {\n type: \"response\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n requestId: command.id,\n success: false,\n error: errorMessage,\n stack: error instanceof Error ? error.stack : undefined,\n contextId: command.contextId,\n };\n this.ws?.send(JSON.stringify(response));\n\n this.log(\"error\", `Command failed: ${command.method}`, {\n id: command.id,\n error: errorMessage,\n });\n }\n }\n\n private sendSessionEvent(\n event: \"connected\" | \"disconnected\" | \"browser_ready\" | \"browser_closed\" | \"error\",\n error?: string\n ): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;\n\n const message: SessionMessage = {\n type: \"session\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n event,\n browserMode: this.options.browserMode,\n error,\n };\n this.ws.send(JSON.stringify(message));\n }\n\n // =========================================================================\n // Method Execution — Delegate to PlaywrightClient\n // =========================================================================\n\n /**\n * Maps incoming WebSocket command method names to PlaywrightClient methods.\n * The client implements IBrowserClient, so all standard browser operations\n * are available and behave identically to the cloud environment.\n */\n private async executeMethod(method: string, args: unknown[]): Promise<unknown> {\n const client = this.client as IBrowserClient;\n\n switch (method) {\n // Lifecycle\n case \"connect\":\n return client.connect(args[0] as any);\n case \"disconnect\":\n return client.disconnect();\n\n // Navigation\n case \"navigate\":\n return client.navigate(args[0] as string, args[1] as any);\n case \"navigateBack\":\n return client.navigateBack(args[0] as any);\n\n // Page Inspection\n case \"snapshot\":\n return client.snapshot(args[0] as any);\n case \"takeScreenshot\":\n return client.takeScreenshot(args[0] as any);\n case \"evaluate\":\n return client.evaluate(args[0] as string, args[1] as any);\n case \"runCode\":\n return client.runCode(args[0] as string, args[1] as any);\n case \"consoleMessages\":\n return client.consoleMessages(args[0] as any);\n case \"networkRequests\":\n return client.networkRequests(args[0] as any);\n\n // Interaction\n case \"click\":\n return client.click(args[0] as string, args[1] as string, args[2] as any);\n case \"clickAtCoordinates\":\n return client.clickAtCoordinates(\n args[0] as number, args[1] as number, args[2] as string, args[3] as any\n );\n case \"moveToCoordinates\":\n return client.moveToCoordinates(\n args[0] as number, args[1] as number, args[2] as string, args[3] as any\n );\n case \"dragCoordinates\":\n return client.dragCoordinates(\n args[0] as number, args[1] as number, args[2] as number,\n args[3] as number, args[4] as string, args[5] as any\n );\n case \"hover\":\n return client.hover(args[0] as string, args[1] as string, args[2] as any);\n case \"drag\":\n return client.drag(\n args[0] as string, args[1] as string,\n args[2] as string, args[3] as string, args[4] as any\n );\n case \"type\":\n return client.type(\n args[0] as string, args[1] as string, args[2] as string,\n args[3] as boolean, args[4] as any\n );\n case \"pressKey\":\n return client.pressKey(args[0] as string, args[1] as any);\n case \"fillForm\":\n return client.fillForm(args[0] as any[], args[1] as any);\n case \"selectOption\":\n return client.selectOption(\n args[0] as string, args[1] as string, args[2] as string, args[3] as any\n );\n case \"fileUpload\":\n return client.fileUpload(args[0] as string[], args[1] as any);\n\n // Scroll\n case \"scroll\":\n return client.scroll(args[0] as any, args[1] as any, args[2] as any, args[3] as any, args[4] as any);\n\n // Dialogs\n case \"handleDialog\":\n return client.handleDialog(args[0] as \"accept\" | \"dismiss\", args[1] as string, args[2] as any);\n\n // Waiting\n case \"waitFor\":\n return client.waitFor(args[0] as any);\n\n // Browser Management\n case \"close\":\n return client.close(args[0] as any);\n case \"resize\":\n return client.resize(args[0] as number, args[1] as number, args[2] as any);\n case \"tabs\":\n return client.tabs(args[0] as \"list\" | \"new\" | \"close\" | \"select\", args[1] as number, args[2] as any);\n\n // Context Management\n case \"swapContext\":\n return client.swapContext?.(args[0] as any);\n\n // Storage & Page Info\n case \"getStorageState\":\n return client.getStorageState(args[0] as any);\n case \"getCurrentUrl\":\n return client.getCurrentUrl(args[0] as any);\n case \"getTitle\":\n return client.getTitle(args[0] as any);\n case \"getLinks\":\n return client.getLinks(args[0] as any);\n case \"getElementBoundingBox\":\n return client.getElementBoundingBox(args[0] as string, args[1] as any);\n\n // Tracing\n case \"startTracing\":\n return client.startTracing?.(args[0] as any);\n case \"stopTracing\":\n return client.stopTracing?.(args[0] as any);\n\n // Video\n case \"isVideoRecordingEnabled\":\n return client.isVideoRecordingEnabled?.() ?? false;\n case \"saveVideo\":\n return client.saveVideo?.() ?? null;\n case \"getVideoPath\":\n return null;\n\n // Screencast\n case \"startScreencast\":\n return client.startScreencast?.(args[0] as any, args[1] as any);\n case \"stopScreencast\":\n return client.stopScreencast?.();\n case \"isScreencastActive\":\n return client.isScreencastActive?.() ?? false;\n\n default:\n throw new Error(`Unknown method: ${method}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|