@ohos-ports/vibium 26.5.31-beta.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/dist/sync.js ADDED
@@ -0,0 +1,1112 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/sync/index.ts
31
+ var sync_exports = {};
32
+ __export(sync_exports, {
33
+ BrowserContextSync: () => BrowserContextSync,
34
+ BrowserSync: () => BrowserSync,
35
+ ClockSync: () => ClockSync,
36
+ DialogSync: () => DialogSync,
37
+ DownloadData: () => DownloadData,
38
+ ElementSync: () => ElementSync,
39
+ KeyboardSync: () => KeyboardSync,
40
+ MouseSync: () => MouseSync,
41
+ PageSync: () => PageSync,
42
+ RecordingSync: () => RecordingSync,
43
+ RouteSync: () => RouteSync,
44
+ TouchSync: () => TouchSync,
45
+ WebSocketInfoSync: () => WebSocketInfoSync,
46
+ browser: () => browser
47
+ });
48
+ module.exports = __toCommonJS(sync_exports);
49
+
50
+ // src/sync/bridge.ts
51
+ var import_worker_threads = require("worker_threads");
52
+ var path = __toESM(require("path"));
53
+ var activeBridges = /* @__PURE__ */ new Set();
54
+ function cleanup() {
55
+ for (const bridge of activeBridges) {
56
+ try {
57
+ bridge.tryQuit();
58
+ } catch {
59
+ }
60
+ }
61
+ activeBridges.clear();
62
+ }
63
+ var handlersRegistered = false;
64
+ function registerCleanupHandlers() {
65
+ if (handlersRegistered) return;
66
+ handlersRegistered = true;
67
+ process.on("exit", cleanup);
68
+ process.on("SIGINT", () => {
69
+ cleanup();
70
+ process.exit(130);
71
+ });
72
+ process.on("SIGTERM", () => {
73
+ cleanup();
74
+ process.exit(143);
75
+ });
76
+ }
77
+ var SyncBridge = class _SyncBridge {
78
+ constructor(worker, signal, callbackPortMain, callbackPortWorker) {
79
+ this.commandId = 0;
80
+ this.terminated = false;
81
+ this.handlers = /* @__PURE__ */ new Map();
82
+ this.worker = worker;
83
+ this.signal = signal;
84
+ this.callbackPortMain = callbackPortMain;
85
+ this.callbackPortWorker = callbackPortWorker;
86
+ }
87
+ static create() {
88
+ registerCleanupHandlers();
89
+ const signal = new Int32Array(new SharedArrayBuffer(8));
90
+ const { port1: callbackPortMain, port2: callbackPortWorker } = new import_worker_threads.MessageChannel();
91
+ const workerPath = path.join(__dirname, "worker.js");
92
+ const worker = new import_worker_threads.Worker(workerPath, {
93
+ workerData: { signal, callbackPort: callbackPortWorker },
94
+ transferList: [callbackPortWorker]
95
+ });
96
+ const bridge = new _SyncBridge(worker, signal, callbackPortMain, callbackPortWorker);
97
+ activeBridges.add(bridge);
98
+ return bridge;
99
+ }
100
+ /** Register a callback handler that can be invoked from the worker thread. */
101
+ registerHandler(id, handler) {
102
+ this.handlers.set(id, handler);
103
+ }
104
+ /** Remove a previously registered callback handler. */
105
+ unregisterHandler(id) {
106
+ this.handlers.delete(id);
107
+ }
108
+ /** Process any pending callbacks that fired between bridge calls. */
109
+ processPendingCallbacks() {
110
+ while (Atomics.load(this.signal, 0) === 2) {
111
+ this.handleCallback();
112
+ }
113
+ }
114
+ /** Handle a single callback request from the worker. */
115
+ handleCallback() {
116
+ const maxSpinIterations = 6e4;
117
+ let cbMsg = (0, import_worker_threads.receiveMessageOnPort)(this.callbackPortMain);
118
+ let spinCount = 0;
119
+ while (!cbMsg) {
120
+ spinCount++;
121
+ if (spinCount >= maxSpinIterations) {
122
+ throw new Error("Timed out waiting for callback message from worker (60s)");
123
+ }
124
+ Atomics.wait(this.signal, 1, Atomics.load(this.signal, 1), 1);
125
+ cbMsg = (0, import_worker_threads.receiveMessageOnPort)(this.callbackPortMain);
126
+ }
127
+ let decision = null;
128
+ const req = cbMsg.message;
129
+ const handler = this.handlers.get(req.handlerId);
130
+ if (handler) {
131
+ try {
132
+ decision = handler(req.data);
133
+ } catch {
134
+ }
135
+ }
136
+ Atomics.store(this.signal, 0, 0);
137
+ this.callbackPortMain.postMessage({ decision });
138
+ }
139
+ call(method, args = []) {
140
+ this.processPendingCallbacks();
141
+ const cmd = { id: this.commandId++, method, args };
142
+ const { port1, port2 } = new import_worker_threads.MessageChannel();
143
+ Atomics.store(this.signal, 0, 0);
144
+ Atomics.store(this.signal, 1, 0);
145
+ this.worker.postMessage({ cmd, port: port2 }, [port2]);
146
+ const commandTimeoutMs = 6e4;
147
+ const waitSliceMs = 1e3;
148
+ const startTime = Date.now();
149
+ for (; ; ) {
150
+ const waitResult = Atomics.wait(this.signal, 0, 0, waitSliceMs);
151
+ if (waitResult === "timed-out") {
152
+ if (Date.now() - startTime >= commandTimeoutMs) {
153
+ port1.close();
154
+ throw new Error(`Bridge call '${method}' timed out after ${commandTimeoutMs / 1e3}s \u2014 worker may have died`);
155
+ }
156
+ continue;
157
+ }
158
+ const sig = Atomics.load(this.signal, 0);
159
+ if (sig === 1) {
160
+ const message = (0, import_worker_threads.receiveMessageOnPort)(port1);
161
+ port1.close();
162
+ if (!message) {
163
+ throw new Error("No response from worker");
164
+ }
165
+ const response = message.message;
166
+ if (response.error) {
167
+ throw new Error(response.error);
168
+ }
169
+ return response.result;
170
+ }
171
+ if (sig === 2) {
172
+ this.handleCallback();
173
+ }
174
+ }
175
+ }
176
+ tryQuit() {
177
+ if (this.terminated) return;
178
+ try {
179
+ const cmd = { id: this.commandId++, method: "quit", args: [] };
180
+ const { port1, port2 } = new import_worker_threads.MessageChannel();
181
+ Atomics.store(this.signal, 0, 0);
182
+ Atomics.store(this.signal, 1, 0);
183
+ this.worker.postMessage({ cmd, port: port2 }, [port2]);
184
+ for (; ; ) {
185
+ const waitResult = Atomics.wait(this.signal, 0, 0, 5e3);
186
+ if (waitResult === "timed-out") {
187
+ port1.close();
188
+ this.terminate();
189
+ return;
190
+ }
191
+ const sig = Atomics.load(this.signal, 0);
192
+ if (sig === 1) {
193
+ port1.close();
194
+ this.callbackPortMain.close();
195
+ this.terminated = true;
196
+ activeBridges.delete(this);
197
+ this.worker.terminate();
198
+ return;
199
+ }
200
+ if (sig === 2) {
201
+ this.handleCallback();
202
+ }
203
+ }
204
+ } catch {
205
+ this.terminate();
206
+ }
207
+ }
208
+ terminate() {
209
+ if (this.terminated) return;
210
+ this.terminated = true;
211
+ this.callbackPortMain.close();
212
+ activeBridges.delete(this);
213
+ this.worker.terminate();
214
+ }
215
+ };
216
+
217
+ // src/sync/page.ts
218
+ var fs = __toESM(require("fs"));
219
+ var nodePath = __toESM(require("path"));
220
+
221
+ // src/sync/element.ts
222
+ var customInspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
223
+ var ElementSync = class _ElementSync {
224
+ constructor(bridge, elementId, info) {
225
+ this.bridge = bridge;
226
+ this.elementId = elementId;
227
+ this.info = info;
228
+ }
229
+ [customInspect]() {
230
+ const text = this.info.text.length > 50 ? this.info.text.slice(0, 50) + "..." : this.info.text;
231
+ return `Element { tag: '${this.info.tag}', text: '${text}' }`;
232
+ }
233
+ /**
234
+ * Click the element.
235
+ * Waits for element to be visible, stable, receive events, and enabled.
236
+ */
237
+ click(options) {
238
+ this.bridge.call("element.click", [this.elementId, options]);
239
+ }
240
+ /** Double-click the element. */
241
+ dblclick(options) {
242
+ this.bridge.call("element.dblclick", [this.elementId, options]);
243
+ }
244
+ /**
245
+ * Fill the element with text (clears existing content first).
246
+ * For inputs and textareas.
247
+ */
248
+ fill(value, options) {
249
+ this.bridge.call("element.fill", [this.elementId, value, options]);
250
+ }
251
+ /**
252
+ * Type text into the element.
253
+ * Waits for element to be visible, stable, receive events, enabled, and editable.
254
+ */
255
+ type(text, options) {
256
+ this.bridge.call("element.type", [this.elementId, text, options]);
257
+ }
258
+ /**
259
+ * Press a key while the element is focused.
260
+ * Supports key names ("Enter", "Tab") and combos ("Control+a").
261
+ */
262
+ press(key, options) {
263
+ this.bridge.call("element.press", [this.elementId, key, options]);
264
+ }
265
+ /** Clear the element's content (select all + delete). */
266
+ clear(options) {
267
+ this.bridge.call("element.clear", [this.elementId, options]);
268
+ }
269
+ /** Check a checkbox (no-op if already checked). */
270
+ check(options) {
271
+ this.bridge.call("element.check", [this.elementId, options]);
272
+ }
273
+ /** Uncheck a checkbox (no-op if already unchecked). */
274
+ uncheck(options) {
275
+ this.bridge.call("element.uncheck", [this.elementId, options]);
276
+ }
277
+ /** Select an option in a <select> element by value. */
278
+ selectOption(value, options) {
279
+ this.bridge.call("element.selectOption", [this.elementId, value, options]);
280
+ }
281
+ /** Hover over the element (move mouse to center, no click). */
282
+ hover(options) {
283
+ this.bridge.call("element.hover", [this.elementId, options]);
284
+ }
285
+ /** Focus the element. */
286
+ focus(options) {
287
+ this.bridge.call("element.focus", [this.elementId, options]);
288
+ }
289
+ /** Drag this element to a target element. */
290
+ dragTo(target, options) {
291
+ this.bridge.call("element.dragTo", [this.elementId, target.elementId, options]);
292
+ }
293
+ /** Tap the element (touch action). */
294
+ tap(options) {
295
+ this.bridge.call("element.tap", [this.elementId, options]);
296
+ }
297
+ /** Scroll the element into view. */
298
+ scrollIntoView(options) {
299
+ this.bridge.call("element.scrollIntoView", [this.elementId, options]);
300
+ }
301
+ /** Dispatch a DOM event on the element. */
302
+ dispatchEvent(eventType, eventInit, options) {
303
+ this.bridge.call("element.dispatchEvent", [this.elementId, eventType, eventInit, options]);
304
+ }
305
+ // --- State methods ---
306
+ text() {
307
+ const result = this.bridge.call("element.text", [this.elementId]);
308
+ return result.text;
309
+ }
310
+ innerText() {
311
+ const result = this.bridge.call("element.innerText", [this.elementId]);
312
+ return result.text;
313
+ }
314
+ html() {
315
+ const result = this.bridge.call("element.html", [this.elementId]);
316
+ return result.html;
317
+ }
318
+ value() {
319
+ const result = this.bridge.call("element.value", [this.elementId]);
320
+ return result.value;
321
+ }
322
+ attr(name) {
323
+ const result = this.bridge.call("element.attr", [this.elementId, name]);
324
+ return result.value;
325
+ }
326
+ getAttribute(name) {
327
+ return this.attr(name);
328
+ }
329
+ bounds() {
330
+ const result = this.bridge.call("element.bounds", [this.elementId]);
331
+ return result.box;
332
+ }
333
+ boundingBox() {
334
+ return this.bounds();
335
+ }
336
+ isVisible() {
337
+ const result = this.bridge.call("element.isVisible", [this.elementId]);
338
+ return result.visible;
339
+ }
340
+ isHidden() {
341
+ const result = this.bridge.call("element.isHidden", [this.elementId]);
342
+ return result.hidden;
343
+ }
344
+ isEnabled() {
345
+ const result = this.bridge.call("element.isEnabled", [this.elementId]);
346
+ return result.enabled;
347
+ }
348
+ isChecked() {
349
+ const result = this.bridge.call("element.isChecked", [this.elementId]);
350
+ return result.checked;
351
+ }
352
+ isEditable() {
353
+ const result = this.bridge.call("element.isEditable", [this.elementId]);
354
+ return result.editable;
355
+ }
356
+ screenshot() {
357
+ const result = this.bridge.call("element.screenshot", [this.elementId]);
358
+ return Buffer.from(result.data, "base64");
359
+ }
360
+ waitUntil(state, options) {
361
+ this.bridge.call("element.waitUntil", [this.elementId, state, options]);
362
+ }
363
+ setFiles(files, options) {
364
+ this.bridge.call("element.setFiles", [this.elementId, files, options]);
365
+ }
366
+ role() {
367
+ const result = this.bridge.call("element.role", [this.elementId]);
368
+ return result.role;
369
+ }
370
+ label() {
371
+ const result = this.bridge.call("element.label", [this.elementId]);
372
+ return result.label;
373
+ }
374
+ find(selector, options) {
375
+ const result = this.bridge.call("element.find", [this.elementId, selector, options]);
376
+ return new _ElementSync(this.bridge, result.elementId, result.info);
377
+ }
378
+ findAll(selector, options) {
379
+ const result = this.bridge.call("element.findAll", [this.elementId, selector, options]);
380
+ return result.elements.map((e) => new _ElementSync(this.bridge, e.elementId, e.info));
381
+ }
382
+ };
383
+
384
+ // src/sync/keyboard.ts
385
+ var KeyboardSync = class {
386
+ constructor(bridge, pageId) {
387
+ this.bridge = bridge;
388
+ this.pageId = pageId;
389
+ }
390
+ press(key) {
391
+ this.bridge.call("keyboard.press", [this.pageId, key]);
392
+ }
393
+ down(key) {
394
+ this.bridge.call("keyboard.down", [this.pageId, key]);
395
+ }
396
+ up(key) {
397
+ this.bridge.call("keyboard.up", [this.pageId, key]);
398
+ }
399
+ type(text) {
400
+ this.bridge.call("keyboard.type", [this.pageId, text]);
401
+ }
402
+ };
403
+ var MouseSync = class {
404
+ constructor(bridge, pageId) {
405
+ this.bridge = bridge;
406
+ this.pageId = pageId;
407
+ }
408
+ click(x, y) {
409
+ this.bridge.call("mouse.click", [this.pageId, x, y]);
410
+ }
411
+ move(x, y) {
412
+ this.bridge.call("mouse.move", [this.pageId, x, y]);
413
+ }
414
+ down() {
415
+ this.bridge.call("mouse.down", [this.pageId]);
416
+ }
417
+ up() {
418
+ this.bridge.call("mouse.up", [this.pageId]);
419
+ }
420
+ wheel(deltaX, deltaY) {
421
+ this.bridge.call("mouse.wheel", [this.pageId, deltaX, deltaY]);
422
+ }
423
+ };
424
+ var TouchSync = class {
425
+ constructor(bridge, pageId) {
426
+ this.bridge = bridge;
427
+ this.pageId = pageId;
428
+ }
429
+ tap(x, y) {
430
+ this.bridge.call("touch.tap", [this.pageId, x, y]);
431
+ }
432
+ };
433
+
434
+ // src/sync/clock.ts
435
+ var ClockSync = class {
436
+ constructor(bridge, pageId) {
437
+ this.bridge = bridge;
438
+ this.pageId = pageId;
439
+ }
440
+ install(options) {
441
+ const opts = options ? { ...options } : void 0;
442
+ if (opts?.time instanceof Date) {
443
+ opts.time = opts.time.getTime();
444
+ }
445
+ this.bridge.call("clock.install", [this.pageId, opts]);
446
+ }
447
+ fastForward(ticks) {
448
+ this.bridge.call("clock.fastForward", [this.pageId, ticks]);
449
+ }
450
+ runFor(ticks) {
451
+ this.bridge.call("clock.runFor", [this.pageId, ticks]);
452
+ }
453
+ pauseAt(time) {
454
+ const t = time instanceof Date ? time.getTime() : time;
455
+ this.bridge.call("clock.pauseAt", [this.pageId, t]);
456
+ }
457
+ resume() {
458
+ this.bridge.call("clock.resume", [this.pageId]);
459
+ }
460
+ setFixedTime(time) {
461
+ const t = time instanceof Date ? time.getTime() : time;
462
+ this.bridge.call("clock.setFixedTime", [this.pageId, t]);
463
+ }
464
+ setSystemTime(time) {
465
+ const t = time instanceof Date ? time.getTime() : time;
466
+ this.bridge.call("clock.setSystemTime", [this.pageId, t]);
467
+ }
468
+ setTimezone(timezone) {
469
+ this.bridge.call("clock.setTimezone", [this.pageId, timezone]);
470
+ }
471
+ };
472
+
473
+ // src/sync/recording.ts
474
+ var RecordingSync = class {
475
+ constructor(bridge, contextId) {
476
+ this.bridge = bridge;
477
+ this.contextId = contextId;
478
+ }
479
+ start(options = {}) {
480
+ this.bridge.call("recording.start", [this.contextId, options]);
481
+ }
482
+ stop(options = {}) {
483
+ const result = this.bridge.call("recording.stop", [this.contextId, options]);
484
+ return Buffer.from(result.data, "base64");
485
+ }
486
+ startChunk(options = {}) {
487
+ this.bridge.call("recording.startChunk", [this.contextId, options]);
488
+ }
489
+ stopChunk(options = {}) {
490
+ const result = this.bridge.call("recording.stopChunk", [this.contextId, options]);
491
+ return Buffer.from(result.data, "base64");
492
+ }
493
+ startGroup(name, options = {}) {
494
+ this.bridge.call("recording.startGroup", [this.contextId, name, options]);
495
+ }
496
+ stopGroup() {
497
+ this.bridge.call("recording.stopGroup", [this.contextId]);
498
+ }
499
+ };
500
+
501
+ // src/sync/context.ts
502
+ var BrowserContextSync = class {
503
+ constructor(bridge, contextId) {
504
+ this.bridge = bridge;
505
+ this.contextId = contextId;
506
+ this.recording = new RecordingSync(bridge, contextId);
507
+ }
508
+ newPage() {
509
+ const result = this.bridge.call("context.newPage", [this.contextId]);
510
+ return new PageSync(this.bridge, result.pageId);
511
+ }
512
+ close() {
513
+ this.bridge.call("context.close", [this.contextId]);
514
+ }
515
+ cookies(urls) {
516
+ const result = this.bridge.call("context.cookies", [this.contextId, urls]);
517
+ return result.cookies;
518
+ }
519
+ setCookies(cookies) {
520
+ this.bridge.call("context.setCookies", [this.contextId, cookies]);
521
+ }
522
+ clearCookies() {
523
+ this.bridge.call("context.clearCookies", [this.contextId]);
524
+ }
525
+ storage() {
526
+ return this.bridge.call("context.storage", [this.contextId]);
527
+ }
528
+ setStorage(state) {
529
+ this.bridge.call("context.setStorage", [this.contextId, state]);
530
+ }
531
+ clearStorage() {
532
+ this.bridge.call("context.clearStorage", [this.contextId]);
533
+ }
534
+ addInitScript(script) {
535
+ const result = this.bridge.call("context.addInitScript", [this.contextId, script]);
536
+ return result.script;
537
+ }
538
+ };
539
+
540
+ // src/sync/route.ts
541
+ var RouteSync = class {
542
+ constructor(request) {
543
+ /** @internal */
544
+ this._decision = { action: "continue" };
545
+ this.request = request;
546
+ }
547
+ /** Fulfill the request with a custom response. */
548
+ fulfill(response = {}) {
549
+ this._decision = { action: "fulfill", ...response };
550
+ }
551
+ /** Continue the request, optionally with overrides. */
552
+ continue(overrides) {
553
+ this._decision = { action: "continue", ...overrides };
554
+ }
555
+ /** Abort the request. */
556
+ abort() {
557
+ this._decision = { action: "abort" };
558
+ }
559
+ };
560
+
561
+ // src/sync/dialog.ts
562
+ var DialogSync = class {
563
+ constructor(data) {
564
+ /** @internal */
565
+ this._decision = { action: "dismiss" };
566
+ this.data = data;
567
+ }
568
+ /** The dialog type: 'alert', 'confirm', 'prompt', or 'beforeunload'. */
569
+ type() {
570
+ return this.data.type;
571
+ }
572
+ /** The dialog message text. */
573
+ message() {
574
+ return this.data.message;
575
+ }
576
+ /** The default value for prompt dialogs. */
577
+ defaultValue() {
578
+ return this.data.defaultValue;
579
+ }
580
+ /** Accept the dialog. For prompt dialogs, optionally provide text. */
581
+ accept(promptText) {
582
+ this._decision = { action: "accept" };
583
+ if (promptText !== void 0) this._decision.promptText = promptText;
584
+ }
585
+ /** Dismiss the dialog (cancel/close). */
586
+ dismiss() {
587
+ this._decision = { action: "dismiss" };
588
+ }
589
+ };
590
+
591
+ // src/sync/page.ts
592
+ var customInspect2 = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
593
+ var DownloadData = class {
594
+ constructor(data) {
595
+ this.url = data.url;
596
+ this.suggestedFilename = data.suggestedFilename;
597
+ this.path = data.path;
598
+ }
599
+ /** Save the downloaded file to a destination path. */
600
+ saveAs(destPath) {
601
+ if (!this.path) {
602
+ throw new Error("Download failed or path not available");
603
+ }
604
+ fs.mkdirSync(nodePath.dirname(destPath), { recursive: true });
605
+ fs.copyFileSync(this.path, destPath);
606
+ }
607
+ };
608
+ var WebSocketInfoSync = class {
609
+ constructor(url) {
610
+ this._isClosed = false;
611
+ this._messageHandlers = [];
612
+ this._closeHandlers = [];
613
+ this._url = url;
614
+ }
615
+ url() {
616
+ return this._url;
617
+ }
618
+ onMessage(fn) {
619
+ this._messageHandlers.push(fn);
620
+ }
621
+ onClose(fn) {
622
+ this._closeHandlers.push(fn);
623
+ }
624
+ isClosed() {
625
+ return this._isClosed;
626
+ }
627
+ /** @internal */
628
+ _emitMessage(data, direction) {
629
+ for (const fn of this._messageHandlers) fn(data, { direction });
630
+ }
631
+ /** @internal */
632
+ _emitClose(code, reason) {
633
+ this._isClosed = true;
634
+ for (const fn of this._closeHandlers) fn(code, reason);
635
+ }
636
+ };
637
+ var PageSync = class _PageSync {
638
+ constructor(bridge, pageId) {
639
+ this._nextHandlerId = 0;
640
+ this._routeHandlerIds = /* @__PURE__ */ new Map();
641
+ // pattern → handlerId
642
+ this._dialogHandlerId = null;
643
+ this._requestHandlerId = null;
644
+ this._responseHandlerId = null;
645
+ this._downloadHandlerId = null;
646
+ this._wsHandlerId = null;
647
+ this._wsInstances = /* @__PURE__ */ new Map();
648
+ this._cachedContext = null;
649
+ this._bridge = bridge;
650
+ this._pageId = pageId;
651
+ this.keyboard = new KeyboardSync(bridge, pageId);
652
+ this.mouse = new MouseSync(bridge, pageId);
653
+ this.touch = new TouchSync(bridge, pageId);
654
+ this.clock = new ClockSync(bridge, pageId);
655
+ this.waitUntil = Object.assign(
656
+ (fn, options) => {
657
+ const result = bridge.call("page.waitForFunction", [pageId, fn, options]);
658
+ return result.value;
659
+ },
660
+ {
661
+ url: (pattern, options) => {
662
+ bridge.call("page.waitForURL", [pageId, pattern, options]);
663
+ },
664
+ loaded: (state, options) => {
665
+ bridge.call("page.waitForLoad", [pageId, state, options]);
666
+ }
667
+ }
668
+ );
669
+ }
670
+ [customInspect2]() {
671
+ try {
672
+ const u = this.url();
673
+ const t = this.title();
674
+ return `Page { url: '${u}', title: '${t}' }`;
675
+ } catch {
676
+ return `Page { id: ${this._pageId} }`;
677
+ }
678
+ }
679
+ /** The parent BrowserContext that owns this page. */
680
+ get context() {
681
+ if (!this._cachedContext) {
682
+ const result = this._bridge.call("page.context", [this._pageId]);
683
+ this._cachedContext = new BrowserContextSync(this._bridge, result.contextId);
684
+ }
685
+ return this._cachedContext;
686
+ }
687
+ // --- Navigation ---
688
+ go(url) {
689
+ this._bridge.call("page.go", [this._pageId, url]);
690
+ }
691
+ back() {
692
+ this._bridge.call("page.back", [this._pageId]);
693
+ }
694
+ forward() {
695
+ this._bridge.call("page.forward", [this._pageId]);
696
+ }
697
+ reload() {
698
+ this._bridge.call("page.reload", [this._pageId]);
699
+ }
700
+ // --- Info ---
701
+ url() {
702
+ const result = this._bridge.call("page.url", [this._pageId]);
703
+ return result.url;
704
+ }
705
+ title() {
706
+ const result = this._bridge.call("page.title", [this._pageId]);
707
+ return result.title;
708
+ }
709
+ content() {
710
+ const result = this._bridge.call("page.content", [this._pageId]);
711
+ return result.content;
712
+ }
713
+ // --- Finding ---
714
+ find(selector, options) {
715
+ const result = this._bridge.call("page.find", [this._pageId, selector, options]);
716
+ return new ElementSync(this._bridge, result.elementId, result.info);
717
+ }
718
+ findAll(selector, options) {
719
+ const result = this._bridge.call("page.findAll", [this._pageId, selector, options]);
720
+ return result.elements.map((e) => new ElementSync(this._bridge, e.elementId, e.info));
721
+ }
722
+ // --- Waiting ---
723
+ /** Capture namespace — set up a listener before performing an action. */
724
+ get capture() {
725
+ const bridge = this._bridge;
726
+ const pageId = this._pageId;
727
+ return {
728
+ response(pattern, fn, options) {
729
+ if (fn) {
730
+ bridge.call("page.captureResponseStart", [pageId, pattern, options]);
731
+ fn();
732
+ return bridge.call("page.captureResponseFinish", [pageId]);
733
+ }
734
+ return bridge.call("page.waitForResponse", [pageId, pattern, options]);
735
+ },
736
+ request(pattern, fn, options) {
737
+ if (fn) {
738
+ bridge.call("page.captureRequestStart", [pageId, pattern, options]);
739
+ fn();
740
+ return bridge.call("page.captureRequestFinish", [pageId]);
741
+ }
742
+ return bridge.call("page.waitForRequest", [pageId, pattern, options]);
743
+ },
744
+ navigation(fn, options) {
745
+ bridge.call("page.captureNavigationStart", [pageId, options]);
746
+ if (fn) fn();
747
+ return bridge.call("page.captureNavigationFinish", [pageId]);
748
+ },
749
+ download(fn, options) {
750
+ bridge.call("page.captureDownloadStart", [pageId, options]);
751
+ if (fn) fn();
752
+ const raw = bridge.call("page.captureDownloadFinish", [pageId]);
753
+ return new DownloadData(raw);
754
+ },
755
+ dialog(fn, options) {
756
+ bridge.call("page.captureDialogStart", [pageId, options]);
757
+ if (fn) fn();
758
+ return bridge.call("page.captureDialogFinish", [pageId]);
759
+ },
760
+ event(name, fn, options) {
761
+ bridge.call("page.captureEventStart", [pageId, name, options]);
762
+ if (fn) fn();
763
+ return bridge.call("page.captureEventFinish", [pageId]);
764
+ }
765
+ };
766
+ }
767
+ wait(ms) {
768
+ this._bridge.call("page.wait", [this._pageId, ms]);
769
+ }
770
+ // --- Screenshots & PDF ---
771
+ screenshot(options) {
772
+ const result = this._bridge.call("page.screenshot", [this._pageId, options]);
773
+ return Buffer.from(result.data, "base64");
774
+ }
775
+ pdf() {
776
+ const result = this._bridge.call("page.pdf", [this._pageId]);
777
+ return Buffer.from(result.data, "base64");
778
+ }
779
+ // --- Evaluation ---
780
+ evaluate(expression) {
781
+ const result = this._bridge.call("page.eval", [this._pageId, expression]);
782
+ return result.value;
783
+ }
784
+ addScript(source) {
785
+ this._bridge.call("page.addScript", [this._pageId, source]);
786
+ }
787
+ addStyle(source) {
788
+ this._bridge.call("page.addStyle", [this._pageId, source]);
789
+ }
790
+ expose(name, fn) {
791
+ this._bridge.call("page.expose", [this._pageId, name, fn]);
792
+ }
793
+ // --- Lifecycle ---
794
+ bringToFront() {
795
+ this._bridge.call("page.bringToFront", [this._pageId]);
796
+ }
797
+ close() {
798
+ this._bridge.call("page.close", [this._pageId]);
799
+ }
800
+ scroll(direction, amount, selector) {
801
+ this._bridge.call("page.scroll", [this._pageId, direction, amount, selector]);
802
+ }
803
+ // --- Emulation ---
804
+ setViewport(size) {
805
+ this._bridge.call("page.setViewport", [this._pageId, size]);
806
+ }
807
+ viewport() {
808
+ return this._bridge.call("page.viewport", [this._pageId]);
809
+ }
810
+ emulateMedia(opts) {
811
+ this._bridge.call("page.emulateMedia", [this._pageId, opts]);
812
+ }
813
+ setContent(html) {
814
+ this._bridge.call("page.setContent", [this._pageId, html]);
815
+ }
816
+ setGeolocation(coords) {
817
+ this._bridge.call("page.setGeolocation", [this._pageId, coords]);
818
+ }
819
+ setWindow(options) {
820
+ this._bridge.call("page.setWindow", [this._pageId, options]);
821
+ }
822
+ window() {
823
+ return this._bridge.call("page.window", [this._pageId]);
824
+ }
825
+ // --- Frames ---
826
+ frames() {
827
+ const result = this._bridge.call("page.frames", [this._pageId]);
828
+ return result.frameIds.map((id) => new _PageSync(this._bridge, id));
829
+ }
830
+ frame(nameOrUrl) {
831
+ const result = this._bridge.call("page.frame", [this._pageId, nameOrUrl]);
832
+ if (result.frameId === null) return null;
833
+ return new _PageSync(this._bridge, result.frameId);
834
+ }
835
+ mainFrame() {
836
+ return this;
837
+ }
838
+ // --- Accessibility ---
839
+ a11yTree(options) {
840
+ const result = this._bridge.call("page.a11yTree", [this._pageId, options]);
841
+ return result.tree;
842
+ }
843
+ // --- Network ---
844
+ route(pattern, action) {
845
+ if (typeof action === "function") {
846
+ const handlerId = `route_${this._pageId}_${this._nextHandlerId++}`;
847
+ this._bridge.registerHandler(handlerId, (data) => {
848
+ const route = new RouteSync(data);
849
+ action(route);
850
+ return route._decision;
851
+ });
852
+ this._routeHandlerIds.set(pattern, handlerId);
853
+ this._bridge.call("page.routeWithCallback", [this._pageId, pattern, handlerId]);
854
+ } else {
855
+ this._bridge.call("page.route", [this._pageId, pattern, action]);
856
+ }
857
+ }
858
+ unroute(pattern) {
859
+ const handlerId = this._routeHandlerIds.get(pattern);
860
+ if (handlerId) {
861
+ this._bridge.unregisterHandler(handlerId);
862
+ this._routeHandlerIds.delete(pattern);
863
+ }
864
+ this._bridge.call("page.unroute", [this._pageId, pattern]);
865
+ }
866
+ setHeaders(headers) {
867
+ this._bridge.call("page.setHeaders", [this._pageId, headers]);
868
+ }
869
+ // --- Events ---
870
+ onDialog(action) {
871
+ if (typeof action === "function") {
872
+ const handlerId = `dialog_${this._pageId}_${this._nextHandlerId++}`;
873
+ this._bridge.registerHandler(handlerId, (data) => {
874
+ const dialog = new DialogSync(data);
875
+ action(dialog);
876
+ return dialog._decision;
877
+ });
878
+ if (this._dialogHandlerId) {
879
+ this._bridge.unregisterHandler(this._dialogHandlerId);
880
+ }
881
+ this._dialogHandlerId = handlerId;
882
+ this._bridge.call("page.onDialogWithCallback", [this._pageId, handlerId]);
883
+ } else {
884
+ this._bridge.call("page.onDialog", [this._pageId, action]);
885
+ }
886
+ }
887
+ onConsole(mode) {
888
+ this._bridge.call("page.onConsole", [this._pageId, mode]);
889
+ }
890
+ consoleMessages() {
891
+ const result = this._bridge.call("page.consoleMessages", [this._pageId]);
892
+ return result.messages;
893
+ }
894
+ onError(mode) {
895
+ this._bridge.call("page.onError", [this._pageId, mode]);
896
+ }
897
+ errors() {
898
+ const result = this._bridge.call("page.errors", [this._pageId]);
899
+ return result.errors;
900
+ }
901
+ onRequest(fn) {
902
+ const handlerId = `request_${this._pageId}_${this._nextHandlerId++}`;
903
+ this._bridge.registerHandler(handlerId, (data) => {
904
+ fn(data);
905
+ return null;
906
+ });
907
+ if (this._requestHandlerId) {
908
+ this._bridge.unregisterHandler(this._requestHandlerId);
909
+ }
910
+ this._requestHandlerId = handlerId;
911
+ this._bridge.call("page.onRequestWithCallback", [this._pageId, handlerId]);
912
+ }
913
+ onResponse(fn) {
914
+ const handlerId = `response_${this._pageId}_${this._nextHandlerId++}`;
915
+ this._bridge.registerHandler(handlerId, (data) => {
916
+ fn(data);
917
+ return null;
918
+ });
919
+ if (this._responseHandlerId) {
920
+ this._bridge.unregisterHandler(this._responseHandlerId);
921
+ }
922
+ this._responseHandlerId = handlerId;
923
+ this._bridge.call("page.onResponseWithCallback", [this._pageId, handlerId]);
924
+ }
925
+ onDownload(fn) {
926
+ const handlerId = `download_${this._pageId}_${this._nextHandlerId++}`;
927
+ this._bridge.registerHandler(handlerId, (data) => {
928
+ fn(new DownloadData(data));
929
+ return null;
930
+ });
931
+ if (this._downloadHandlerId) {
932
+ this._bridge.unregisterHandler(this._downloadHandlerId);
933
+ }
934
+ this._downloadHandlerId = handlerId;
935
+ this._bridge.call("page.onDownloadWithCallback", [this._pageId, handlerId]);
936
+ }
937
+ onWebSocket(fn) {
938
+ const handlerId = `ws_${this._pageId}_${this._nextHandlerId++}`;
939
+ this._bridge.registerHandler(handlerId, (data) => {
940
+ if (data.type === "created") {
941
+ const ws = new WebSocketInfoSync(data.url);
942
+ this._wsInstances.set(data.wsId, ws);
943
+ fn(ws);
944
+ } else if (data.type === "message") {
945
+ const ws = this._wsInstances.get(data.wsId);
946
+ if (ws) ws._emitMessage(data.data, data.direction);
947
+ } else if (data.type === "close") {
948
+ const ws = this._wsInstances.get(data.wsId);
949
+ if (ws) {
950
+ ws._emitClose(data.code, data.reason);
951
+ this._wsInstances.delete(data.wsId);
952
+ }
953
+ }
954
+ return null;
955
+ });
956
+ if (this._wsHandlerId) {
957
+ this._bridge.unregisterHandler(this._wsHandlerId);
958
+ }
959
+ this._wsHandlerId = handlerId;
960
+ this._bridge.call("page.onWebSocketWithCallback", [this._pageId, handlerId]);
961
+ }
962
+ removeAllListeners(event) {
963
+ if (!event || event === "dialog") {
964
+ if (this._dialogHandlerId) {
965
+ this._bridge.unregisterHandler(this._dialogHandlerId);
966
+ this._dialogHandlerId = null;
967
+ }
968
+ }
969
+ if (!event || event === "request") {
970
+ if (this._requestHandlerId) {
971
+ this._bridge.unregisterHandler(this._requestHandlerId);
972
+ this._requestHandlerId = null;
973
+ }
974
+ for (const [, handlerId] of this._routeHandlerIds) {
975
+ this._bridge.unregisterHandler(handlerId);
976
+ }
977
+ this._routeHandlerIds.clear();
978
+ }
979
+ if (!event || event === "response") {
980
+ if (this._responseHandlerId) {
981
+ this._bridge.unregisterHandler(this._responseHandlerId);
982
+ this._responseHandlerId = null;
983
+ }
984
+ }
985
+ if (!event || event === "download") {
986
+ if (this._downloadHandlerId) {
987
+ this._bridge.unregisterHandler(this._downloadHandlerId);
988
+ this._downloadHandlerId = null;
989
+ }
990
+ }
991
+ if (!event || event === "websocket") {
992
+ if (this._wsHandlerId) {
993
+ this._bridge.unregisterHandler(this._wsHandlerId);
994
+ this._wsHandlerId = null;
995
+ }
996
+ this._wsInstances.clear();
997
+ }
998
+ this._bridge.call("page.removeAllListeners", [this._pageId, event]);
999
+ }
1000
+ };
1001
+
1002
+ // src/sync/browser.ts
1003
+ var customInspect3 = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
1004
+ var BrowserSync = class {
1005
+ constructor(bridge) {
1006
+ this._nextHandlerId = 0;
1007
+ this._bridge = bridge;
1008
+ }
1009
+ [customInspect3]() {
1010
+ return "Browser { connected: true }";
1011
+ }
1012
+ page() {
1013
+ const result = this._bridge.call("browser.page");
1014
+ return new PageSync(this._bridge, result.pageId);
1015
+ }
1016
+ newPage() {
1017
+ const result = this._bridge.call("browser.newPage");
1018
+ return new PageSync(this._bridge, result.pageId);
1019
+ }
1020
+ pages() {
1021
+ const result = this._bridge.call("browser.pages");
1022
+ return result.pageIds.map((id) => new PageSync(this._bridge, id));
1023
+ }
1024
+ newContext() {
1025
+ const result = this._bridge.call("browser.newContext");
1026
+ return new BrowserContextSync(this._bridge, result.contextId);
1027
+ }
1028
+ waitForPage(options) {
1029
+ const result = this._bridge.call("browser.waitForPage", [options]);
1030
+ return new PageSync(this._bridge, result.pageId);
1031
+ }
1032
+ waitForPopup(options) {
1033
+ const result = this._bridge.call("browser.waitForPopup", [options]);
1034
+ return new PageSync(this._bridge, result.pageId);
1035
+ }
1036
+ onPage(callback) {
1037
+ if (this._pageHandlerId) {
1038
+ this._bridge.unregisterHandler(this._pageHandlerId);
1039
+ }
1040
+ const handlerId = `page_${this._nextHandlerId++}`;
1041
+ this._bridge.registerHandler(handlerId, (data) => {
1042
+ callback(new PageSync(this._bridge, data.pageId));
1043
+ });
1044
+ this._pageHandlerId = handlerId;
1045
+ this._bridge.call("browser.onPage", [handlerId]);
1046
+ }
1047
+ onPopup(callback) {
1048
+ if (this._popupHandlerId) {
1049
+ this._bridge.unregisterHandler(this._popupHandlerId);
1050
+ }
1051
+ const handlerId = `popup_${this._nextHandlerId++}`;
1052
+ this._bridge.registerHandler(handlerId, (data) => {
1053
+ callback(new PageSync(this._bridge, data.pageId));
1054
+ });
1055
+ this._popupHandlerId = handlerId;
1056
+ this._bridge.call("browser.onPopup", [handlerId]);
1057
+ }
1058
+ removeAllListeners(event) {
1059
+ if (!event || event === "page") {
1060
+ if (this._pageHandlerId) {
1061
+ this._bridge.unregisterHandler(this._pageHandlerId);
1062
+ this._pageHandlerId = void 0;
1063
+ }
1064
+ }
1065
+ if (!event || event === "popup") {
1066
+ if (this._popupHandlerId) {
1067
+ this._bridge.unregisterHandler(this._popupHandlerId);
1068
+ this._popupHandlerId = void 0;
1069
+ }
1070
+ }
1071
+ this._bridge.call("browser.removeAllListeners", [event]);
1072
+ }
1073
+ stop() {
1074
+ this._bridge.tryQuit();
1075
+ }
1076
+ };
1077
+ var browser = {
1078
+ start(urlOrOptions, options = {}) {
1079
+ let url;
1080
+ if (typeof urlOrOptions === "object") {
1081
+ options = urlOrOptions;
1082
+ url = void 0;
1083
+ } else {
1084
+ url = urlOrOptions;
1085
+ }
1086
+ const bridge = SyncBridge.create();
1087
+ try {
1088
+ bridge.call("browser.start", [url, options]);
1089
+ } catch (e) {
1090
+ bridge.terminate();
1091
+ throw e;
1092
+ }
1093
+ return new BrowserSync(bridge);
1094
+ }
1095
+ };
1096
+ // Annotate the CommonJS export names for ESM import in node:
1097
+ 0 && (module.exports = {
1098
+ BrowserContextSync,
1099
+ BrowserSync,
1100
+ ClockSync,
1101
+ DialogSync,
1102
+ DownloadData,
1103
+ ElementSync,
1104
+ KeyboardSync,
1105
+ MouseSync,
1106
+ PageSync,
1107
+ RecordingSync,
1108
+ RouteSync,
1109
+ TouchSync,
1110
+ WebSocketInfoSync,
1111
+ browser
1112
+ });