@volter-ai-dev/supercode-browser-playwright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,475 @@
1
+ // src/executor.ts
2
+ import { errors } from "playwright-core";
3
+ import {
4
+ BROWSER_OPERATION_NAMES,
5
+ BrowserActionRefusal,
6
+ parseBrowserOperationCall
7
+ } from "./protocol.mjs";
8
+ var PLAYWRIGHT_IMPLEMENTATION = "playwright-core 1.63.0";
9
+ var SCRIPT_TIMEOUT_CLAMP_MS = 9e3;
10
+ var ACTION_TIMEOUT_MS = 5e3;
11
+ var WAIT_TIMEOUT_CLAMP_MS = 9e3;
12
+ var PLAYWRIGHT_FEATURES = Object.freeze([
13
+ "page.ariaSnapshot",
14
+ "page.keyboard",
15
+ "page.navigation.history",
16
+ "locator.css",
17
+ "locator.ref",
18
+ "locator.role",
19
+ "locator.text",
20
+ "locator.testId",
21
+ "locator.label",
22
+ "locator.placeholder",
23
+ "locator.altText",
24
+ "locator.title",
25
+ "locator.first",
26
+ "locator.nth",
27
+ "locator.count",
28
+ "locator.waitFor",
29
+ "locator.textContent",
30
+ "locator.inputValue",
31
+ "locator.getAttribute",
32
+ "locator.isVisible",
33
+ "locator.click",
34
+ "locator.fill",
35
+ "locator.press",
36
+ "locator.hover",
37
+ "locator.focus",
38
+ "locator.check",
39
+ "locator.uncheck",
40
+ "locator.selectOption",
41
+ "locator.boundingBox",
42
+ "locator.dragTo",
43
+ "page.mouse",
44
+ "page.mouse.wheel",
45
+ "page.on.console",
46
+ "page.on.pageerror",
47
+ "page.consoleMessages",
48
+ "page.pageErrors",
49
+ "page.screenshot.png",
50
+ "page.evaluate"
51
+ ]);
52
+ var REVISION_KEY = "__supercodeBrowserRevision";
53
+ function installRevisionCounter(key) {
54
+ const scope = globalThis;
55
+ if (typeof scope[key] === "number") return;
56
+ scope[key] = 0;
57
+ new MutationObserver(() => {
58
+ scope[key] = scope[key] + 1;
59
+ }).observe(document, { attributes: true, childList: true, characterData: true, subtree: true });
60
+ }
61
+ function inspectInPage({ elements, limit }) {
62
+ const normalize = (value) => value.replace(/\s+/g, " ").trim();
63
+ const implied = (element) => {
64
+ const tag = element.tagName.toLowerCase();
65
+ if (tag === "button") return "button";
66
+ if (tag === "a" && element.hasAttribute("href")) return "link";
67
+ if (/^h[1-6]$/.test(tag)) return "heading";
68
+ if (tag === "textarea") return "textbox";
69
+ if (tag === "select") return "combobox";
70
+ if (tag === "option") return "option";
71
+ if (tag === "img") return "img";
72
+ if (tag === "ul" || tag === "ol") return "list";
73
+ if (tag === "li") return "listitem";
74
+ if (tag === "nav") return "navigation";
75
+ if (tag === "main") return "main";
76
+ if (tag === "form") return "form";
77
+ if (tag === "input") {
78
+ const type = (element.getAttribute("type") ?? "text").toLowerCase();
79
+ if (type === "button" || type === "submit" || type === "reset") return "button";
80
+ if (type === "checkbox") return "checkbox";
81
+ if (type === "radio") return "radio";
82
+ if (type === "range") return "slider";
83
+ return "textbox";
84
+ }
85
+ return null;
86
+ };
87
+ const nameOf = (element) => {
88
+ const aria = element.getAttribute("aria-label");
89
+ if (aria?.trim()) return normalize(aria);
90
+ const ids = element.getAttribute("aria-labelledby")?.split(/\s+/).filter(Boolean) ?? [];
91
+ const labelled = normalize(ids.map((id) => element.ownerDocument.getElementById(id)?.textContent ?? "").join(" "));
92
+ if (labelled) return labelled;
93
+ if (element instanceof HTMLInputElement && element.labels?.length) {
94
+ const label = normalize(Array.from(element.labels).map((candidate) => candidate.textContent ?? "").join(" "));
95
+ if (label) return label;
96
+ }
97
+ for (const attribute of ["alt", "title", "placeholder"]) {
98
+ const value = element.getAttribute(attribute);
99
+ if (value?.trim()) return normalize(value);
100
+ }
101
+ return normalize(element.textContent ?? "");
102
+ };
103
+ const visible = (element) => {
104
+ if (element.getAttribute("aria-hidden") === "true") return false;
105
+ if (!(element instanceof HTMLElement)) return true;
106
+ if (element.hidden) return false;
107
+ const style = getComputedStyle(element);
108
+ return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0";
109
+ };
110
+ return elements.slice(0, limit).map((element) => {
111
+ const role = element.getAttribute("role")?.trim() || implied(element);
112
+ const name = nameOf(element).slice(0, 500);
113
+ const value = element instanceof HTMLInputElement ? element.type === "password" ? "<redacted>" : element.value : element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement ? element.value : void 0;
114
+ const checked = element instanceof HTMLInputElement && (element.type === "checkbox" || element.type === "radio") ? element.checked : void 0;
115
+ return {
116
+ tag: element.tagName.toLowerCase(),
117
+ ...role ? { role } : {},
118
+ ...name ? { name } : {},
119
+ ...value !== void 0 ? { value: value.slice(0, 2e3) } : {},
120
+ disabled: (element instanceof HTMLButtonElement || element instanceof HTMLInputElement || element instanceof HTMLSelectElement) && element.disabled,
121
+ ...checked !== void 0 ? { checked } : {},
122
+ visible: visible(element)
123
+ };
124
+ });
125
+ }
126
+ function scrollInPage(delta) {
127
+ const amount = delta.amount ?? Math.max(240, Math.round(window.innerHeight * 0.8));
128
+ window.scrollBy({ left: delta.left * amount, top: delta.top * amount, behavior: "instant" });
129
+ return { x: window.scrollX, y: window.scrollY };
130
+ }
131
+ function pngSize(bytes) {
132
+ const signature = [137, 80, 78, 71, 13, 10, 26, 10];
133
+ if (bytes.length < 24 || !signature.every((byte, index) => bytes[index] === byte)) return null;
134
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
135
+ return { width: view.getUint32(16), height: view.getUint32(20) };
136
+ }
137
+ function base64(bytes) {
138
+ let binary = "";
139
+ for (let offset = 0; offset < bytes.length; offset += 32768)
140
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
141
+ return btoa(binary);
142
+ }
143
+ function serializableValue(value, syntheticEvents) {
144
+ if (value === void 0) return null;
145
+ const replacer = (_key, item) => {
146
+ const bytes = item instanceof Uint8Array ? item : item && typeof item === "object" && item.type === "Buffer" && Array.isArray(item.data) ? Uint8Array.from(item.data) : null;
147
+ if (!bytes) return item;
148
+ const size = pngSize(bytes);
149
+ const encoded = base64(bytes);
150
+ if (!size) return encoded;
151
+ const dataUrl = `data:image/png;base64,${encoded}`;
152
+ if (dataUrl.length > 768 * 1024) return { error: "Screenshot exceeds the 768 KiB image record bound.", width: size.width, height: size.height };
153
+ return {
154
+ dataUrl,
155
+ format: "png",
156
+ width: size.width,
157
+ height: size.height,
158
+ fidelity: syntheticEvents ? "Pixels rasterized by the CDP endpoint's own renderer." : "Native Chrome pixels captured over CDP."
159
+ };
160
+ };
161
+ try {
162
+ return JSON.parse(JSON.stringify(value, replacer));
163
+ } catch {
164
+ return String(value);
165
+ }
166
+ }
167
+ function errorMessage(error) {
168
+ return error instanceof Error ? error.message : String(error);
169
+ }
170
+ function classifyPlaywrightError(error) {
171
+ if (error instanceof BrowserActionRefusal) return error.code;
172
+ if (error instanceof errors.TimeoutError) return "TIMED_OUT";
173
+ const message = errorMessage(error);
174
+ if (/has been closed|Target closed|Target page, context or browser|Browser closed|browser has disconnected|Session closed|detached/i.test(message))
175
+ return "NOT_AVAILABLE";
176
+ if (/strict mode violation|resolved to 0 elements|no element matches|matched no element/i.test(message))
177
+ return "NOT_FOUND";
178
+ if (/unavailable|not supported/i.test(message)) return "UNSUPPORTED";
179
+ return "FAILED";
180
+ }
181
+ var PlaywrightOperationExecutor = class {
182
+ page;
183
+ options;
184
+ ready;
185
+ constructor(page, options) {
186
+ this.page = page;
187
+ this.options = options;
188
+ this.ready = (async () => {
189
+ await page.addInitScript(installRevisionCounter, REVISION_KEY);
190
+ await page.evaluate(installRevisionCounter, REVISION_KEY).catch(() => void 0);
191
+ })();
192
+ }
193
+ async execute(raw) {
194
+ const call = parseBrowserOperationCall(raw);
195
+ const operation = operationName(raw);
196
+ if (!call) return this.failure(operation, "INVALID_INPUT", "Invalid browser operation request.");
197
+ try {
198
+ await this.ready;
199
+ return await this.executeCall(call);
200
+ } catch (error) {
201
+ return this.failure(call.operation, classifyPlaywrightError(error), errorMessage(error));
202
+ }
203
+ }
204
+ locator(value, index) {
205
+ const locator = value;
206
+ const exact = (candidate) => candidate.exact !== void 0 ? { exact: candidate.exact } : {};
207
+ const page = this.page;
208
+ const base = locator.by === "css" ? page.locator(locator.value) : locator.by === "ref" ? page.locator(`aria-ref=${locator.value}`) : locator.by === "role" ? page.getByRole(locator.role, {
209
+ ...locator.name !== void 0 ? { name: locator.name } : {},
210
+ // A role's name matches exactly unless told otherwise.
211
+ exact: locator.exact ?? true
212
+ }) : locator.by === "text" ? page.getByText(locator.text, exact(locator)) : locator.by === "label" ? page.getByLabel(locator.text, exact(locator)) : locator.by === "placeholder" ? page.getByPlaceholder(locator.text, exact(locator)) : locator.by === "altText" ? page.getByAltText(locator.text, exact(locator)) : locator.by === "title" ? page.getByTitle(locator.text, exact(locator)) : page.getByTestId(locator.value);
213
+ return index === void 0 ? base : index === 0 ? base.first() : base.nth(index);
214
+ }
215
+ /**
216
+ * Playwright's `aria-ref` engine resolves against the last AI-mode snapshot
217
+ * the page took. Refs are stable per element, so refreshing the whole-page
218
+ * snapshot before resolving one keeps every ref from `browser.snapshot`
219
+ * addressable even after an element-scoped snapshot replaced the map.
220
+ */
221
+ async refreshRefs(value) {
222
+ if (value?.by === "ref")
223
+ await this.page.ariaSnapshot({ mode: "ai", timeout: ACTION_TIMEOUT_MS });
224
+ }
225
+ async refOf(locator) {
226
+ try {
227
+ const nodes = await locator.ariaSnapshotJSON({ mode: "ai", depth: 1, timeout: ACTION_TIMEOUT_MS });
228
+ const first = Array.isArray(nodes) ? nodes.find((node) => node && typeof node === "object") : void 0;
229
+ return typeof first?.ref === "string" ? first.ref : "";
230
+ } catch {
231
+ return "";
232
+ }
233
+ }
234
+ async inspectAll(locator, limit) {
235
+ const handles = (await locator.elementHandles()).slice(0, limit);
236
+ let fields;
237
+ try {
238
+ const inspect = inspectInPage;
239
+ fields = await this.page.evaluate(inspect, { elements: handles, limit });
240
+ } finally {
241
+ await Promise.all(handles.map((handle) => handle.dispose().catch(() => void 0)));
242
+ }
243
+ const refs = await Promise.all(fields.map((_, index) => this.refOf(locator.nth(index))));
244
+ return fields.map((field, index) => ({ ref: refs[index] ?? "", ...field }));
245
+ }
246
+ async inspect(locator) {
247
+ const [inspection] = await this.inspectAll(locator.first(), 1);
248
+ if (!inspection) throw new BrowserActionRefusal("NOT_FOUND", "The locator matched no element.");
249
+ return inspection;
250
+ }
251
+ /** Run a locator action; a failure on a locator that matches nothing is NOT_FOUND. */
252
+ async act(locator, action, run) {
253
+ try {
254
+ return await run();
255
+ } catch (error) {
256
+ if (!(error instanceof BrowserActionRefusal) && await locator.count().catch(() => 1) === 0)
257
+ throw new BrowserActionRefusal("NOT_FOUND", `${action} found no element for the locator.`);
258
+ throw error;
259
+ }
260
+ }
261
+ /** The host's policy for an action; an element that is not there is the action's own failure. */
262
+ async guard(action) {
263
+ if (!this.options.actionGuard || await action.locator.count().catch(() => 0) === 0) return;
264
+ await this.options.actionGuard(action);
265
+ }
266
+ async revision() {
267
+ const value = await this.page.evaluate((key) => globalThis[key], REVISION_KEY).catch(() => void 0);
268
+ return typeof value === "number" ? value : 0;
269
+ }
270
+ async executeCall(call) {
271
+ const input = call.input;
272
+ const page = this.page;
273
+ const expectedRevision = typeof input.expectedRevision === "number" ? input.expectedRevision : void 0;
274
+ if (expectedRevision !== void 0) {
275
+ const current = await this.revision();
276
+ if (expectedRevision !== current)
277
+ return this.failure(call.operation, "STALE_PAGE", `The page changed (expected revision ${expectedRevision}, current revision ${current}).`);
278
+ }
279
+ if (call.operation === "browser.status")
280
+ return this.success(call.operation, {
281
+ available: true,
282
+ features: PLAYWRIGHT_FEATURES,
283
+ syntheticEvents: this.options.syntheticEvents,
284
+ implementation: PLAYWRIGHT_IMPLEMENTATION,
285
+ endpoint: this.options.endpoint
286
+ });
287
+ if (call.operation === "browser.snapshot") {
288
+ await this.refreshRefs(input.locator);
289
+ const scoped = input.locator ? this.locator(input.locator).first() : null;
290
+ const text = scoped ? await this.act(scoped, "ariaSnapshot", () => scoped.ariaSnapshot({ mode: "ai", timeout: ACTION_TIMEOUT_MS })) : await page.ariaSnapshot({ mode: "ai", timeout: ACTION_TIMEOUT_MS });
291
+ const bounded = text.slice(0, 64e3);
292
+ return this.success(call.operation, { text: bounded, truncated: bounded.length < text.length });
293
+ }
294
+ if (call.operation === "browser.query") {
295
+ await this.refreshRefs(input.locator);
296
+ const locator2 = this.locator(input.locator, typeof input.index === "number" ? input.index : void 0);
297
+ const count = await locator2.count();
298
+ return this.success(call.operation, { count, matches: await this.inspectAll(locator2, 50), truncated: count > 50 });
299
+ }
300
+ if (call.operation === "browser.wait") {
301
+ await this.refreshRefs(input.locator);
302
+ const requested = typeof input.timeout === "number" ? input.timeout : 5e3;
303
+ const timeout2 = Math.min(requested, WAIT_TIMEOUT_CLAMP_MS);
304
+ const locator2 = this.locator(input.locator, typeof input.index === "number" ? input.index : 0);
305
+ try {
306
+ await locator2.waitFor({ state: input.state === "attached" ? "attached" : "visible", timeout: timeout2 });
307
+ } catch (error) {
308
+ if (error instanceof errors.TimeoutError)
309
+ throw new BrowserActionRefusal("TIMED_OUT", `waitFor timed out after ${timeout2}ms` + (timeout2 < requested ? ` (the requested ${requested}ms is clamped to ${WAIT_TIMEOUT_CLAMP_MS}ms by the provider call deadline)` : "") + ".");
310
+ throw error;
311
+ }
312
+ return this.success(call.operation, { ready: true });
313
+ }
314
+ if (call.operation === "browser.scroll") {
315
+ const direction = input.direction;
316
+ const position = await page.evaluate(scrollInPage, {
317
+ left: direction === "left" ? -1 : direction === "right" ? 1 : 0,
318
+ top: direction === "up" ? -1 : direction === "down" ? 1 : 0,
319
+ amount: typeof input.amount === "number" ? input.amount : null
320
+ });
321
+ return this.success(call.operation, position);
322
+ }
323
+ if (call.operation === "browser.script") return this.script(call);
324
+ if (call.operation === "browser.mouse") {
325
+ const action = input.action;
326
+ if (action === "move") await page.mouse.move(input.x, input.y);
327
+ else if (action === "click") await page.mouse.click(input.x, input.y);
328
+ else if (action === "down") await page.mouse.down();
329
+ else await page.mouse.up();
330
+ return this.success(call.operation, { action, ...typeof input.x === "number" ? { x: input.x, y: input.y } : {} });
331
+ }
332
+ if (call.operation === "browser.wheel") {
333
+ const deltaX = typeof input.deltaX === "number" ? input.deltaX : 0;
334
+ const deltaY = typeof input.deltaY === "number" ? input.deltaY : 0;
335
+ await page.mouse.wheel(deltaX, deltaY);
336
+ return this.success(call.operation, { deltaX, deltaY });
337
+ }
338
+ if (call.operation === "browser.drag") {
339
+ const resolve = async (endpoint) => {
340
+ if (endpoint.locator === void 0) return { x: endpoint.x, y: endpoint.y };
341
+ await this.refreshRefs(endpoint.locator);
342
+ const locator2 = this.locator(endpoint.locator).first();
343
+ const box = await locator2.count() === 0 ? null : await locator2.boundingBox({ timeout: ACTION_TIMEOUT_MS });
344
+ if (!box) throw new BrowserActionRefusal("NOT_FOUND", "The drag locator matched no element.");
345
+ return { x: box.x + box.width / 2, y: box.y + box.height / 2 };
346
+ };
347
+ for (const end of [input.from, input.to])
348
+ if (end.locator !== void 0) await this.guard({ action: "drag", locator: this.locator(end.locator).first() });
349
+ const from = await resolve(input.from);
350
+ const to = await resolve(input.to);
351
+ await page.mouse.move(from.x, from.y);
352
+ await page.mouse.down();
353
+ await page.mouse.move(to.x, to.y, { steps: typeof input.steps === "number" ? input.steps : 8 });
354
+ await page.mouse.up();
355
+ return this.success(call.operation, { from, to });
356
+ }
357
+ if (call.operation === "browser.back") {
358
+ await page.goBack({ waitUntil: "commit", timeout: ACTION_TIMEOUT_MS });
359
+ return this.success(call.operation, { requested: true });
360
+ }
361
+ if (call.operation === "browser.forward") {
362
+ await page.goForward({ waitUntil: "commit", timeout: ACTION_TIMEOUT_MS });
363
+ return this.success(call.operation, { requested: true });
364
+ }
365
+ if (call.operation === "browser.reload") {
366
+ await page.reload({ waitUntil: "commit", timeout: ACTION_TIMEOUT_MS });
367
+ return this.success(call.operation, { requested: true });
368
+ }
369
+ await this.refreshRefs(input.locator);
370
+ const locator = input.locator ? this.locator(input.locator, typeof input.index === "number" ? input.index : 0) : null;
371
+ const timeout = ACTION_TIMEOUT_MS;
372
+ if (call.operation === "browser.box") {
373
+ const box = await locator.count() === 0 ? null : await locator.boundingBox({ timeout });
374
+ if (!box) return this.failure(call.operation, "NOT_FOUND", "The locator matched no element.");
375
+ return this.success(call.operation, box);
376
+ }
377
+ if (call.operation === "browser.press" && !locator) {
378
+ await this.guard({ action: "press", locator: page.locator("*:focus").first(), value: input.key });
379
+ await page.keyboard.press(input.key);
380
+ return this.success(call.operation, { key: input.key });
381
+ }
382
+ const target = locator;
383
+ const guarded = call.operation === "browser.select" ? "select" : call.operation.slice("browser.".length);
384
+ await this.guard({
385
+ action: guarded,
386
+ locator: target.first(),
387
+ ...call.operation === "browser.fill" ? { value: input.value } : call.operation === "browser.press" ? { value: input.key } : call.operation === "browser.select" ? { value: input.values } : {}
388
+ });
389
+ const before = await this.inspect(target).catch(() => null);
390
+ if (call.operation === "browser.click") await this.act(target, "click", () => target.click({ timeout }));
391
+ else if (call.operation === "browser.fill") await this.act(target, "fill", () => target.fill(input.value, { timeout }));
392
+ else if (call.operation === "browser.press") await this.act(target, "press", () => target.press(input.key, { timeout }));
393
+ else if (call.operation === "browser.hover") await this.act(target, "hover", () => target.hover({ timeout }));
394
+ else if (call.operation === "browser.focus") await this.act(target, "focus", () => target.focus({ timeout }));
395
+ else if (call.operation === "browser.check") await this.act(target, "check", () => target.check({ timeout }));
396
+ else if (call.operation === "browser.uncheck") await this.act(target, "uncheck", () => target.uncheck({ timeout }));
397
+ else if (call.operation === "browser.select") {
398
+ const values = await this.act(target, "selectOption", () => target.selectOption(input.values, { timeout }));
399
+ return this.success(call.operation, { values });
400
+ }
401
+ const after = await this.inspect(target).catch(() => null);
402
+ const inspection = after ?? before;
403
+ if (!inspection) throw new BrowserActionRefusal("NOT_FOUND", "The locator matched no element.");
404
+ return this.success(call.operation, inspection);
405
+ }
406
+ async script(call) {
407
+ const input = call.input;
408
+ const source = input.source;
409
+ const args = input.args ?? {};
410
+ const requested = typeof input.timeout === "number" ? input.timeout : 3e4;
411
+ const timeout = Math.min(requested, SCRIPT_TIMEOUT_CLAMP_MS);
412
+ const AsyncFunction = Object.getPrototypeOf(async function() {
413
+ }).constructor;
414
+ let run;
415
+ try {
416
+ run = new AsyncFunction("page", "args", source);
417
+ } catch (error) {
418
+ return this.failure(call.operation, "FAILED", `The script did not parse: ${errorMessage(error)}`);
419
+ }
420
+ const notice = timeout < requested ? `The script timeout is clamped to ${SCRIPT_TIMEOUT_CLAMP_MS}ms: the harness abandons a provider call at 12 s.` : void 0;
421
+ let timer;
422
+ try {
423
+ const value = await Promise.race([
424
+ run(this.page, args),
425
+ new Promise((_resolve, reject) => {
426
+ timer = setTimeout(() => reject(new BrowserActionRefusal("FAILED", `The script exceeded ${timeout}ms.` + (notice ? ` ${notice}` : ""))), timeout);
427
+ })
428
+ ]);
429
+ return this.success(call.operation, {
430
+ value: serializableValue(value, this.options.syntheticEvents),
431
+ ...notice ? { notice } : {}
432
+ });
433
+ } finally {
434
+ clearTimeout(timer);
435
+ this.page.removeAllListeners();
436
+ }
437
+ }
438
+ async target() {
439
+ if (this.page.isClosed()) return { url: "", title: "", revision: 0 };
440
+ const bounded = (promise, fallback) => {
441
+ let timer;
442
+ return Promise.race([
443
+ promise.catch(() => fallback),
444
+ new Promise((resolve) => {
445
+ timer = setTimeout(() => resolve(fallback), 1e3);
446
+ })
447
+ ]).finally(() => clearTimeout(timer));
448
+ };
449
+ const [title, revision] = await Promise.all([
450
+ bounded(this.page.title(), ""),
451
+ bounded(this.revision(), 0)
452
+ ]);
453
+ return { url: this.page.url(), title, revision };
454
+ }
455
+ async success(operation, value) {
456
+ return { ok: true, operation, target: await this.target(), value };
457
+ }
458
+ async failure(operation, code, message) {
459
+ return { ok: false, operation, error: { code, message }, target: await this.target() };
460
+ }
461
+ };
462
+ function operationName(raw) {
463
+ const candidate = raw && typeof raw === "object" && !Array.isArray(raw) ? raw.operation : void 0;
464
+ return typeof candidate === "string" && BROWSER_OPERATION_NAMES.includes(candidate) ? candidate : "browser.status";
465
+ }
466
+ export {
467
+ ACTION_TIMEOUT_MS,
468
+ PLAYWRIGHT_FEATURES,
469
+ PLAYWRIGHT_IMPLEMENTATION,
470
+ PlaywrightOperationExecutor,
471
+ SCRIPT_TIMEOUT_CLAMP_MS,
472
+ WAIT_TIMEOUT_CLAMP_MS,
473
+ classifyPlaywrightError
474
+ };
475
+ //# sourceMappingURL=executor.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/executor.ts"],
4
+ "sourcesContent": ["/**\n * Supercode's `supercode/browser-operation-v1` calls over a real Playwright\n * `Page`: every locator, action and snapshot is playwright-core's own, driven\n * over CDP. No Node API is used, so the executor also runs in a browser realm\n * with a browser build of playwright-core (`@volter/almostcdp/playwright`).\n */\n\nimport { errors, type Locator, type Page } from \"playwright-core\";\nimport {\n BROWSER_OPERATION_NAMES,\n BrowserActionRefusal,\n parseBrowserOperationCall,\n type BrowserLocator,\n type BrowserOperationCall,\n type BrowserOperationErrorCode,\n type BrowserOperationName,\n type BrowserOperationResult,\n type BrowserTarget,\n type ElementInspection,\n} from \"./protocol.js\";\n\n/** The implementation this provider reports; the pinned playwright-core. */\nexport const PLAYWRIGHT_IMPLEMENTATION = \"playwright-core 1.63.0\";\n/** The harness abandons a provider call at 12 s; a script must end before that. */\nexport const SCRIPT_TIMEOUT_CLAMP_MS = 9_000;\n/** Actionability budget for one locator action. */\nexport const ACTION_TIMEOUT_MS = 5_000;\n/** `browser.wait` accepts 30 s on the wire; the harness deadline caps what can be honoured. */\nexport const WAIT_TIMEOUT_CLAMP_MS = 9_000;\n\n/** The Playwright features `browser.status` reports. */\nexport const PLAYWRIGHT_FEATURES: readonly string[] = Object.freeze([\n \"page.ariaSnapshot\",\n \"page.keyboard\",\n \"page.navigation.history\",\n \"locator.css\",\n \"locator.ref\",\n \"locator.role\",\n \"locator.text\",\n \"locator.testId\",\n \"locator.label\",\n \"locator.placeholder\",\n \"locator.altText\",\n \"locator.title\",\n \"locator.first\",\n \"locator.nth\",\n \"locator.count\",\n \"locator.waitFor\",\n \"locator.textContent\",\n \"locator.inputValue\",\n \"locator.getAttribute\",\n \"locator.isVisible\",\n \"locator.click\",\n \"locator.fill\",\n \"locator.press\",\n \"locator.hover\",\n \"locator.focus\",\n \"locator.check\",\n \"locator.uncheck\",\n \"locator.selectOption\",\n \"locator.boundingBox\",\n \"locator.dragTo\",\n \"page.mouse\",\n \"page.mouse.wheel\",\n \"page.on.console\",\n \"page.on.pageerror\",\n \"page.consoleMessages\",\n \"page.pageErrors\",\n \"page.screenshot.png\",\n \"page.evaluate\",\n]);\n\nexport interface PlaywrightOperationExecutorOptions {\n /** True when the endpoint dispatches `isTrusted:false` input (an AlmostCDP endpoint); false for native Chrome. */\n syntheticEvents: boolean;\n /** `browser.version()` of the connected endpoint, reported by `browser.status`. */\n endpoint: string;\n /**\n * The host's policy for one locator action, asked before it runs; throwing\n * a `BrowserActionRefusal` refuses it with that code. `browser.script` is\n * not guarded: a script is trusted with the page.\n */\n actionGuard?: (action: PlaywrightAction) => void | Promise<void>;\n}\n\n/** One locator action an operation is about to perform. */\nexport interface PlaywrightAction {\n action: \"click\" | \"fill\" | \"press\" | \"hover\" | \"focus\" | \"check\" | \"uncheck\" | \"select\" | \"drag\";\n locator: Locator;\n value?: unknown;\n}\n\n\nconst REVISION_KEY = \"__supercodeBrowserRevision\";\n\n/**\n * Keeps a document-mutation counter on the page's main world. Installed as an\n * init script (every future document) and evaluated once (the current one).\n * Self-contained: Playwright serializes it into the page.\n */\nfunction installRevisionCounter(key: string): void {\n const scope = globalThis as unknown as Record<string, unknown>;\n if (typeof scope[key] === \"number\") return;\n scope[key] = 0;\n new MutationObserver(() => { scope[key] = (scope[key] as number) + 1; })\n .observe(document, { attributes: true, childList: true, characterData: true, subtree: true });\n}\n\n/**\n * `ElementInspection`'s fields except `ref`, computed in the page.\n * Self-contained: Playwright serializes it into the page.\n */\nfunction inspectInPage({ elements, limit }: { elements: Element[]; limit: number }): Array<Omit<ElementInspection, \"ref\">> {\n const normalize = (value: string): string => value.replace(/\\s+/g, \" \").trim();\n const implied = (element: Element): string | null => {\n const tag = element.tagName.toLowerCase();\n if (tag === \"button\") return \"button\";\n if (tag === \"a\" && element.hasAttribute(\"href\")) return \"link\";\n if (/^h[1-6]$/.test(tag)) return \"heading\";\n if (tag === \"textarea\") return \"textbox\";\n if (tag === \"select\") return \"combobox\";\n if (tag === \"option\") return \"option\";\n if (tag === \"img\") return \"img\";\n if (tag === \"ul\" || tag === \"ol\") return \"list\";\n if (tag === \"li\") return \"listitem\";\n if (tag === \"nav\") return \"navigation\";\n if (tag === \"main\") return \"main\";\n if (tag === \"form\") return \"form\";\n if (tag === \"input\") {\n const type = (element.getAttribute(\"type\") ?? \"text\").toLowerCase();\n if (type === \"button\" || type === \"submit\" || type === \"reset\") return \"button\";\n if (type === \"checkbox\") return \"checkbox\";\n if (type === \"radio\") return \"radio\";\n if (type === \"range\") return \"slider\";\n return \"textbox\";\n }\n return null;\n };\n const nameOf = (element: Element): string => {\n const aria = element.getAttribute(\"aria-label\");\n if (aria?.trim()) return normalize(aria);\n const ids = element.getAttribute(\"aria-labelledby\")?.split(/\\s+/).filter(Boolean) ?? [];\n const labelled = normalize(ids.map((id) => element.ownerDocument.getElementById(id)?.textContent ?? \"\").join(\" \"));\n if (labelled) return labelled;\n if (element instanceof HTMLInputElement && element.labels?.length) {\n const label = normalize(Array.from(element.labels).map((candidate) => candidate.textContent ?? \"\").join(\" \"));\n if (label) return label;\n }\n for (const attribute of [\"alt\", \"title\", \"placeholder\"]) {\n const value = element.getAttribute(attribute);\n if (value?.trim()) return normalize(value);\n }\n return normalize(element.textContent ?? \"\");\n };\n const visible = (element: Element): boolean => {\n if (element.getAttribute(\"aria-hidden\") === \"true\") return false;\n if (!(element instanceof HTMLElement)) return true;\n if (element.hidden) return false;\n const style = getComputedStyle(element);\n return style.display !== \"none\" && style.visibility !== \"hidden\" && style.opacity !== \"0\";\n };\n return elements.slice(0, limit).map((element) => {\n const role = element.getAttribute(\"role\")?.trim() || implied(element);\n const name = nameOf(element).slice(0, 500);\n const value = element instanceof HTMLInputElement\n ? (element.type === \"password\" ? \"<redacted>\" : element.value)\n : element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement ? element.value : undefined;\n const checked = element instanceof HTMLInputElement &&\n (element.type === \"checkbox\" || element.type === \"radio\") ? element.checked : undefined;\n return {\n tag: element.tagName.toLowerCase(),\n ...(role ? { role } : {}),\n ...(name ? { name } : {}),\n ...(value !== undefined ? { value: value.slice(0, 2_000) } : {}),\n disabled: (element instanceof HTMLButtonElement || element instanceof HTMLInputElement ||\n element instanceof HTMLSelectElement) && element.disabled,\n ...(checked !== undefined ? { checked } : {}),\n visible: visible(element),\n };\n });\n}\n\nfunction scrollInPage(delta: { left: number; top: number; amount: number | null }): { x: number; y: number } {\n const amount = delta.amount ?? Math.max(240, Math.round(window.innerHeight * 0.8));\n window.scrollBy({ left: delta.left * amount, top: delta.top * amount, behavior: \"instant\" });\n return { x: window.scrollX, y: window.scrollY };\n}\n\n/** A PNG's pixel size from its IHDR chunk. */\nfunction pngSize(bytes: Uint8Array): { width: number; height: number } | null {\n const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n if (bytes.length < 24 || !signature.every((byte, index) => bytes[index] === byte)) return null;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n return { width: view.getUint32(16), height: view.getUint32(20) };\n}\n\n/** Base64 of bytes without Node's Buffer. */\nfunction base64(bytes: Uint8Array): string {\n let binary = \"\";\n for (let offset = 0; offset < bytes.length; offset += 0x8000)\n binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));\n return btoa(binary);\n}\n\n/**\n * Scripts return data, not live objects: keep the wire JSON-clean. Screenshot\n * bytes become a bounded image record rather than a JSON array of numbers.\n */\nfunction serializableValue(value: unknown, syntheticEvents: boolean): unknown {\n if (value === undefined) return null;\n const replacer = (_key: string, item: unknown): unknown => {\n const bytes = item instanceof Uint8Array ? item\n : item && typeof item === \"object\" && (item as { type?: unknown }).type === \"Buffer\" &&\n Array.isArray((item as { data?: unknown }).data) ? Uint8Array.from((item as { data: number[] }).data)\n : null;\n if (!bytes) return item;\n const size = pngSize(bytes);\n const encoded = base64(bytes);\n if (!size) return encoded;\n const dataUrl = `data:image/png;base64,${encoded}`;\n if (dataUrl.length > 768 * 1024) return { error: \"Screenshot exceeds the 768 KiB image record bound.\", width: size.width, height: size.height };\n return {\n dataUrl,\n format: \"png\",\n width: size.width,\n height: size.height,\n fidelity: syntheticEvents\n ? \"Pixels rasterized by the CDP endpoint's own renderer.\"\n : \"Native Chrome pixels captured over CDP.\",\n };\n };\n try {\n return JSON.parse(JSON.stringify(value, replacer));\n } catch {\n return String(value);\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Map a Playwright failure onto the wire's error codes. */\nexport function classifyPlaywrightError(error: unknown): BrowserOperationErrorCode {\n if (error instanceof BrowserActionRefusal) return error.code;\n if (error instanceof errors.TimeoutError) return \"TIMED_OUT\";\n const message = errorMessage(error);\n if (/has been closed|Target closed|Target page, context or browser|Browser closed|browser has disconnected|Session closed|detached/i.test(message))\n return \"NOT_AVAILABLE\";\n if (/strict mode violation|resolved to 0 elements|no element matches|matched no element/i.test(message))\n return \"NOT_FOUND\";\n if (/unavailable|not supported/i.test(message)) return \"UNSUPPORTED\";\n return \"FAILED\";\n}\n\nexport class PlaywrightOperationExecutor {\n private readonly page: Page;\n private readonly options: PlaywrightOperationExecutorOptions;\n private readonly ready: Promise<void>;\n\n constructor(page: Page, options: PlaywrightOperationExecutorOptions) {\n this.page = page;\n this.options = options;\n this.ready = (async () => {\n await page.addInitScript(installRevisionCounter, REVISION_KEY);\n await page.evaluate(installRevisionCounter, REVISION_KEY).catch(() => undefined);\n })();\n }\n\n async execute(raw: unknown): Promise<BrowserOperationResult> {\n const call = parseBrowserOperationCall(raw);\n const operation = operationName(raw);\n if (!call) return this.failure(operation, \"INVALID_INPUT\", \"Invalid browser operation request.\");\n try {\n await this.ready;\n return await this.executeCall(call);\n } catch (error) {\n return this.failure(call.operation, classifyPlaywrightError(error), errorMessage(error));\n }\n }\n\n private locator(value: unknown, index?: number): Locator {\n const locator = value as BrowserLocator;\n const exact = (candidate: { exact?: boolean }) => candidate.exact !== undefined ? { exact: candidate.exact } : {};\n const page = this.page;\n const base = locator.by === \"css\" ? page.locator(locator.value)\n // Refs are the `[ref=\u2026]` marks of an AI-mode aria snapshot, resolved by\n // Playwright's built-in `aria-ref` selector engine.\n : locator.by === \"ref\" ? page.locator(`aria-ref=${locator.value}`)\n : locator.by === \"role\" ? page.getByRole(locator.role as Parameters<Page[\"getByRole\"]>[0], {\n ...(locator.name !== undefined ? { name: locator.name } : {}),\n // A role's name matches exactly unless told otherwise.\n exact: locator.exact ?? true,\n })\n : locator.by === \"text\" ? page.getByText(locator.text, exact(locator))\n : locator.by === \"label\" ? page.getByLabel(locator.text, exact(locator))\n : locator.by === \"placeholder\" ? page.getByPlaceholder(locator.text, exact(locator))\n : locator.by === \"altText\" ? page.getByAltText(locator.text, exact(locator))\n : locator.by === \"title\" ? page.getByTitle(locator.text, exact(locator))\n : page.getByTestId(locator.value);\n return index === undefined ? base : index === 0 ? base.first() : base.nth(index);\n }\n\n /**\n * Playwright's `aria-ref` engine resolves against the last AI-mode snapshot\n * the page took. Refs are stable per element, so refreshing the whole-page\n * snapshot before resolving one keeps every ref from `browser.snapshot`\n * addressable even after an element-scoped snapshot replaced the map.\n */\n private async refreshRefs(value: unknown): Promise<void> {\n if ((value as BrowserLocator | undefined)?.by === \"ref\")\n await this.page.ariaSnapshot({ mode: \"ai\", timeout: ACTION_TIMEOUT_MS });\n }\n\n private async refOf(locator: Locator): Promise<string> {\n try {\n const nodes = await locator.ariaSnapshotJSON({ mode: \"ai\", depth: 1, timeout: ACTION_TIMEOUT_MS }) as unknown;\n const first = Array.isArray(nodes) ? nodes.find((node) => node && typeof node === \"object\") as { ref?: unknown } | undefined : undefined;\n return typeof first?.ref === \"string\" ? first.ref : \"\";\n } catch {\n return \"\";\n }\n }\n\n private async inspectAll(locator: Locator, limit: number): Promise<ElementInspection[]> {\n // Element handles, not `evaluateAll`: Playwright's `evaluateAll` resolves an\n // `aria-ref` locator in the main world, where the snapshot's refs are not\n // known, and finds nothing (measured with Playwright 1.63 on Chrome).\n const handles = (await locator.elementHandles()).slice(0, limit);\n let fields: Array<Omit<ElementInspection, \"ref\">>;\n try {\n const inspect = inspectInPage as unknown as (input: { elements: unknown[]; limit: number }) => Array<Omit<ElementInspection, \"ref\">>;\n fields = await this.page.evaluate(inspect, { elements: handles as unknown[], limit });\n } finally {\n await Promise.all(handles.map((handle) => handle.dispose().catch(() => undefined)));\n }\n const refs = await Promise.all(fields.map((_, index) => this.refOf(locator.nth(index))));\n return fields.map((field, index) => ({ ref: refs[index] ?? \"\", ...field }));\n }\n\n private async inspect(locator: Locator): Promise<ElementInspection> {\n const [inspection] = await this.inspectAll(locator.first(), 1);\n if (!inspection) throw new BrowserActionRefusal(\"NOT_FOUND\", \"The locator matched no element.\");\n return inspection;\n }\n\n /** Run a locator action; a failure on a locator that matches nothing is NOT_FOUND. */\n private async act<T>(locator: Locator, action: string, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error) {\n if (!(error instanceof BrowserActionRefusal) && await locator.count().catch(() => 1) === 0)\n throw new BrowserActionRefusal(\"NOT_FOUND\", `${action} found no element for the locator.`);\n throw error;\n }\n }\n\n /** The host's policy for an action; an element that is not there is the action's own failure. */\n private async guard(action: PlaywrightAction): Promise<void> {\n if (!this.options.actionGuard || await action.locator.count().catch(() => 0) === 0) return;\n await this.options.actionGuard(action);\n }\n\n private async revision(): Promise<number> {\n const value = await this.page.evaluate((key) => (globalThis as unknown as Record<string, unknown>)[key], REVISION_KEY)\n .catch(() => undefined);\n return typeof value === \"number\" ? value : 0;\n }\n\n private async executeCall(call: BrowserOperationCall): Promise<BrowserOperationResult> {\n const input = call.input;\n const page = this.page;\n const expectedRevision = typeof input.expectedRevision === \"number\" ? input.expectedRevision : undefined;\n if (expectedRevision !== undefined) {\n const current = await this.revision();\n if (expectedRevision !== current)\n return this.failure(call.operation, \"STALE_PAGE\", `The page changed (expected revision ${expectedRevision}, current revision ${current}).`);\n }\n if (call.operation === \"browser.status\")\n return this.success(call.operation, {\n available: true,\n features: PLAYWRIGHT_FEATURES,\n syntheticEvents: this.options.syntheticEvents,\n implementation: PLAYWRIGHT_IMPLEMENTATION,\n endpoint: this.options.endpoint,\n });\n if (call.operation === \"browser.snapshot\") {\n await this.refreshRefs(input.locator);\n const scoped = input.locator ? this.locator(input.locator).first() : null;\n const text = scoped\n ? await this.act(scoped, \"ariaSnapshot\", () => scoped.ariaSnapshot({ mode: \"ai\", timeout: ACTION_TIMEOUT_MS }))\n : await page.ariaSnapshot({ mode: \"ai\", timeout: ACTION_TIMEOUT_MS });\n const bounded = text.slice(0, 64_000);\n return this.success(call.operation, { text: bounded, truncated: bounded.length < text.length });\n }\n if (call.operation === \"browser.query\") {\n await this.refreshRefs(input.locator);\n const locator = this.locator(input.locator, typeof input.index === \"number\" ? input.index : undefined);\n const count = await locator.count();\n return this.success(call.operation, { count, matches: await this.inspectAll(locator, 50), truncated: count > 50 });\n }\n if (call.operation === \"browser.wait\") {\n await this.refreshRefs(input.locator);\n const requested = typeof input.timeout === \"number\" ? input.timeout : 5_000;\n const timeout = Math.min(requested, WAIT_TIMEOUT_CLAMP_MS);\n const locator = this.locator(input.locator, typeof input.index === \"number\" ? input.index : 0);\n try {\n await locator.waitFor({ state: input.state === \"attached\" ? \"attached\" : \"visible\", timeout });\n } catch (error) {\n if (error instanceof errors.TimeoutError)\n throw new BrowserActionRefusal(\"TIMED_OUT\", `waitFor timed out after ${timeout}ms` +\n (timeout < requested ? ` (the requested ${requested}ms is clamped to ${WAIT_TIMEOUT_CLAMP_MS}ms by the provider call deadline)` : \"\") + \".\");\n throw error;\n }\n return this.success(call.operation, { ready: true });\n }\n if (call.operation === \"browser.scroll\") {\n const direction = input.direction as \"up\" | \"down\" | \"left\" | \"right\";\n const position = await page.evaluate(scrollInPage, {\n left: direction === \"left\" ? -1 : direction === \"right\" ? 1 : 0,\n top: direction === \"up\" ? -1 : direction === \"down\" ? 1 : 0,\n amount: typeof input.amount === \"number\" ? input.amount : null,\n });\n return this.success(call.operation, position);\n }\n if (call.operation === \"browser.script\") return this.script(call);\n if (call.operation === \"browser.mouse\") {\n const action = input.action as \"move\" | \"down\" | \"up\" | \"click\";\n if (action === \"move\") await page.mouse.move(input.x as number, input.y as number);\n else if (action === \"click\") await page.mouse.click(input.x as number, input.y as number);\n else if (action === \"down\") await page.mouse.down();\n else await page.mouse.up();\n return this.success(call.operation, { action, ...(typeof input.x === \"number\" ? { x: input.x, y: input.y } : {}) });\n }\n if (call.operation === \"browser.wheel\") {\n const deltaX = typeof input.deltaX === \"number\" ? input.deltaX : 0;\n const deltaY = typeof input.deltaY === \"number\" ? input.deltaY : 0;\n await page.mouse.wheel(deltaX, deltaY);\n return this.success(call.operation, { deltaX, deltaY });\n }\n if (call.operation === \"browser.drag\") {\n const resolve = async (endpoint: Record<string, unknown>): Promise<{ x: number; y: number }> => {\n if (endpoint.locator === undefined) return { x: endpoint.x as number, y: endpoint.y as number };\n await this.refreshRefs(endpoint.locator);\n const locator = this.locator(endpoint.locator).first();\n const box = await locator.count() === 0 ? null : await locator.boundingBox({ timeout: ACTION_TIMEOUT_MS });\n if (!box) throw new BrowserActionRefusal(\"NOT_FOUND\", \"The drag locator matched no element.\");\n return { x: box.x + box.width / 2, y: box.y + box.height / 2 };\n };\n for (const end of [input.from, input.to] as Array<Record<string, unknown>>)\n if (end.locator !== undefined) await this.guard({ action: \"drag\", locator: this.locator(end.locator).first() });\n const from = await resolve(input.from as Record<string, unknown>);\n const to = await resolve(input.to as Record<string, unknown>);\n await page.mouse.move(from.x, from.y);\n await page.mouse.down();\n await page.mouse.move(to.x, to.y, { steps: typeof input.steps === \"number\" ? input.steps : 8 });\n await page.mouse.up();\n return this.success(call.operation, { from, to });\n }\n if (call.operation === \"browser.back\") {\n await page.goBack({ waitUntil: \"commit\", timeout: ACTION_TIMEOUT_MS });\n return this.success(call.operation, { requested: true });\n }\n if (call.operation === \"browser.forward\") {\n await page.goForward({ waitUntil: \"commit\", timeout: ACTION_TIMEOUT_MS });\n return this.success(call.operation, { requested: true });\n }\n if (call.operation === \"browser.reload\") {\n await page.reload({ waitUntil: \"commit\", timeout: ACTION_TIMEOUT_MS });\n return this.success(call.operation, { requested: true });\n }\n\n await this.refreshRefs(input.locator);\n const locator = input.locator\n ? this.locator(input.locator, typeof input.index === \"number\" ? input.index : 0)\n : null;\n const timeout = ACTION_TIMEOUT_MS;\n if (call.operation === \"browser.box\") {\n const box = await locator!.count() === 0 ? null : await locator!.boundingBox({ timeout });\n if (!box) return this.failure(call.operation, \"NOT_FOUND\", \"The locator matched no element.\");\n return this.success(call.operation, box);\n }\n if (call.operation === \"browser.press\" && !locator) {\n await this.guard({ action: \"press\", locator: page.locator(\"*:focus\").first(), value: input.key });\n await page.keyboard.press(input.key as string);\n return this.success(call.operation, { key: input.key });\n }\n const target = locator!;\n const guarded = call.operation === \"browser.select\" ? \"select\" : call.operation.slice(\"browser.\".length) as PlaywrightAction[\"action\"];\n await this.guard({ action: guarded, locator: target.first(),\n ...(call.operation === \"browser.fill\" ? { value: input.value } : call.operation === \"browser.press\" ? { value: input.key }\n : call.operation === \"browser.select\" ? { value: input.values } : {}) });\n // The inspection is read after the action; an action that detaches or\n // navigates away from its element reports the element as it was.\n const before = await this.inspect(target).catch(() => null);\n if (call.operation === \"browser.click\") await this.act(target, \"click\", () => target.click({ timeout }));\n else if (call.operation === \"browser.fill\") await this.act(target, \"fill\", () => target.fill(input.value as string, { timeout }));\n else if (call.operation === \"browser.press\") await this.act(target, \"press\", () => target.press(input.key as string, { timeout }));\n else if (call.operation === \"browser.hover\") await this.act(target, \"hover\", () => target.hover({ timeout }));\n else if (call.operation === \"browser.focus\") await this.act(target, \"focus\", () => target.focus({ timeout }));\n else if (call.operation === \"browser.check\") await this.act(target, \"check\", () => target.check({ timeout }));\n else if (call.operation === \"browser.uncheck\") await this.act(target, \"uncheck\", () => target.uncheck({ timeout }));\n else if (call.operation === \"browser.select\") {\n const values = await this.act(target, \"selectOption\", () => target.selectOption(input.values as string[], { timeout }));\n return this.success(call.operation, { values });\n }\n const after = await this.inspect(target).catch(() => null);\n const inspection = after ?? before;\n if (!inspection) throw new BrowserActionRefusal(\"NOT_FOUND\", \"The locator matched no element.\");\n return this.success(call.operation, inspection);\n }\n\n private async script(call: BrowserOperationCall): Promise<BrowserOperationResult> {\n const input = call.input;\n const source = input.source as string;\n const args = (input.args as Record<string, unknown> | undefined) ?? {};\n const requested = typeof input.timeout === \"number\" ? input.timeout : 30_000;\n const timeout = Math.min(requested, SCRIPT_TIMEOUT_CLAMP_MS);\n // Ordinary Playwright, run in this realm with the real `page`.\n const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor as\n new (...parameters: string[]) => (...values: unknown[]) => Promise<unknown>;\n let run: (...values: unknown[]) => Promise<unknown>;\n try {\n run = new AsyncFunction(\"page\", \"args\", source);\n } catch (error) {\n return this.failure(call.operation, \"FAILED\", `The script did not parse: ${errorMessage(error)}`);\n }\n const notice = timeout < requested\n ? `The script timeout is clamped to ${SCRIPT_TIMEOUT_CLAMP_MS}ms: the harness abandons a provider call at 12 s.`\n : undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const value = await Promise.race([\n run(this.page, args),\n new Promise((_resolve, reject) => {\n timer = setTimeout(() => reject(new BrowserActionRefusal(\"FAILED\", `The script exceeded ${timeout}ms.` + (notice ? ` ${notice}` : \"\"))), timeout);\n }),\n ]);\n return this.success(call.operation, {\n value: serializableValue(value, this.options.syntheticEvents),\n ...(notice ? { notice } : {}),\n });\n } finally {\n clearTimeout(timer);\n // Listeners a script attached do not outlive it.\n this.page.removeAllListeners();\n }\n }\n\n private async target(): Promise<BrowserTarget> {\n if (this.page.isClosed()) return { url: \"\", title: \"\", revision: 0 };\n // A page mid-navigation can hold `title()` until its next document exists;\n // the target is a description, so it never outwaits the call.\n const bounded = <T>(promise: Promise<T>, fallback: T): Promise<T> => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return Promise.race([\n promise.catch(() => fallback),\n new Promise<T>((resolve) => { timer = setTimeout(() => resolve(fallback), 1_000); }),\n ]).finally(() => clearTimeout(timer));\n };\n const [title, revision] = await Promise.all([\n bounded(this.page.title(), \"\"),\n bounded(this.revision(), 0),\n ]);\n return { url: this.page.url(), title, revision };\n }\n\n private async success(operation: BrowserOperationName, value: unknown): Promise<BrowserOperationResult> {\n return { ok: true, operation, target: await this.target(), value };\n }\n\n private async failure(operation: BrowserOperationName, code: BrowserOperationErrorCode, message: string): Promise<BrowserOperationResult> {\n return { ok: false, operation, error: { code, message }, target: await this.target() };\n }\n}\n\nfunction operationName(raw: unknown): BrowserOperationName {\n const candidate = raw && typeof raw === \"object\" && !Array.isArray(raw) ? (raw as Record<string, unknown>).operation : undefined;\n return typeof candidate === \"string\" && (BROWSER_OPERATION_NAMES as readonly string[]).includes(candidate)\n ? candidate as BrowserOperationName\n : \"browser.status\";\n}\n"],
5
+ "mappings": ";AAOA,SAAS,cAAuC;AAChD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AAGA,IAAM,4BAA4B;AAElC,IAAM,0BAA0B;AAEhC,IAAM,oBAAoB;AAE1B,IAAM,wBAAwB;AAG9B,IAAM,sBAAyC,OAAO,OAAO;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAuBD,IAAM,eAAe;AAOrB,SAAS,uBAAuB,KAAmB;AACjD,QAAM,QAAQ;AACd,MAAI,OAAO,MAAM,GAAG,MAAM,SAAU;AACpC,QAAM,GAAG,IAAI;AACb,MAAI,iBAAiB,MAAM;AAAE,UAAM,GAAG,IAAK,MAAM,GAAG,IAAe;AAAA,EAAG,CAAC,EACpE,QAAQ,UAAU,EAAE,YAAY,MAAM,WAAW,MAAM,eAAe,MAAM,SAAS,KAAK,CAAC;AAChG;AAMA,SAAS,cAAc,EAAE,UAAU,MAAM,GAAkF;AACzH,QAAM,YAAY,CAAC,UAA0B,MAAM,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC7E,QAAM,UAAU,CAAC,YAAoC;AACnD,UAAM,MAAM,QAAQ,QAAQ,YAAY;AACxC,QAAI,QAAQ,SAAU,QAAO;AAC7B,QAAI,QAAQ,OAAO,QAAQ,aAAa,MAAM,EAAG,QAAO;AACxD,QAAI,WAAW,KAAK,GAAG,EAAG,QAAO;AACjC,QAAI,QAAQ,WAAY,QAAO;AAC/B,QAAI,QAAQ,SAAU,QAAO;AAC7B,QAAI,QAAQ,SAAU,QAAO;AAC7B,QAAI,QAAQ,MAAO,QAAO;AAC1B,QAAI,QAAQ,QAAQ,QAAQ,KAAM,QAAO;AACzC,QAAI,QAAQ,KAAM,QAAO;AACzB,QAAI,QAAQ,MAAO,QAAO;AAC1B,QAAI,QAAQ,OAAQ,QAAO;AAC3B,QAAI,QAAQ,OAAQ,QAAO;AAC3B,QAAI,QAAQ,SAAS;AACnB,YAAM,QAAQ,QAAQ,aAAa,MAAM,KAAK,QAAQ,YAAY;AAClE,UAAI,SAAS,YAAY,SAAS,YAAY,SAAS,QAAS,QAAO;AACvE,UAAI,SAAS,WAAY,QAAO;AAChC,UAAI,SAAS,QAAS,QAAO;AAC7B,UAAI,SAAS,QAAS,QAAO;AAC7B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACA,QAAM,SAAS,CAAC,YAA6B;AAC3C,UAAM,OAAO,QAAQ,aAAa,YAAY;AAC9C,QAAI,MAAM,KAAK,EAAG,QAAO,UAAU,IAAI;AACvC,UAAM,MAAM,QAAQ,aAAa,iBAAiB,GAAG,MAAM,KAAK,EAAE,OAAO,OAAO,KAAK,CAAC;AACtF,UAAM,WAAW,UAAU,IAAI,IAAI,CAAC,OAAO,QAAQ,cAAc,eAAe,EAAE,GAAG,eAAe,EAAE,EAAE,KAAK,GAAG,CAAC;AACjH,QAAI,SAAU,QAAO;AACrB,QAAI,mBAAmB,oBAAoB,QAAQ,QAAQ,QAAQ;AACjE,YAAM,QAAQ,UAAU,MAAM,KAAK,QAAQ,MAAM,EAAE,IAAI,CAAC,cAAc,UAAU,eAAe,EAAE,EAAE,KAAK,GAAG,CAAC;AAC5G,UAAI,MAAO,QAAO;AAAA,IACpB;AACA,eAAW,aAAa,CAAC,OAAO,SAAS,aAAa,GAAG;AACvD,YAAM,QAAQ,QAAQ,aAAa,SAAS;AAC5C,UAAI,OAAO,KAAK,EAAG,QAAO,UAAU,KAAK;AAAA,IAC3C;AACA,WAAO,UAAU,QAAQ,eAAe,EAAE;AAAA,EAC5C;AACA,QAAM,UAAU,CAAC,YAA8B;AAC7C,QAAI,QAAQ,aAAa,aAAa,MAAM,OAAQ,QAAO;AAC3D,QAAI,EAAE,mBAAmB,aAAc,QAAO;AAC9C,QAAI,QAAQ,OAAQ,QAAO;AAC3B,UAAM,QAAQ,iBAAiB,OAAO;AACtC,WAAO,MAAM,YAAY,UAAU,MAAM,eAAe,YAAY,MAAM,YAAY;AAAA,EACxF;AACA,SAAO,SAAS,MAAM,GAAG,KAAK,EAAE,IAAI,CAAC,YAAY;AAC/C,UAAM,OAAO,QAAQ,aAAa,MAAM,GAAG,KAAK,KAAK,QAAQ,OAAO;AACpE,UAAM,OAAO,OAAO,OAAO,EAAE,MAAM,GAAG,GAAG;AACzC,UAAM,QAAQ,mBAAmB,mBAC5B,QAAQ,SAAS,aAAa,eAAe,QAAQ,QACtD,mBAAmB,uBAAuB,mBAAmB,oBAAoB,QAAQ,QAAQ;AACrG,UAAM,UAAU,mBAAmB,qBAChC,QAAQ,SAAS,cAAc,QAAQ,SAAS,WAAW,QAAQ,UAAU;AAChF,WAAO;AAAA,MACL,KAAK,QAAQ,QAAQ,YAAY;AAAA,MACjC,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,GAAG,GAAK,EAAE,IAAI,CAAC;AAAA,MAC9D,WAAW,mBAAmB,qBAAqB,mBAAmB,oBACpE,mBAAmB,sBAAsB,QAAQ;AAAA,MACnD,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,SAAS,QAAQ,OAAO;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;AAEA,SAAS,aAAa,OAAuF;AAC3G,QAAM,SAAS,MAAM,UAAU,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,cAAc,GAAG,CAAC;AACjF,SAAO,SAAS,EAAE,MAAM,MAAM,OAAO,QAAQ,KAAK,MAAM,MAAM,QAAQ,UAAU,UAAU,CAAC;AAC3F,SAAO,EAAE,GAAG,OAAO,SAAS,GAAG,OAAO,QAAQ;AAChD;AAGA,SAAS,QAAQ,OAA6D;AAC5E,QAAM,YAAY,CAAC,KAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI;AACjE,MAAI,MAAM,SAAS,MAAM,CAAC,UAAU,MAAM,CAAC,MAAM,UAAU,MAAM,KAAK,MAAM,IAAI,EAAG,QAAO;AAC1F,QAAM,OAAO,IAAI,SAAS,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;AAC1E,SAAO,EAAE,OAAO,KAAK,UAAU,EAAE,GAAG,QAAQ,KAAK,UAAU,EAAE,EAAE;AACjE;AAGA,SAAS,OAAO,OAA2B;AACzC,MAAI,SAAS;AACb,WAAS,SAAS,GAAG,SAAS,MAAM,QAAQ,UAAU;AACpD,cAAU,OAAO,aAAa,GAAG,MAAM,SAAS,QAAQ,SAAS,KAAM,CAAC;AAC1E,SAAO,KAAK,MAAM;AACpB;AAMA,SAAS,kBAAkB,OAAgB,iBAAmC;AAC5E,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,WAAW,CAAC,MAAc,SAA2B;AACzD,UAAM,QAAQ,gBAAgB,aAAa,OACvC,QAAQ,OAAO,SAAS,YAAa,KAA4B,SAAS,YAC1E,MAAM,QAAS,KAA4B,IAAI,IAAI,WAAW,KAAM,KAA4B,IAAI,IACpG;AACJ,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,OAAO,QAAQ,KAAK;AAC1B,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,yBAAyB,OAAO;AAChD,QAAI,QAAQ,SAAS,MAAM,KAAM,QAAO,EAAE,OAAO,sDAAsD,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AAC9I,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,UAAU,kBACN,0DACA;AAAA,IACN;AAAA,EACF;AACA,MAAI;AACF,WAAO,KAAK,MAAM,KAAK,UAAU,OAAO,QAAQ,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAGO,SAAS,wBAAwB,OAA2C;AACjF,MAAI,iBAAiB,qBAAsB,QAAO,MAAM;AACxD,MAAI,iBAAiB,OAAO,aAAc,QAAO;AACjD,QAAM,UAAU,aAAa,KAAK;AAClC,MAAI,iIAAiI,KAAK,OAAO;AAC/I,WAAO;AACT,MAAI,sFAAsF,KAAK,OAAO;AACpG,WAAO;AACT,MAAI,6BAA6B,KAAK,OAAO,EAAG,QAAO;AACvD,SAAO;AACT;AAEO,IAAM,8BAAN,MAAkC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAAY,SAA6C;AACnE,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,SAAS,YAAY;AACxB,YAAM,KAAK,cAAc,wBAAwB,YAAY;AAC7D,YAAM,KAAK,SAAS,wBAAwB,YAAY,EAAE,MAAM,MAAM,MAAS;AAAA,IACjF,GAAG;AAAA,EACL;AAAA,EAEA,MAAM,QAAQ,KAA+C;AAC3D,UAAM,OAAO,0BAA0B,GAAG;AAC1C,UAAM,YAAY,cAAc,GAAG;AACnC,QAAI,CAAC,KAAM,QAAO,KAAK,QAAQ,WAAW,iBAAiB,oCAAoC;AAC/F,QAAI;AACF,YAAM,KAAK;AACX,aAAO,MAAM,KAAK,YAAY,IAAI;AAAA,IACpC,SAAS,OAAO;AACd,aAAO,KAAK,QAAQ,KAAK,WAAW,wBAAwB,KAAK,GAAG,aAAa,KAAK,CAAC;AAAA,IACzF;AAAA,EACF;AAAA,EAEQ,QAAQ,OAAgB,OAAyB;AACvD,UAAM,UAAU;AAChB,UAAM,QAAQ,CAAC,cAAmC,UAAU,UAAU,SAAY,EAAE,OAAO,UAAU,MAAM,IAAI,CAAC;AAChH,UAAM,OAAO,KAAK;AAClB,UAAM,OAAO,QAAQ,OAAO,QAAQ,KAAK,QAAQ,QAAQ,KAAK,IAG1D,QAAQ,OAAO,QAAQ,KAAK,QAAQ,YAAY,QAAQ,KAAK,EAAE,IAC/D,QAAQ,OAAO,SAAS,KAAK,UAAU,QAAQ,MAA0C;AAAA,MACvF,GAAI,QAAQ,SAAS,SAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,MAE3D,OAAO,QAAQ,SAAS;AAAA,IAC1B,CAAC,IACD,QAAQ,OAAO,SAAS,KAAK,UAAU,QAAQ,MAAM,MAAM,OAAO,CAAC,IACnE,QAAQ,OAAO,UAAU,KAAK,WAAW,QAAQ,MAAM,MAAM,OAAO,CAAC,IACrE,QAAQ,OAAO,gBAAgB,KAAK,iBAAiB,QAAQ,MAAM,MAAM,OAAO,CAAC,IACjF,QAAQ,OAAO,YAAY,KAAK,aAAa,QAAQ,MAAM,MAAM,OAAO,CAAC,IACzE,QAAQ,OAAO,UAAU,KAAK,WAAW,QAAQ,MAAM,MAAM,OAAO,CAAC,IACrE,KAAK,YAAY,QAAQ,KAAK;AAClC,WAAO,UAAU,SAAY,OAAO,UAAU,IAAI,KAAK,MAAM,IAAI,KAAK,IAAI,KAAK;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,YAAY,OAA+B;AACvD,QAAK,OAAsC,OAAO;AAChD,YAAM,KAAK,KAAK,aAAa,EAAE,MAAM,MAAM,SAAS,kBAAkB,CAAC;AAAA,EAC3E;AAAA,EAEA,MAAc,MAAM,SAAmC;AACrD,QAAI;AACF,YAAM,QAAQ,MAAM,QAAQ,iBAAiB,EAAE,MAAM,MAAM,OAAO,GAAG,SAAS,kBAAkB,CAAC;AACjG,YAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,CAAC,SAAS,QAAQ,OAAO,SAAS,QAAQ,IAAqC;AAC/H,aAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,MAAM;AAAA,IACtD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,SAAkB,OAA6C;AAItF,UAAM,WAAW,MAAM,QAAQ,eAAe,GAAG,MAAM,GAAG,KAAK;AAC/D,QAAI;AACJ,QAAI;AACF,YAAM,UAAU;AAChB,eAAS,MAAM,KAAK,KAAK,SAAS,SAAS,EAAE,UAAU,SAAsB,MAAM,CAAC;AAAA,IACtF,UAAE;AACA,YAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,QAAQ,EAAE,MAAM,MAAM,MAAS,CAAC,CAAC;AAAA,IACpF;AACA,UAAM,OAAO,MAAM,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAG,UAAU,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC;AACvF,WAAO,OAAO,IAAI,CAAC,OAAO,WAAW,EAAE,KAAK,KAAK,KAAK,KAAK,IAAI,GAAG,MAAM,EAAE;AAAA,EAC5E;AAAA,EAEA,MAAc,QAAQ,SAA8C;AAClE,UAAM,CAAC,UAAU,IAAI,MAAM,KAAK,WAAW,QAAQ,MAAM,GAAG,CAAC;AAC7D,QAAI,CAAC,WAAY,OAAM,IAAI,qBAAqB,aAAa,iCAAiC;AAC9F,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,IAAO,SAAkB,QAAgB,KAAmC;AACxF,QAAI;AACF,aAAO,MAAM,IAAI;AAAA,IACnB,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,yBAAyB,MAAM,QAAQ,MAAM,EAAE,MAAM,MAAM,CAAC,MAAM;AACvF,cAAM,IAAI,qBAAqB,aAAa,GAAG,MAAM,oCAAoC;AAC3F,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,MAAM,QAAyC;AAC3D,QAAI,CAAC,KAAK,QAAQ,eAAe,MAAM,OAAO,QAAQ,MAAM,EAAE,MAAM,MAAM,CAAC,MAAM,EAAG;AACpF,UAAM,KAAK,QAAQ,YAAY,MAAM;AAAA,EACvC;AAAA,EAEA,MAAc,WAA4B;AACxC,UAAM,QAAQ,MAAM,KAAK,KAAK,SAAS,CAAC,QAAS,WAAkD,GAAG,GAAG,YAAY,EAClH,MAAM,MAAM,MAAS;AACxB,WAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,EAC7C;AAAA,EAEA,MAAc,YAAY,MAA6D;AACrF,UAAM,QAAQ,KAAK;AACnB,UAAM,OAAO,KAAK;AAClB,UAAM,mBAAmB,OAAO,MAAM,qBAAqB,WAAW,MAAM,mBAAmB;AAC/F,QAAI,qBAAqB,QAAW;AAClC,YAAM,UAAU,MAAM,KAAK,SAAS;AACpC,UAAI,qBAAqB;AACvB,eAAO,KAAK,QAAQ,KAAK,WAAW,cAAc,uCAAuC,gBAAgB,sBAAsB,OAAO,IAAI;AAAA,IAC9I;AACA,QAAI,KAAK,cAAc;AACrB,aAAO,KAAK,QAAQ,KAAK,WAAW;AAAA,QAClC,WAAW;AAAA,QACX,UAAU;AAAA,QACV,iBAAiB,KAAK,QAAQ;AAAA,QAC9B,gBAAgB;AAAA,QAChB,UAAU,KAAK,QAAQ;AAAA,MACzB,CAAC;AACH,QAAI,KAAK,cAAc,oBAAoB;AACzC,YAAM,KAAK,YAAY,MAAM,OAAO;AACpC,YAAM,SAAS,MAAM,UAAU,KAAK,QAAQ,MAAM,OAAO,EAAE,MAAM,IAAI;AACrE,YAAM,OAAO,SACT,MAAM,KAAK,IAAI,QAAQ,gBAAgB,MAAM,OAAO,aAAa,EAAE,MAAM,MAAM,SAAS,kBAAkB,CAAC,CAAC,IAC5G,MAAM,KAAK,aAAa,EAAE,MAAM,MAAM,SAAS,kBAAkB,CAAC;AACtE,YAAM,UAAU,KAAK,MAAM,GAAG,IAAM;AACpC,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,MAAM,SAAS,WAAW,QAAQ,SAAS,KAAK,OAAO,CAAC;AAAA,IAChG;AACA,QAAI,KAAK,cAAc,iBAAiB;AACtC,YAAM,KAAK,YAAY,MAAM,OAAO;AACpC,YAAMA,WAAU,KAAK,QAAQ,MAAM,SAAS,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,MAAS;AACrG,YAAM,QAAQ,MAAMA,SAAQ,MAAM;AAClC,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,OAAO,SAAS,MAAM,KAAK,WAAWA,UAAS,EAAE,GAAG,WAAW,QAAQ,GAAG,CAAC;AAAA,IACnH;AACA,QAAI,KAAK,cAAc,gBAAgB;AACrC,YAAM,KAAK,YAAY,MAAM,OAAO;AACpC,YAAM,YAAY,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AACtE,YAAMC,WAAU,KAAK,IAAI,WAAW,qBAAqB;AACzD,YAAMD,WAAU,KAAK,QAAQ,MAAM,SAAS,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,CAAC;AAC7F,UAAI;AACF,cAAMA,SAAQ,QAAQ,EAAE,OAAO,MAAM,UAAU,aAAa,aAAa,WAAW,SAAAC,SAAQ,CAAC;AAAA,MAC/F,SAAS,OAAO;AACd,YAAI,iBAAiB,OAAO;AAC1B,gBAAM,IAAI,qBAAqB,aAAa,2BAA2BA,QAAO,QAC3EA,WAAU,YAAY,mBAAmB,SAAS,oBAAoB,qBAAqB,sCAAsC,MAAM,GAAG;AAC/I,cAAM;AAAA,MACR;AACA,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,OAAO,KAAK,CAAC;AAAA,IACrD;AACA,QAAI,KAAK,cAAc,kBAAkB;AACvC,YAAM,YAAY,MAAM;AACxB,YAAM,WAAW,MAAM,KAAK,SAAS,cAAc;AAAA,QACjD,MAAM,cAAc,SAAS,KAAK,cAAc,UAAU,IAAI;AAAA,QAC9D,KAAK,cAAc,OAAO,KAAK,cAAc,SAAS,IAAI;AAAA,QAC1D,QAAQ,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAAA,MAC5D,CAAC;AACD,aAAO,KAAK,QAAQ,KAAK,WAAW,QAAQ;AAAA,IAC9C;AACA,QAAI,KAAK,cAAc,iBAAkB,QAAO,KAAK,OAAO,IAAI;AAChE,QAAI,KAAK,cAAc,iBAAiB;AACtC,YAAM,SAAS,MAAM;AACrB,UAAI,WAAW,OAAQ,OAAM,KAAK,MAAM,KAAK,MAAM,GAAa,MAAM,CAAW;AAAA,eACxE,WAAW,QAAS,OAAM,KAAK,MAAM,MAAM,MAAM,GAAa,MAAM,CAAW;AAAA,eAC/E,WAAW,OAAQ,OAAM,KAAK,MAAM,KAAK;AAAA,UAC7C,OAAM,KAAK,MAAM,GAAG;AACzB,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,QAAQ,GAAI,OAAO,MAAM,MAAM,WAAW,EAAE,GAAG,MAAM,GAAG,GAAG,MAAM,EAAE,IAAI,CAAC,EAAG,CAAC;AAAA,IACpH;AACA,QAAI,KAAK,cAAc,iBAAiB;AACtC,YAAM,SAAS,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AACjE,YAAM,SAAS,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AACjE,YAAM,KAAK,MAAM,MAAM,QAAQ,MAAM;AACrC,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,QAAQ,OAAO,CAAC;AAAA,IACxD;AACA,QAAI,KAAK,cAAc,gBAAgB;AACrC,YAAM,UAAU,OAAO,aAAyE;AAC9F,YAAI,SAAS,YAAY,OAAW,QAAO,EAAE,GAAG,SAAS,GAAa,GAAG,SAAS,EAAY;AAC9F,cAAM,KAAK,YAAY,SAAS,OAAO;AACvC,cAAMD,WAAU,KAAK,QAAQ,SAAS,OAAO,EAAE,MAAM;AACrD,cAAM,MAAM,MAAMA,SAAQ,MAAM,MAAM,IAAI,OAAO,MAAMA,SAAQ,YAAY,EAAE,SAAS,kBAAkB,CAAC;AACzG,YAAI,CAAC,IAAK,OAAM,IAAI,qBAAqB,aAAa,sCAAsC;AAC5F,eAAO,EAAE,GAAG,IAAI,IAAI,IAAI,QAAQ,GAAG,GAAG,IAAI,IAAI,IAAI,SAAS,EAAE;AAAA,MAC/D;AACA,iBAAW,OAAO,CAAC,MAAM,MAAM,MAAM,EAAE;AACrC,YAAI,IAAI,YAAY,OAAW,OAAM,KAAK,MAAM,EAAE,QAAQ,QAAQ,SAAS,KAAK,QAAQ,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;AAChH,YAAM,OAAO,MAAM,QAAQ,MAAM,IAA+B;AAChE,YAAM,KAAK,MAAM,QAAQ,MAAM,EAA6B;AAC5D,YAAM,KAAK,MAAM,KAAK,KAAK,GAAG,KAAK,CAAC;AACpC,YAAM,KAAK,MAAM,KAAK;AACtB,YAAM,KAAK,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,EAAE,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,EAAE,CAAC;AAC9F,YAAM,KAAK,MAAM,GAAG;AACpB,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,MAAM,GAAG,CAAC;AAAA,IAClD;AACA,QAAI,KAAK,cAAc,gBAAgB;AACrC,YAAM,KAAK,OAAO,EAAE,WAAW,UAAU,SAAS,kBAAkB,CAAC;AACrE,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IACzD;AACA,QAAI,KAAK,cAAc,mBAAmB;AACxC,YAAM,KAAK,UAAU,EAAE,WAAW,UAAU,SAAS,kBAAkB,CAAC;AACxE,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IACzD;AACA,QAAI,KAAK,cAAc,kBAAkB;AACvC,YAAM,KAAK,OAAO,EAAE,WAAW,UAAU,SAAS,kBAAkB,CAAC;AACrE,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IACzD;AAEA,UAAM,KAAK,YAAY,MAAM,OAAO;AACpC,UAAM,UAAU,MAAM,UAClB,KAAK,QAAQ,MAAM,SAAS,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,CAAC,IAC7E;AACJ,UAAM,UAAU;AAChB,QAAI,KAAK,cAAc,eAAe;AACpC,YAAM,MAAM,MAAM,QAAS,MAAM,MAAM,IAAI,OAAO,MAAM,QAAS,YAAY,EAAE,QAAQ,CAAC;AACxF,UAAI,CAAC,IAAK,QAAO,KAAK,QAAQ,KAAK,WAAW,aAAa,iCAAiC;AAC5F,aAAO,KAAK,QAAQ,KAAK,WAAW,GAAG;AAAA,IACzC;AACA,QAAI,KAAK,cAAc,mBAAmB,CAAC,SAAS;AAClD,YAAM,KAAK,MAAM,EAAE,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,EAAE,MAAM,GAAG,OAAO,MAAM,IAAI,CAAC;AAChG,YAAM,KAAK,SAAS,MAAM,MAAM,GAAa;AAC7C,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,KAAK,MAAM,IAAI,CAAC;AAAA,IACxD;AACA,UAAM,SAAS;AACf,UAAM,UAAU,KAAK,cAAc,mBAAmB,WAAW,KAAK,UAAU,MAAM,WAAW,MAAM;AACvG,UAAM,KAAK,MAAM;AAAA,MAAE,QAAQ;AAAA,MAAS,SAAS,OAAO,MAAM;AAAA,MACxD,GAAI,KAAK,cAAc,iBAAiB,EAAE,OAAO,MAAM,MAAM,IAAI,KAAK,cAAc,kBAAkB,EAAE,OAAO,MAAM,IAAI,IACrH,KAAK,cAAc,mBAAmB,EAAE,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA,IAAG,CAAC;AAG3E,UAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,EAAE,MAAM,MAAM,IAAI;AAC1D,QAAI,KAAK,cAAc,gBAAiB,OAAM,KAAK,IAAI,QAAQ,SAAS,MAAM,OAAO,MAAM,EAAE,QAAQ,CAAC,CAAC;AAAA,aAC9F,KAAK,cAAc,eAAgB,OAAM,KAAK,IAAI,QAAQ,QAAQ,MAAM,OAAO,KAAK,MAAM,OAAiB,EAAE,QAAQ,CAAC,CAAC;AAAA,aACvH,KAAK,cAAc,gBAAiB,OAAM,KAAK,IAAI,QAAQ,SAAS,MAAM,OAAO,MAAM,MAAM,KAAe,EAAE,QAAQ,CAAC,CAAC;AAAA,aACxH,KAAK,cAAc,gBAAiB,OAAM,KAAK,IAAI,QAAQ,SAAS,MAAM,OAAO,MAAM,EAAE,QAAQ,CAAC,CAAC;AAAA,aACnG,KAAK,cAAc,gBAAiB,OAAM,KAAK,IAAI,QAAQ,SAAS,MAAM,OAAO,MAAM,EAAE,QAAQ,CAAC,CAAC;AAAA,aACnG,KAAK,cAAc,gBAAiB,OAAM,KAAK,IAAI,QAAQ,SAAS,MAAM,OAAO,MAAM,EAAE,QAAQ,CAAC,CAAC;AAAA,aACnG,KAAK,cAAc,kBAAmB,OAAM,KAAK,IAAI,QAAQ,WAAW,MAAM,OAAO,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAAA,aACzG,KAAK,cAAc,kBAAkB;AAC5C,YAAM,SAAS,MAAM,KAAK,IAAI,QAAQ,gBAAgB,MAAM,OAAO,aAAa,MAAM,QAAoB,EAAE,QAAQ,CAAC,CAAC;AACtH,aAAO,KAAK,QAAQ,KAAK,WAAW,EAAE,OAAO,CAAC;AAAA,IAChD;AACA,UAAM,QAAQ,MAAM,KAAK,QAAQ,MAAM,EAAE,MAAM,MAAM,IAAI;AACzD,UAAM,aAAa,SAAS;AAC5B,QAAI,CAAC,WAAY,OAAM,IAAI,qBAAqB,aAAa,iCAAiC;AAC9F,WAAO,KAAK,QAAQ,KAAK,WAAW,UAAU;AAAA,EAChD;AAAA,EAEA,MAAc,OAAO,MAA6D;AAChF,UAAM,QAAQ,KAAK;AACnB,UAAM,SAAS,MAAM;AACrB,UAAM,OAAQ,MAAM,QAAgD,CAAC;AACrE,UAAM,YAAY,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AACtE,UAAM,UAAU,KAAK,IAAI,WAAW,uBAAuB;AAE3D,UAAM,gBAAgB,OAAO,eAAe,iBAAkB;AAAA,IAAC,CAAC,EAAE;AAElE,QAAI;AACJ,QAAI;AACF,YAAM,IAAI,cAAc,QAAQ,QAAQ,MAAM;AAAA,IAChD,SAAS,OAAO;AACd,aAAO,KAAK,QAAQ,KAAK,WAAW,UAAU,6BAA6B,aAAa,KAAK,CAAC,EAAE;AAAA,IAClG;AACA,UAAM,SAAS,UAAU,YACrB,oCAAoC,uBAAuB,sDAC3D;AACJ,QAAI;AACJ,QAAI;AACF,YAAM,QAAQ,MAAM,QAAQ,KAAK;AAAA,QAC/B,IAAI,KAAK,MAAM,IAAI;AAAA,QACnB,IAAI,QAAQ,CAAC,UAAU,WAAW;AAChC,kBAAQ,WAAW,MAAM,OAAO,IAAI,qBAAqB,UAAU,uBAAuB,OAAO,SAAS,SAAS,IAAI,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO;AAAA,QAClJ,CAAC;AAAA,MACH,CAAC;AACD,aAAO,KAAK,QAAQ,KAAK,WAAW;AAAA,QAClC,OAAO,kBAAkB,OAAO,KAAK,QAAQ,eAAe;AAAA,QAC5D,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC7B,CAAC;AAAA,IACH,UAAE;AACA,mBAAa,KAAK;AAElB,WAAK,KAAK,mBAAmB;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAc,SAAiC;AAC7C,QAAI,KAAK,KAAK,SAAS,EAAG,QAAO,EAAE,KAAK,IAAI,OAAO,IAAI,UAAU,EAAE;AAGnE,UAAM,UAAU,CAAI,SAAqB,aAA4B;AACnE,UAAI;AACJ,aAAO,QAAQ,KAAK;AAAA,QAClB,QAAQ,MAAM,MAAM,QAAQ;AAAA,QAC5B,IAAI,QAAW,CAAC,YAAY;AAAE,kBAAQ,WAAW,MAAM,QAAQ,QAAQ,GAAG,GAAK;AAAA,QAAG,CAAC;AAAA,MACrF,CAAC,EAAE,QAAQ,MAAM,aAAa,KAAK,CAAC;AAAA,IACtC;AACA,UAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC1C,QAAQ,KAAK,KAAK,MAAM,GAAG,EAAE;AAAA,MAC7B,QAAQ,KAAK,SAAS,GAAG,CAAC;AAAA,IAC5B,CAAC;AACD,WAAO,EAAE,KAAK,KAAK,KAAK,IAAI,GAAG,OAAO,SAAS;AAAA,EACjD;AAAA,EAEA,MAAc,QAAQ,WAAiC,OAAiD;AACtG,WAAO,EAAE,IAAI,MAAM,WAAW,QAAQ,MAAM,KAAK,OAAO,GAAG,MAAM;AAAA,EACnE;AAAA,EAEA,MAAc,QAAQ,WAAiC,MAAiC,SAAkD;AACxI,WAAO,EAAE,IAAI,OAAO,WAAW,OAAO,EAAE,MAAM,QAAQ,GAAG,QAAQ,MAAM,KAAK,OAAO,EAAE;AAAA,EACvF;AACF;AAEA,SAAS,cAAc,KAAoC;AACzD,QAAM,YAAY,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,IAAK,IAAgC,YAAY;AACvH,SAAO,OAAO,cAAc,YAAa,wBAA8C,SAAS,SAAS,IACrG,YACA;AACN;",
6
+ "names": ["locator", "timeout"]
7
+ }
@@ -0,0 +1,5 @@
1
+ export { ACTION_TIMEOUT_MS, PLAYWRIGHT_FEATURES, PLAYWRIGHT_IMPLEMENTATION, PlaywrightOperationExecutor, SCRIPT_TIMEOUT_CLAMP_MS, WAIT_TIMEOUT_CLAMP_MS, classifyPlaywrightError, type PlaywrightAction, type PlaywrightOperationExecutorOptions, } from "./executor.js";
2
+ export * from "./protocol.js";
3
+ export { MAX_REQUEST_BYTES, MAX_RESPONSE_BYTES, createPlaywrightBrowserProvider, type PlaywrightBrowserProvider, type PlaywrightBrowserProviderOptions, type ProviderResponse, } from "./provider.js";
4
+ export { defaultProvidersDirectory, serveHttp, serveTcp, type HttpServeOptions, type ServeHandle, type TcpServeOptions, } from "./serve.js";
5
+ export { main } from "./cli.js";