@canaryai/cli 0.1.11 → 0.1.13
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-HJ2JWIJ7.js → chunk-2T64Z2NI.js} +7 -1
- package/dist/chunk-2T64Z2NI.js.map +1 -0
- package/dist/{chunk-G2X3H7AM.js → chunk-L26U3BST.js} +231 -132
- package/dist/chunk-L26U3BST.js.map +1 -0
- package/dist/{chunk-VYBCH4ZP.js → chunk-V7U52ISX.js} +2 -2
- package/dist/{feature-flag-PN5IFFQR.js → feature-flag-MFTRYRYX.js} +2 -2
- package/dist/index.js +32 -16
- package/dist/index.js.map +1 -1
- package/dist/{knobs-DAG7HD2F.js → knobs-T3O4Z3ZB.js} +2 -2
- package/dist/{local-browser-VOBIUIGT.js → local-browser-SYPTG6IQ.js} +3 -3
- package/dist/{mcp-I6FCGDDR.js → mcp-TMD2R5Z6.js} +4 -4
- package/dist/{psql-A3BADRQN.js → psql-6IFVXM3A.js} +2 -2
- package/dist/{redis-N2DSDDQU.js → redis-HZC32IEO.js} +2 -2
- package/dist/release-WOD3DAX4.js +249 -0
- package/dist/release-WOD3DAX4.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-G2X3H7AM.js.map +0 -1
- package/dist/chunk-HJ2JWIJ7.js.map +0 -1
- /package/dist/{chunk-VYBCH4ZP.js.map → chunk-V7U52ISX.js.map} +0 -0
- /package/dist/{feature-flag-PN5IFFQR.js.map → feature-flag-MFTRYRYX.js.map} +0 -0
- /package/dist/{knobs-DAG7HD2F.js.map → knobs-T3O4Z3ZB.js.map} +0 -0
- /package/dist/{local-browser-VOBIUIGT.js.map → local-browser-SYPTG6IQ.js.map} +0 -0
- /package/dist/{mcp-I6FCGDDR.js.map → mcp-TMD2R5Z6.js.map} +0 -0
- /package/dist/{psql-A3BADRQN.js.map → psql-6IFVXM3A.js.map} +0 -0
- /package/dist/{redis-N2DSDDQU.js.map → redis-HZC32IEO.js.map} +0 -0
|
@@ -4,13 +4,12 @@ var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
|
4
4
|
var RECONNECT_DELAY_MS = 1e3;
|
|
5
5
|
var MAX_RECONNECT_DELAY_MS = 3e4;
|
|
6
6
|
var MAX_RECONNECT_ATTEMPTS = 10;
|
|
7
|
-
var LocalBrowserHost = class {
|
|
7
|
+
var LocalBrowserHost = class _LocalBrowserHost {
|
|
8
8
|
options;
|
|
9
9
|
ws = null;
|
|
10
10
|
browser = null;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
pendingDialogs = [];
|
|
11
|
+
contexts = /* @__PURE__ */ new Map();
|
|
12
|
+
static DEFAULT_CONTEXT_ID = "__default__";
|
|
14
13
|
heartbeatTimer = null;
|
|
15
14
|
reconnectAttempts = 0;
|
|
16
15
|
isShuttingDown = false;
|
|
@@ -49,13 +48,13 @@ var LocalBrowserHost = class {
|
|
|
49
48
|
}
|
|
50
49
|
this.ws = null;
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
for (const [id, slot] of this.contexts) {
|
|
53
52
|
try {
|
|
54
|
-
await
|
|
53
|
+
await slot.context.close();
|
|
55
54
|
} catch {
|
|
56
55
|
}
|
|
57
|
-
this.context = null;
|
|
58
56
|
}
|
|
57
|
+
this.contexts.clear();
|
|
59
58
|
if (this.browser) {
|
|
60
59
|
try {
|
|
61
60
|
await this.browser.close();
|
|
@@ -63,7 +62,6 @@ var LocalBrowserHost = class {
|
|
|
63
62
|
}
|
|
64
63
|
this.browser = null;
|
|
65
64
|
}
|
|
66
|
-
this.page = null;
|
|
67
65
|
this.log("info", "Local browser host stopped");
|
|
68
66
|
}
|
|
69
67
|
// =========================================================================
|
|
@@ -158,10 +156,13 @@ var LocalBrowserHost = class {
|
|
|
158
156
|
if (browserMode === "cdp" && cdpUrl) {
|
|
159
157
|
this.log("info", "Connecting to existing Chrome via CDP", { cdpUrl });
|
|
160
158
|
this.browser = await chromium.connectOverCDP(cdpUrl);
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
const pages =
|
|
164
|
-
|
|
159
|
+
const existingContexts = this.browser.contexts();
|
|
160
|
+
const ctx = existingContexts[0] ?? await this.browser.newContext();
|
|
161
|
+
const pages = ctx.pages();
|
|
162
|
+
const pg = pages[0] ?? await ctx.newPage();
|
|
163
|
+
const slot = { context: ctx, page: pg, pendingDialogs: [] };
|
|
164
|
+
pg.on("dialog", (dialog) => slot.pendingDialogs.push(dialog));
|
|
165
|
+
this.contexts.set(_LocalBrowserHost.DEFAULT_CONTEXT_ID, slot);
|
|
165
166
|
} else {
|
|
166
167
|
this.log("info", "Launching new Playwright browser", { headless });
|
|
167
168
|
this.browser = await chromium.launch({
|
|
@@ -180,12 +181,12 @@ var LocalBrowserHost = class {
|
|
|
180
181
|
this.log("debug", "Storage state file not found, starting fresh");
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
const ctx = await this.browser.newContext(contextOptions);
|
|
185
|
+
const pg = await ctx.newPage();
|
|
186
|
+
const slot = { context: ctx, page: pg, pendingDialogs: [] };
|
|
187
|
+
pg.on("dialog", (dialog) => slot.pendingDialogs.push(dialog));
|
|
188
|
+
this.contexts.set(_LocalBrowserHost.DEFAULT_CONTEXT_ID, slot);
|
|
185
189
|
}
|
|
186
|
-
this.page.on("dialog", (dialog) => {
|
|
187
|
-
this.pendingDialogs.push(dialog);
|
|
188
|
-
});
|
|
189
190
|
this.log("info", "Browser ready");
|
|
190
191
|
}
|
|
191
192
|
// =========================================================================
|
|
@@ -215,20 +216,23 @@ var LocalBrowserHost = class {
|
|
|
215
216
|
}
|
|
216
217
|
async handleCommand(command) {
|
|
217
218
|
const startTime = Date.now();
|
|
218
|
-
|
|
219
|
+
const contextId = command.contextId;
|
|
220
|
+
this.log("debug", `Executing command: ${command.method}`, { id: command.id, contextId });
|
|
219
221
|
try {
|
|
220
|
-
const result = await this.executeMethod(command.method, command.args);
|
|
222
|
+
const result = await this.executeMethod(command.method, command.args, contextId);
|
|
221
223
|
const response = {
|
|
222
224
|
type: "response",
|
|
223
225
|
id: crypto.randomUUID(),
|
|
224
226
|
timestamp: Date.now(),
|
|
225
227
|
requestId: command.id,
|
|
226
228
|
success: true,
|
|
227
|
-
result
|
|
229
|
+
result,
|
|
230
|
+
contextId
|
|
228
231
|
};
|
|
229
232
|
this.ws?.send(JSON.stringify(response));
|
|
230
233
|
this.log("debug", `Command completed: ${command.method}`, {
|
|
231
234
|
id: command.id,
|
|
235
|
+
contextId,
|
|
232
236
|
durationMs: Date.now() - startTime
|
|
233
237
|
});
|
|
234
238
|
} catch (error) {
|
|
@@ -240,11 +244,13 @@ var LocalBrowserHost = class {
|
|
|
240
244
|
requestId: command.id,
|
|
241
245
|
success: false,
|
|
242
246
|
error: errorMessage,
|
|
243
|
-
stack: error instanceof Error ? error.stack : void 0
|
|
247
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
248
|
+
contextId
|
|
244
249
|
};
|
|
245
250
|
this.ws?.send(JSON.stringify(response));
|
|
246
251
|
this.log("error", `Command failed: ${command.method}`, {
|
|
247
252
|
id: command.id,
|
|
253
|
+
contextId,
|
|
248
254
|
error: errorMessage
|
|
249
255
|
});
|
|
250
256
|
}
|
|
@@ -264,7 +270,51 @@ var LocalBrowserHost = class {
|
|
|
264
270
|
// =========================================================================
|
|
265
271
|
// Method Execution
|
|
266
272
|
// =========================================================================
|
|
267
|
-
|
|
273
|
+
getSlot(contextId) {
|
|
274
|
+
const id = contextId ?? _LocalBrowserHost.DEFAULT_CONTEXT_ID;
|
|
275
|
+
const slot = this.contexts.get(id);
|
|
276
|
+
if (!slot) throw new Error(`Context not found: ${id}`);
|
|
277
|
+
return slot;
|
|
278
|
+
}
|
|
279
|
+
async createContextSlot(contextId, options) {
|
|
280
|
+
if (!this.browser) throw new Error("No browser available");
|
|
281
|
+
if (this.contexts.has(contextId)) throw new Error(`Context already exists: ${contextId}`);
|
|
282
|
+
const contextOptions = {
|
|
283
|
+
viewport: { width: 1920, height: 1080 }
|
|
284
|
+
};
|
|
285
|
+
if (options?.storageState) {
|
|
286
|
+
const tmpPath = `/tmp/storage-state-${crypto.randomUUID()}.json`;
|
|
287
|
+
await Bun.write(tmpPath, JSON.stringify(options.storageState));
|
|
288
|
+
contextOptions.storageState = tmpPath;
|
|
289
|
+
this.log("info", "Loaded inline storage state for new context", { contextId });
|
|
290
|
+
}
|
|
291
|
+
const ctx = await this.browser.newContext(contextOptions);
|
|
292
|
+
const pg = await ctx.newPage();
|
|
293
|
+
const slot = { context: ctx, page: pg, pendingDialogs: [] };
|
|
294
|
+
pg.on("dialog", (dialog) => slot.pendingDialogs.push(dialog));
|
|
295
|
+
this.contexts.set(contextId, slot);
|
|
296
|
+
this.log("info", "Created new context slot", { contextId });
|
|
297
|
+
}
|
|
298
|
+
async destroyContextSlot(contextId) {
|
|
299
|
+
if (contextId === _LocalBrowserHost.DEFAULT_CONTEXT_ID) {
|
|
300
|
+
throw new Error("Cannot destroy the default context");
|
|
301
|
+
}
|
|
302
|
+
const slot = this.contexts.get(contextId);
|
|
303
|
+
if (!slot) throw new Error(`Context not found: ${contextId}`);
|
|
304
|
+
try {
|
|
305
|
+
await slot.context.close();
|
|
306
|
+
} catch {
|
|
307
|
+
}
|
|
308
|
+
this.contexts.delete(contextId);
|
|
309
|
+
this.log("info", "Destroyed context slot", { contextId });
|
|
310
|
+
}
|
|
311
|
+
async executeMethod(method, args, contextId) {
|
|
312
|
+
switch (method) {
|
|
313
|
+
case "createContext":
|
|
314
|
+
return this.createContextSlot(args[0], args[1]);
|
|
315
|
+
case "destroyContext":
|
|
316
|
+
return this.destroyContextSlot(args[0]);
|
|
317
|
+
}
|
|
268
318
|
switch (method) {
|
|
269
319
|
// Lifecycle
|
|
270
320
|
case "connect":
|
|
@@ -273,38 +323,40 @@ var LocalBrowserHost = class {
|
|
|
273
323
|
return this.disconnect();
|
|
274
324
|
// Navigation
|
|
275
325
|
case "navigate":
|
|
276
|
-
return this.navigate(args[0], args[1]);
|
|
326
|
+
return this.navigate(args[0], args[1], contextId);
|
|
277
327
|
case "navigateBack":
|
|
278
|
-
return this.navigateBack(args[0]);
|
|
328
|
+
return this.navigateBack(args[0], contextId);
|
|
279
329
|
// Page Inspection
|
|
280
330
|
case "snapshot":
|
|
281
|
-
return this.snapshot(args[0]);
|
|
331
|
+
return this.snapshot(args[0], contextId);
|
|
282
332
|
case "takeScreenshot":
|
|
283
|
-
return this.takeScreenshot(args[0]);
|
|
333
|
+
return this.takeScreenshot(args[0], contextId);
|
|
284
334
|
case "evaluate":
|
|
285
|
-
return this.evaluate(args[0], args[1]);
|
|
335
|
+
return this.evaluate(args[0], args[1], contextId);
|
|
286
336
|
case "runCode":
|
|
287
|
-
return this.runCode(args[0], args[1]);
|
|
337
|
+
return this.runCode(args[0], args[1], contextId);
|
|
288
338
|
case "consoleMessages":
|
|
289
339
|
return this.consoleMessages(args[0]);
|
|
290
340
|
case "networkRequests":
|
|
291
341
|
return this.networkRequests(args[0]);
|
|
292
342
|
// Interaction
|
|
293
343
|
case "click":
|
|
294
|
-
return this.click(args[0], args[1], args[2]);
|
|
344
|
+
return this.click(args[0], args[1], args[2], contextId);
|
|
295
345
|
case "clickAtCoordinates":
|
|
296
346
|
return this.clickAtCoordinates(
|
|
297
347
|
args[0],
|
|
298
348
|
args[1],
|
|
299
349
|
args[2],
|
|
300
|
-
args[3]
|
|
350
|
+
args[3],
|
|
351
|
+
contextId
|
|
301
352
|
);
|
|
302
353
|
case "moveToCoordinates":
|
|
303
354
|
return this.moveToCoordinates(
|
|
304
355
|
args[0],
|
|
305
356
|
args[1],
|
|
306
357
|
args[2],
|
|
307
|
-
args[3]
|
|
358
|
+
args[3],
|
|
359
|
+
contextId
|
|
308
360
|
);
|
|
309
361
|
case "dragCoordinates":
|
|
310
362
|
return this.dragCoordinates(
|
|
@@ -313,17 +365,19 @@ var LocalBrowserHost = class {
|
|
|
313
365
|
args[2],
|
|
314
366
|
args[3],
|
|
315
367
|
args[4],
|
|
316
|
-
args[5]
|
|
368
|
+
args[5],
|
|
369
|
+
contextId
|
|
317
370
|
);
|
|
318
371
|
case "hover":
|
|
319
|
-
return this.hover(args[0], args[1], args[2]);
|
|
372
|
+
return this.hover(args[0], args[1], args[2], contextId);
|
|
320
373
|
case "drag":
|
|
321
374
|
return this.drag(
|
|
322
375
|
args[0],
|
|
323
376
|
args[1],
|
|
324
377
|
args[2],
|
|
325
378
|
args[3],
|
|
326
|
-
args[4]
|
|
379
|
+
args[4],
|
|
380
|
+
contextId
|
|
327
381
|
);
|
|
328
382
|
case "type":
|
|
329
383
|
return this.type(
|
|
@@ -331,50 +385,55 @@ var LocalBrowserHost = class {
|
|
|
331
385
|
args[1],
|
|
332
386
|
args[2],
|
|
333
387
|
args[3],
|
|
334
|
-
args[4]
|
|
388
|
+
args[4],
|
|
389
|
+
contextId
|
|
335
390
|
);
|
|
336
391
|
case "pressKey":
|
|
337
|
-
return this.pressKey(args[0], args[1]);
|
|
392
|
+
return this.pressKey(args[0], args[1], contextId);
|
|
338
393
|
case "fillForm":
|
|
339
|
-
return this.fillForm(args[0], args[1]);
|
|
394
|
+
return this.fillForm(args[0], args[1], contextId);
|
|
340
395
|
case "selectOption":
|
|
341
396
|
return this.selectOption(
|
|
342
397
|
args[0],
|
|
343
398
|
args[1],
|
|
344
399
|
args[2],
|
|
345
|
-
args[3]
|
|
400
|
+
args[3],
|
|
401
|
+
contextId
|
|
346
402
|
);
|
|
347
403
|
case "fileUpload":
|
|
348
|
-
return this.fileUpload(args[0], args[1]);
|
|
404
|
+
return this.fileUpload(args[0], args[1], contextId);
|
|
349
405
|
// Dialogs
|
|
350
406
|
case "handleDialog":
|
|
351
|
-
return this.handleDialog(args[0], args[1], args[2]);
|
|
407
|
+
return this.handleDialog(args[0], args[1], args[2], contextId);
|
|
352
408
|
// Waiting
|
|
353
409
|
case "waitFor":
|
|
354
|
-
return this.waitFor(args[0]);
|
|
410
|
+
return this.waitFor(args[0], contextId);
|
|
355
411
|
// Browser Management
|
|
356
412
|
case "close":
|
|
357
|
-
return this.closePage(args[0]);
|
|
413
|
+
return this.closePage(args[0], contextId);
|
|
358
414
|
case "resize":
|
|
359
|
-
return this.resize(args[0], args[1], args[2]);
|
|
415
|
+
return this.resize(args[0], args[1], args[2], contextId);
|
|
360
416
|
case "tabs":
|
|
361
|
-
return this.tabs(args[0], args[1], args[2]);
|
|
417
|
+
return this.tabs(args[0], args[1], args[2], contextId);
|
|
418
|
+
// Context Management
|
|
419
|
+
case "swapContext":
|
|
420
|
+
return this.handleSwapContext(args[0], contextId);
|
|
362
421
|
// Storage
|
|
363
422
|
case "getStorageState":
|
|
364
|
-
return this.getStorageState(args[0]);
|
|
423
|
+
return this.getStorageState(args[0], contextId);
|
|
365
424
|
case "getCurrentUrl":
|
|
366
|
-
return this.getCurrentUrl(args[0]);
|
|
425
|
+
return this.getCurrentUrl(args[0], contextId);
|
|
367
426
|
case "getTitle":
|
|
368
|
-
return this.getTitle(args[0]);
|
|
427
|
+
return this.getTitle(args[0], contextId);
|
|
369
428
|
case "getLinks":
|
|
370
|
-
return this.getLinks(args[0]);
|
|
429
|
+
return this.getLinks(args[0], contextId);
|
|
371
430
|
case "getElementBoundingBox":
|
|
372
|
-
return this.getElementBoundingBox(args[0], args[1]);
|
|
431
|
+
return this.getElementBoundingBox(args[0], args[1], contextId);
|
|
373
432
|
// Tracing
|
|
374
433
|
case "startTracing":
|
|
375
|
-
return this.startTracing(args[0]);
|
|
434
|
+
return this.startTracing(args[0], contextId);
|
|
376
435
|
case "stopTracing":
|
|
377
|
-
return this.stopTracing(args[0]);
|
|
436
|
+
return this.stopTracing(args[0], contextId);
|
|
378
437
|
// Video
|
|
379
438
|
case "isVideoRecordingEnabled":
|
|
380
439
|
return false;
|
|
@@ -390,12 +449,47 @@ var LocalBrowserHost = class {
|
|
|
390
449
|
// =========================================================================
|
|
391
450
|
// IBrowserClient Method Implementations
|
|
392
451
|
// =========================================================================
|
|
393
|
-
|
|
394
|
-
if (!this.
|
|
395
|
-
|
|
452
|
+
async handleSwapContext(options, contextId) {
|
|
453
|
+
if (!this.browser) throw new Error("No browser available");
|
|
454
|
+
const slotId = contextId ?? _LocalBrowserHost.DEFAULT_CONTEXT_ID;
|
|
455
|
+
const existing = this.contexts.get(slotId);
|
|
456
|
+
if (existing) {
|
|
457
|
+
await existing.context.close();
|
|
458
|
+
this.contexts.delete(slotId);
|
|
459
|
+
}
|
|
460
|
+
const contextOptions = {
|
|
461
|
+
viewport: { width: 1920, height: 1080 }
|
|
462
|
+
};
|
|
463
|
+
if (options.storageState) {
|
|
464
|
+
const tmpPath = `/tmp/storage-state-${crypto.randomUUID()}.json`;
|
|
465
|
+
await Bun.write(tmpPath, JSON.stringify(options.storageState));
|
|
466
|
+
contextOptions.storageState = tmpPath;
|
|
467
|
+
this.log("info", "Loaded inline storage state for context swap");
|
|
468
|
+
} else if (options.storageStatePath) {
|
|
469
|
+
try {
|
|
470
|
+
const exists = await Bun.file(options.storageStatePath).exists();
|
|
471
|
+
if (exists) {
|
|
472
|
+
contextOptions.storageState = options.storageStatePath;
|
|
473
|
+
this.log("info", "Loading storage state from file for context swap", {
|
|
474
|
+
storageStatePath: options.storageStatePath
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
} catch {
|
|
478
|
+
this.log("debug", "Storage state file not found, starting fresh context");
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const ctx = await this.browser.newContext(contextOptions);
|
|
482
|
+
const pg = await ctx.newPage();
|
|
483
|
+
const slot = { context: ctx, page: pg, pendingDialogs: [] };
|
|
484
|
+
pg.on("dialog", (dialog) => slot.pendingDialogs.push(dialog));
|
|
485
|
+
this.contexts.set(slotId, slot);
|
|
486
|
+
this.log("info", "Browser context swapped successfully", { contextId: slotId });
|
|
396
487
|
}
|
|
397
|
-
|
|
398
|
-
return this.
|
|
488
|
+
getPage(contextId) {
|
|
489
|
+
return this.getSlot(contextId).page;
|
|
490
|
+
}
|
|
491
|
+
resolveRef(ref, contextId) {
|
|
492
|
+
return this.getPage(contextId).locator(`aria-ref=${ref}`);
|
|
399
493
|
}
|
|
400
494
|
async connect(_options) {
|
|
401
495
|
return;
|
|
@@ -403,27 +497,27 @@ var LocalBrowserHost = class {
|
|
|
403
497
|
async disconnect() {
|
|
404
498
|
await this.stop();
|
|
405
499
|
}
|
|
406
|
-
async navigate(url, _opts) {
|
|
407
|
-
const page = this.getPage();
|
|
500
|
+
async navigate(url, _opts, contextId) {
|
|
501
|
+
const page = this.getPage(contextId);
|
|
408
502
|
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
409
503
|
await page.waitForLoadState("load", { timeout: 5e3 }).catch(() => {
|
|
410
504
|
});
|
|
411
|
-
return this.captureSnapshot();
|
|
505
|
+
return this.captureSnapshot(contextId);
|
|
412
506
|
}
|
|
413
|
-
async navigateBack(_opts) {
|
|
414
|
-
await this.getPage().goBack();
|
|
415
|
-
return this.captureSnapshot();
|
|
507
|
+
async navigateBack(_opts, contextId) {
|
|
508
|
+
await this.getPage(contextId).goBack();
|
|
509
|
+
return this.captureSnapshot(contextId);
|
|
416
510
|
}
|
|
417
|
-
async snapshot(_opts) {
|
|
418
|
-
return this.captureSnapshot();
|
|
511
|
+
async snapshot(_opts, contextId) {
|
|
512
|
+
return this.captureSnapshot(contextId);
|
|
419
513
|
}
|
|
420
|
-
async captureSnapshot() {
|
|
421
|
-
const page = this.getPage();
|
|
514
|
+
async captureSnapshot(contextId) {
|
|
515
|
+
const page = this.getPage(contextId);
|
|
422
516
|
this.lastSnapshotYaml = await page._snapshotForAI({ mode: "full" });
|
|
423
517
|
return this.lastSnapshotYaml;
|
|
424
518
|
}
|
|
425
|
-
async takeScreenshot(opts) {
|
|
426
|
-
const page = this.getPage();
|
|
519
|
+
async takeScreenshot(opts, contextId) {
|
|
520
|
+
const page = this.getPage(contextId);
|
|
427
521
|
const buffer = await page.screenshot({
|
|
428
522
|
type: opts?.type ?? "jpeg",
|
|
429
523
|
fullPage: opts?.fullPage ?? false
|
|
@@ -431,12 +525,12 @@ var LocalBrowserHost = class {
|
|
|
431
525
|
const mime = opts?.type === "png" ? "image/png" : "image/jpeg";
|
|
432
526
|
return `data:${mime};base64,${buffer.toString("base64")}`;
|
|
433
527
|
}
|
|
434
|
-
async evaluate(fn, _opts) {
|
|
435
|
-
const page = this.getPage();
|
|
528
|
+
async evaluate(fn, _opts, contextId) {
|
|
529
|
+
const page = this.getPage(contextId);
|
|
436
530
|
return page.evaluate(new Function(`return (${fn})()`));
|
|
437
531
|
}
|
|
438
|
-
async runCode(code, _opts) {
|
|
439
|
-
const page = this.getPage();
|
|
532
|
+
async runCode(code, _opts, contextId) {
|
|
533
|
+
const page = this.getPage(contextId);
|
|
440
534
|
const fn = new Function("page", `return (async () => { ${code} })()`);
|
|
441
535
|
return fn(page);
|
|
442
536
|
}
|
|
@@ -446,15 +540,15 @@ var LocalBrowserHost = class {
|
|
|
446
540
|
async networkRequests(_opts) {
|
|
447
541
|
return "Network request capture not implemented in CLI host";
|
|
448
542
|
}
|
|
449
|
-
async click(ref, _elementDesc, opts) {
|
|
450
|
-
const locator = this.resolveRef(ref);
|
|
543
|
+
async click(ref, _elementDesc, opts, contextId) {
|
|
544
|
+
const locator = this.resolveRef(ref, contextId);
|
|
451
545
|
await locator.scrollIntoViewIfNeeded({ timeout: 5e3 }).catch(() => {
|
|
452
546
|
});
|
|
453
547
|
const box = await locator.boundingBox();
|
|
454
548
|
if (box) {
|
|
455
549
|
const centerX = box.x + box.width / 2;
|
|
456
550
|
const centerY = box.y + box.height / 2;
|
|
457
|
-
const page = this.getPage();
|
|
551
|
+
const page = this.getPage(contextId);
|
|
458
552
|
if (opts?.modifiers?.length) {
|
|
459
553
|
for (const mod of opts.modifiers) {
|
|
460
554
|
await page.keyboard.down(mod);
|
|
@@ -478,34 +572,34 @@ var LocalBrowserHost = class {
|
|
|
478
572
|
}
|
|
479
573
|
}
|
|
480
574
|
}
|
|
481
|
-
async clickAtCoordinates(x, y, _elementDesc, opts) {
|
|
482
|
-
const page = this.getPage();
|
|
575
|
+
async clickAtCoordinates(x, y, _elementDesc, opts, contextId) {
|
|
576
|
+
const page = this.getPage(contextId);
|
|
483
577
|
if (opts?.doubleClick) {
|
|
484
578
|
await page.mouse.dblclick(x, y);
|
|
485
579
|
} else {
|
|
486
580
|
await page.mouse.click(x, y);
|
|
487
581
|
}
|
|
488
582
|
}
|
|
489
|
-
async moveToCoordinates(x, y, _elementDesc, _opts) {
|
|
490
|
-
await this.getPage().mouse.move(x, y);
|
|
583
|
+
async moveToCoordinates(x, y, _elementDesc, _opts, contextId) {
|
|
584
|
+
await this.getPage(contextId).mouse.move(x, y);
|
|
491
585
|
}
|
|
492
|
-
async dragCoordinates(startX, startY, endX, endY, _elementDesc, _opts) {
|
|
493
|
-
const page = this.getPage();
|
|
586
|
+
async dragCoordinates(startX, startY, endX, endY, _elementDesc, _opts, contextId) {
|
|
587
|
+
const page = this.getPage(contextId);
|
|
494
588
|
await page.mouse.move(startX, startY);
|
|
495
589
|
await page.mouse.down();
|
|
496
590
|
await page.mouse.move(endX, endY);
|
|
497
591
|
await page.mouse.up();
|
|
498
592
|
}
|
|
499
|
-
async hover(ref, _elementDesc, opts) {
|
|
500
|
-
await this.resolveRef(ref).hover({ timeout: opts?.timeoutMs ?? 3e4 });
|
|
593
|
+
async hover(ref, _elementDesc, opts, contextId) {
|
|
594
|
+
await this.resolveRef(ref, contextId).hover({ timeout: opts?.timeoutMs ?? 3e4 });
|
|
501
595
|
}
|
|
502
|
-
async drag(startRef, _startElement, endRef, _endElement, opts) {
|
|
503
|
-
const startLocator = this.resolveRef(startRef);
|
|
504
|
-
const endLocator = this.resolveRef(endRef);
|
|
596
|
+
async drag(startRef, _startElement, endRef, _endElement, opts, contextId) {
|
|
597
|
+
const startLocator = this.resolveRef(startRef, contextId);
|
|
598
|
+
const endLocator = this.resolveRef(endRef, contextId);
|
|
505
599
|
await startLocator.dragTo(endLocator, { timeout: opts?.timeoutMs ?? 6e4 });
|
|
506
600
|
}
|
|
507
|
-
async type(ref, text, _elementDesc, submit, opts) {
|
|
508
|
-
const locator = this.resolveRef(ref);
|
|
601
|
+
async type(ref, text, _elementDesc, submit, opts, contextId) {
|
|
602
|
+
const locator = this.resolveRef(ref, contextId);
|
|
509
603
|
await locator.clear();
|
|
510
604
|
await locator.pressSequentially(text, {
|
|
511
605
|
delay: opts?.delay ?? 0,
|
|
@@ -515,12 +609,12 @@ var LocalBrowserHost = class {
|
|
|
515
609
|
await locator.press("Enter");
|
|
516
610
|
}
|
|
517
611
|
}
|
|
518
|
-
async pressKey(key, _opts) {
|
|
519
|
-
await this.getPage().keyboard.press(key);
|
|
612
|
+
async pressKey(key, _opts, contextId) {
|
|
613
|
+
await this.getPage(contextId).keyboard.press(key);
|
|
520
614
|
}
|
|
521
|
-
async fillForm(fields, opts) {
|
|
615
|
+
async fillForm(fields, opts, contextId) {
|
|
522
616
|
for (const field of fields) {
|
|
523
|
-
const locator = this.resolveRef(field.ref);
|
|
617
|
+
const locator = this.resolveRef(field.ref, contextId);
|
|
524
618
|
const fieldType = field.type ?? "textbox";
|
|
525
619
|
switch (fieldType) {
|
|
526
620
|
case "checkbox": {
|
|
@@ -542,17 +636,18 @@ var LocalBrowserHost = class {
|
|
|
542
636
|
}
|
|
543
637
|
}
|
|
544
638
|
}
|
|
545
|
-
async selectOption(ref, value, _elementDesc, opts) {
|
|
546
|
-
await this.resolveRef(ref).selectOption(value, { timeout: opts?.timeoutMs ?? 3e4 });
|
|
639
|
+
async selectOption(ref, value, _elementDesc, opts, contextId) {
|
|
640
|
+
await this.resolveRef(ref, contextId).selectOption(value, { timeout: opts?.timeoutMs ?? 3e4 });
|
|
547
641
|
}
|
|
548
|
-
async fileUpload(paths, opts) {
|
|
549
|
-
const fileChooser = await this.getPage().waitForEvent("filechooser", {
|
|
642
|
+
async fileUpload(paths, opts, contextId) {
|
|
643
|
+
const fileChooser = await this.getPage(contextId).waitForEvent("filechooser", {
|
|
550
644
|
timeout: opts?.timeoutMs ?? 3e4
|
|
551
645
|
});
|
|
552
646
|
await fileChooser.setFiles(paths);
|
|
553
647
|
}
|
|
554
|
-
async handleDialog(action, promptText, _opts) {
|
|
555
|
-
const
|
|
648
|
+
async handleDialog(action, promptText, _opts, contextId) {
|
|
649
|
+
const slot = this.getSlot(contextId);
|
|
650
|
+
const dialog = slot.pendingDialogs.shift();
|
|
556
651
|
if (dialog) {
|
|
557
652
|
if (action === "accept") {
|
|
558
653
|
await dialog.accept(promptText);
|
|
@@ -561,8 +656,8 @@ var LocalBrowserHost = class {
|
|
|
561
656
|
}
|
|
562
657
|
}
|
|
563
658
|
}
|
|
564
|
-
async waitFor(opts) {
|
|
565
|
-
const page = this.getPage();
|
|
659
|
+
async waitFor(opts, contextId) {
|
|
660
|
+
const page = this.getPage(contextId);
|
|
566
661
|
const timeout = opts?.timeout ?? opts?.timeoutMs ?? 3e4;
|
|
567
662
|
if (opts?.timeSec) {
|
|
568
663
|
await page.waitForTimeout(opts.timeSec * 1e3);
|
|
@@ -583,16 +678,20 @@ var LocalBrowserHost = class {
|
|
|
583
678
|
});
|
|
584
679
|
}
|
|
585
680
|
}
|
|
586
|
-
async closePage(_opts) {
|
|
587
|
-
|
|
588
|
-
|
|
681
|
+
async closePage(_opts, contextId) {
|
|
682
|
+
const slot = this.getSlot(contextId);
|
|
683
|
+
await slot.page.close();
|
|
684
|
+
const remaining = slot.context.pages();
|
|
685
|
+
if (remaining.length > 0) {
|
|
686
|
+
slot.page = remaining[0];
|
|
687
|
+
}
|
|
589
688
|
}
|
|
590
|
-
async resize(width, height, _opts) {
|
|
591
|
-
await this.getPage().setViewportSize({ width, height });
|
|
689
|
+
async resize(width, height, _opts, contextId) {
|
|
690
|
+
await this.getPage(contextId).setViewportSize({ width, height });
|
|
592
691
|
}
|
|
593
|
-
async tabs(action, index, _opts) {
|
|
594
|
-
|
|
595
|
-
const pages =
|
|
692
|
+
async tabs(action, index, _opts, contextId) {
|
|
693
|
+
const slot = this.getSlot(contextId);
|
|
694
|
+
const pages = slot.context.pages();
|
|
596
695
|
switch (action) {
|
|
597
696
|
case "list":
|
|
598
697
|
return Promise.all(
|
|
@@ -603,58 +702,58 @@ var LocalBrowserHost = class {
|
|
|
603
702
|
}))
|
|
604
703
|
);
|
|
605
704
|
case "new": {
|
|
606
|
-
const newPage = await
|
|
607
|
-
|
|
608
|
-
newPage.on("dialog", (dialog) =>
|
|
705
|
+
const newPage = await slot.context.newPage();
|
|
706
|
+
slot.page = newPage;
|
|
707
|
+
newPage.on("dialog", (dialog) => slot.pendingDialogs.push(dialog));
|
|
609
708
|
return { index: pages.length };
|
|
610
709
|
}
|
|
611
710
|
case "close":
|
|
612
711
|
if (index !== void 0 && pages[index]) {
|
|
613
712
|
await pages[index].close();
|
|
614
713
|
} else {
|
|
615
|
-
await
|
|
714
|
+
await slot.page.close();
|
|
616
715
|
}
|
|
617
|
-
|
|
716
|
+
slot.page = slot.context.pages()[0] ?? slot.page;
|
|
618
717
|
break;
|
|
619
718
|
case "select":
|
|
620
719
|
if (index !== void 0 && pages[index]) {
|
|
621
|
-
|
|
720
|
+
slot.page = pages[index];
|
|
622
721
|
}
|
|
623
722
|
break;
|
|
624
723
|
}
|
|
625
724
|
return null;
|
|
626
725
|
}
|
|
627
|
-
async getStorageState(_opts) {
|
|
628
|
-
|
|
629
|
-
return
|
|
726
|
+
async getStorageState(_opts, contextId) {
|
|
727
|
+
const slot = this.getSlot(contextId);
|
|
728
|
+
return slot.context.storageState();
|
|
630
729
|
}
|
|
631
|
-
async getCurrentUrl(_opts) {
|
|
632
|
-
return this.getPage().url();
|
|
730
|
+
async getCurrentUrl(_opts, contextId) {
|
|
731
|
+
return this.getPage(contextId).url();
|
|
633
732
|
}
|
|
634
|
-
async getTitle(_opts) {
|
|
635
|
-
return this.getPage().title();
|
|
733
|
+
async getTitle(_opts, contextId) {
|
|
734
|
+
return this.getPage(contextId).title();
|
|
636
735
|
}
|
|
637
|
-
async getLinks(_opts) {
|
|
638
|
-
const page = this.getPage();
|
|
736
|
+
async getLinks(_opts, contextId) {
|
|
737
|
+
const page = this.getPage(contextId);
|
|
639
738
|
return page.$$eval(
|
|
640
739
|
"a[href]",
|
|
641
740
|
(links) => links.map((a) => a.href).filter((h) => !!h && (h.startsWith("http://") || h.startsWith("https://")))
|
|
642
741
|
);
|
|
643
742
|
}
|
|
644
|
-
async getElementBoundingBox(ref, _opts) {
|
|
645
|
-
const locator = this.resolveRef(ref);
|
|
743
|
+
async getElementBoundingBox(ref, _opts, contextId) {
|
|
744
|
+
const locator = this.resolveRef(ref, contextId);
|
|
646
745
|
const box = await locator.boundingBox();
|
|
647
746
|
if (!box) return null;
|
|
648
747
|
return { x: box.x, y: box.y, width: box.width, height: box.height };
|
|
649
748
|
}
|
|
650
|
-
async startTracing(_opts) {
|
|
651
|
-
|
|
652
|
-
await
|
|
749
|
+
async startTracing(_opts, contextId) {
|
|
750
|
+
const slot = this.getSlot(contextId);
|
|
751
|
+
await slot.context.tracing.start({ screenshots: true, snapshots: true });
|
|
653
752
|
}
|
|
654
|
-
async stopTracing(_opts) {
|
|
655
|
-
|
|
753
|
+
async stopTracing(_opts, contextId) {
|
|
754
|
+
const slot = this.getSlot(contextId);
|
|
656
755
|
const tracePath = `/tmp/trace-${Date.now()}.zip`;
|
|
657
|
-
await
|
|
756
|
+
await slot.context.tracing.stop({ path: tracePath });
|
|
658
757
|
return {
|
|
659
758
|
trace: tracePath,
|
|
660
759
|
network: "",
|
|
@@ -668,4 +767,4 @@ var LocalBrowserHost = class {
|
|
|
668
767
|
export {
|
|
669
768
|
LocalBrowserHost
|
|
670
769
|
};
|
|
671
|
-
//# sourceMappingURL=chunk-
|
|
770
|
+
//# sourceMappingURL=chunk-L26U3BST.js.map
|