@undo76/agent-dom 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.
package/dist/index.cjs ADDED
@@ -0,0 +1,603 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ActionError: () => ActionError,
24
+ AgentDomError: () => AgentDomError,
25
+ AgentObservation: () => AgentObservation,
26
+ AgentPage: () => AgentPage,
27
+ ElementNotFoundError: () => ElementNotFoundError,
28
+ StaleElementReferenceError: () => StaleElementReferenceError,
29
+ createAgentPage: () => createAgentPage
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/errors.ts
34
+ var AgentDomError = class extends Error {
35
+ name = "AgentDomError";
36
+ };
37
+ var StaleElementReferenceError = class extends AgentDomError {
38
+ name = "StaleElementReferenceError";
39
+ constructor(ref, snapshotGeneration, currentGeneration) {
40
+ super(
41
+ `${ref} belongs to snapshot generation ${snapshotGeneration}; the current document generation is ${currentGeneration}. Observe the page again.`
42
+ );
43
+ }
44
+ };
45
+ var ElementNotFoundError = class extends AgentDomError {
46
+ name = "ElementNotFoundError";
47
+ constructor(message) {
48
+ super(message);
49
+ }
50
+ };
51
+ var ActionError = class extends AgentDomError {
52
+ name = "ActionError";
53
+ };
54
+
55
+ // src/actions.ts
56
+ function viewOf(element) {
57
+ const view = element.ownerDocument.defaultView;
58
+ if (!view) throw new ActionError("The element is not attached to a browser window.");
59
+ return view;
60
+ }
61
+ function assertEnabled(element) {
62
+ const disabled = element.getAttribute("aria-disabled") === "true" || "disabled" in element && typeof element.disabled === "boolean" && element.disabled;
63
+ if (disabled) throw new ActionError("Cannot act on a disabled element.");
64
+ }
65
+ function dispatch(element, type) {
66
+ const view = viewOf(element);
67
+ element.dispatchEvent(new view.Event(type, { bubbles: true, composed: true }));
68
+ }
69
+ function setNativeValue(element, value) {
70
+ const view = viewOf(element);
71
+ const prototype = element instanceof view.HTMLInputElement ? view.HTMLInputElement.prototype : view.HTMLTextAreaElement.prototype;
72
+ const setter = Object.getOwnPropertyDescriptor(prototype, "value")?.set;
73
+ if (setter) setter.call(element, value);
74
+ else element.value = value;
75
+ }
76
+ function setNativeChecked(element, checked) {
77
+ const view = viewOf(element);
78
+ const setter = Object.getOwnPropertyDescriptor(view.HTMLInputElement.prototype, "checked")?.set;
79
+ if (setter) setter.call(element, checked);
80
+ else element.checked = checked;
81
+ }
82
+ function clickElement(element) {
83
+ assertEnabled(element);
84
+ if (!(element instanceof viewOf(element).HTMLElement)) {
85
+ throw new ActionError("Click requires an HTML element.");
86
+ }
87
+ element.scrollIntoView?.({ block: "center", inline: "center" });
88
+ element.focus({ preventScroll: true });
89
+ element.click();
90
+ }
91
+ function fillElement(element, value) {
92
+ assertEnabled(element);
93
+ const view = viewOf(element);
94
+ if (element instanceof view.HTMLInputElement) {
95
+ if (["checkbox", "radio", "file", "button", "submit", "reset"].includes(element.type)) {
96
+ throw new ActionError(`Cannot fill an input of type ${element.type}.`);
97
+ }
98
+ if (element.readOnly) throw new ActionError("Cannot fill a read-only input.");
99
+ setNativeValue(element, value);
100
+ } else if (element instanceof view.HTMLTextAreaElement) {
101
+ if (element.readOnly) throw new ActionError("Cannot fill a read-only textarea.");
102
+ setNativeValue(element, value);
103
+ } else if (element instanceof view.HTMLElement && element.isContentEditable) {
104
+ element.textContent = value;
105
+ } else {
106
+ throw new ActionError("Fill requires an input, textarea, or contenteditable element.");
107
+ }
108
+ dispatch(element, "input");
109
+ dispatch(element, "change");
110
+ }
111
+ function selectElement(element, value) {
112
+ assertEnabled(element);
113
+ const view = viewOf(element);
114
+ if (!(element instanceof view.HTMLSelectElement)) throw new ActionError("Select requires a select element.");
115
+ const values = new Set(Array.isArray(value) ? value : [value]);
116
+ if (values.size > 1 && !element.multiple) throw new ActionError("Cannot select multiple values in a single select.");
117
+ const available = new Set(Array.from(element.options, (option) => option.value));
118
+ if (Array.from(values).some((item) => !available.has(item))) {
119
+ throw new ActionError("One or more select values do not exist.");
120
+ }
121
+ for (const option of element.options) {
122
+ option.selected = values.has(option.value);
123
+ }
124
+ dispatch(element, "input");
125
+ dispatch(element, "change");
126
+ }
127
+ function checkElement(element, checked) {
128
+ assertEnabled(element);
129
+ const view = viewOf(element);
130
+ if (!(element instanceof view.HTMLInputElement) || !["checkbox", "radio"].includes(element.type)) {
131
+ throw new ActionError("Check requires a checkbox or radio input.");
132
+ }
133
+ if (!checked && element.type === "radio") throw new ActionError("Radio inputs cannot be unchecked directly.");
134
+ if (element.checked === checked) return;
135
+ setNativeChecked(element, checked);
136
+ dispatch(element, "input");
137
+ dispatch(element, "change");
138
+ }
139
+ function focusElement(element) {
140
+ if (!(element instanceof viewOf(element).HTMLElement)) throw new ActionError("Focus requires an HTML element.");
141
+ element.focus();
142
+ }
143
+ function scrollElement(element, block = "center", inline = "nearest") {
144
+ element.scrollIntoView?.({ behavior: "auto", block, inline });
145
+ }
146
+ function pressElement(element, key) {
147
+ assertEnabled(element);
148
+ const view = viewOf(element);
149
+ if (!(element instanceof view.HTMLElement)) throw new ActionError("Press requires an HTML element.");
150
+ element.focus({ preventScroll: true });
151
+ const init = { key, bubbles: true, cancelable: true, composed: true };
152
+ const proceed = element.dispatchEvent(new view.KeyboardEvent("keydown", init));
153
+ if (proceed && key.length === 1) element.dispatchEvent(new view.KeyboardEvent("keypress", init));
154
+ element.dispatchEvent(new view.KeyboardEvent("keyup", init));
155
+ }
156
+
157
+ // src/semantics.ts
158
+ var import_dom_accessibility_api = require("dom-accessibility-api");
159
+ var FALLBACK_ROLES = {
160
+ article: "article",
161
+ aside: "complementary",
162
+ body: "document",
163
+ caption: "caption",
164
+ dd: "definition",
165
+ details: "group",
166
+ dialog: "dialog",
167
+ dl: "list",
168
+ dt: "term",
169
+ footer: "contentinfo",
170
+ form: "form",
171
+ header: "banner",
172
+ li: "listitem",
173
+ main: "main",
174
+ nav: "navigation",
175
+ ol: "list",
176
+ p: "paragraph",
177
+ section: "region",
178
+ summary: "button",
179
+ table: "table",
180
+ tbody: "rowgroup",
181
+ td: "cell",
182
+ tfoot: "rowgroup",
183
+ th: "columnheader",
184
+ thead: "rowgroup",
185
+ tr: "row",
186
+ ul: "list"
187
+ };
188
+ var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
189
+ "button",
190
+ "checkbox",
191
+ "combobox",
192
+ "gridcell",
193
+ "link",
194
+ "listbox",
195
+ "menuitem",
196
+ "menuitemcheckbox",
197
+ "menuitemradio",
198
+ "option",
199
+ "radio",
200
+ "searchbox",
201
+ "slider",
202
+ "spinbutton",
203
+ "switch",
204
+ "tab",
205
+ "textbox",
206
+ "treeitem"
207
+ ]);
208
+ var TEXT_FALLBACK_ROLES = /* @__PURE__ */ new Set([
209
+ "article",
210
+ "caption",
211
+ "cell",
212
+ "columnheader",
213
+ "definition",
214
+ "heading",
215
+ "listitem",
216
+ "paragraph",
217
+ "rowheader",
218
+ "term"
219
+ ]);
220
+ var SKIPPED_TAGS = /* @__PURE__ */ new Set([
221
+ "base",
222
+ "link",
223
+ "meta",
224
+ "noscript",
225
+ "script",
226
+ "style",
227
+ "template",
228
+ "title"
229
+ ]);
230
+ function shadowHost(element) {
231
+ const root = element.getRootNode();
232
+ return root.nodeType === 11 && "host" in root ? root.host : null;
233
+ }
234
+ function parentAcrossShadow(element) {
235
+ return element.parentElement ?? shadowHost(element);
236
+ }
237
+ function isHidden(element) {
238
+ let current = element;
239
+ while (current) {
240
+ if (current.hasAttribute("hidden") || current.hasAttribute("inert") || current.getAttribute("aria-hidden") === "true") {
241
+ return true;
242
+ }
243
+ const view = current.ownerDocument.defaultView;
244
+ if (view) {
245
+ const style = view.getComputedStyle(current);
246
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
247
+ return true;
248
+ }
249
+ }
250
+ current = parentAcrossShadow(current);
251
+ }
252
+ return false;
253
+ }
254
+ function roleOf(element) {
255
+ const explicitOrImplicit = (0, import_dom_accessibility_api.getRole)(element);
256
+ if (explicitOrImplicit && explicitOrImplicit !== "generic" && explicitOrImplicit !== "presentation") {
257
+ return explicitOrImplicit;
258
+ }
259
+ if (element.localName === "input" && element.type === "password") return "textbox";
260
+ if (/^h[1-6]$/u.test(element.localName)) return "heading";
261
+ return FALLBACK_ROLES[element.localName] ?? null;
262
+ }
263
+ function isInteractive(element, role) {
264
+ if (role && INTERACTIVE_ROLES.has(role)) return true;
265
+ if (element.hasAttribute("contenteditable")) return true;
266
+ if (element.hasAttribute("tabindex") && element.getAttribute("tabindex") !== "-1") return true;
267
+ return ["button", "input", "select", "textarea"].includes(element.localName) || element.localName === "a" && element.hasAttribute("href");
268
+ }
269
+ function cleanText(value) {
270
+ return value.replace(/\s+/gu, " ").trim();
271
+ }
272
+ function clipped(value, maxLength) {
273
+ if (value.length <= maxLength) return value;
274
+ return `${value.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
275
+ }
276
+ function nameOf(element, role, maxLength) {
277
+ let name = "";
278
+ try {
279
+ name = cleanText((0, import_dom_accessibility_api.computeAccessibleName)(element));
280
+ } catch {
281
+ }
282
+ if (!name && TEXT_FALLBACK_ROLES.has(role)) {
283
+ name = cleanText(element.textContent ?? "");
284
+ }
285
+ return clipped(name, maxLength);
286
+ }
287
+ function descriptionOf(element, maxLength) {
288
+ try {
289
+ const description = clipped(cleanText((0, import_dom_accessibility_api.computeAccessibleDescription)(element)), maxLength);
290
+ return description || void 0;
291
+ } catch {
292
+ return void 0;
293
+ }
294
+ }
295
+ function ariaBoolean(element, name) {
296
+ const value = element.getAttribute(name);
297
+ if (value === "true") return true;
298
+ if (value === "false") return false;
299
+ return void 0;
300
+ }
301
+ function ariaTriState(element, name) {
302
+ const value = element.getAttribute(name);
303
+ if (value === "mixed") return "mixed";
304
+ if (value === "true") return true;
305
+ if (value === "false") return false;
306
+ return void 0;
307
+ }
308
+ function stateOf(element, role) {
309
+ const state = {};
310
+ const disabled = "disabled" in element && typeof element.disabled === "boolean" ? element.disabled : ariaBoolean(element, "aria-disabled");
311
+ if (disabled !== void 0) state.disabled = disabled;
312
+ const required = "required" in element && typeof element.required === "boolean" ? element.required : ariaBoolean(element, "aria-required");
313
+ if (required !== void 0) state.required = required;
314
+ const readOnly = "readOnly" in element && typeof element.readOnly === "boolean" ? element.readOnly : ariaBoolean(element, "aria-readonly");
315
+ if (readOnly !== void 0) state.readonly = readOnly;
316
+ if (element.localName === "input" && ["checkbox", "radio"].includes(element.type)) {
317
+ const input = element;
318
+ state.checked = input.indeterminate ? "mixed" : input.checked;
319
+ } else {
320
+ const checked = ariaTriState(element, "aria-checked");
321
+ if (checked !== void 0) state.checked = checked;
322
+ }
323
+ if (element.localName === "option") state.selected = element.selected;
324
+ else {
325
+ const selected = ariaBoolean(element, "aria-selected");
326
+ if (selected !== void 0) state.selected = selected;
327
+ }
328
+ const expanded = ariaBoolean(element, "aria-expanded");
329
+ if (expanded !== void 0) state.expanded = expanded;
330
+ const pressed = ariaTriState(element, "aria-pressed");
331
+ if (pressed !== void 0) state.pressed = pressed;
332
+ if (role === "heading") {
333
+ const explicitLevel = Number(element.getAttribute("aria-level"));
334
+ const nativeLevel = /^h([1-6])$/u.exec(element.localName)?.[1];
335
+ const level = explicitLevel > 0 ? explicitLevel : Number(nativeLevel);
336
+ if (level > 0) state.level = level;
337
+ }
338
+ if (element.localName === "select") {
339
+ const select = element;
340
+ state.value = select.multiple ? Array.from(select.selectedOptions, (option) => option.value).join(", ") : select.value;
341
+ } else if (element.localName === "input" && !["password", "file", "checkbox", "radio"].includes(element.type) || element.localName === "textarea") {
342
+ state.value = element.value;
343
+ }
344
+ return state;
345
+ }
346
+ function* walkElements(root) {
347
+ const start = root.nodeType === 9 || root.nodeType === 11 && "host" in root ? Array.from(root.children) : [root];
348
+ function* visit(element, depth) {
349
+ if (SKIPPED_TAGS.has(element.localName)) return;
350
+ yield { element, depth };
351
+ if (element.shadowRoot) {
352
+ for (const child of element.shadowRoot.children) yield* visit(child, depth + 1);
353
+ }
354
+ for (const child of element.children) yield* visit(child, depth + 1);
355
+ }
356
+ for (const element of start) yield* visit(element, 0);
357
+ }
358
+
359
+ // src/observation.ts
360
+ function matches(value, matcher) {
361
+ if (matcher instanceof RegExp) {
362
+ matcher.lastIndex = 0;
363
+ return matcher.test(value);
364
+ }
365
+ return value.toLocaleLowerCase().includes(matcher.toLocaleLowerCase());
366
+ }
367
+ function exactlyOne(elements, description) {
368
+ if (elements.length === 0) throw new ElementNotFoundError(`No element matches ${description}.`);
369
+ if (elements.length > 1) {
370
+ throw new ElementNotFoundError(`${elements.length} elements match ${description}; use a ref from the observation.`);
371
+ }
372
+ return elements[0];
373
+ }
374
+ function quote(value) {
375
+ return JSON.stringify(value);
376
+ }
377
+ function formatElement(element) {
378
+ const fields = [element.role];
379
+ if (element.name) fields.push(quote(element.name));
380
+ fields.push(`[ref=${element.ref}]`);
381
+ if (element.level !== void 0) fields.push(`[level=${element.level}]`);
382
+ if (element.disabled) fields.push("[disabled]");
383
+ if (element.readonly) fields.push("[readonly]");
384
+ if (element.required) fields.push("[required]");
385
+ if (element.checked !== void 0) fields.push(`[checked=${element.checked}]`);
386
+ if (element.selected !== void 0) fields.push(`[selected=${element.selected}]`);
387
+ if (element.expanded !== void 0) fields.push(`[expanded=${element.expanded}]`);
388
+ if (element.pressed !== void 0) fields.push(`[pressed=${element.pressed}]`);
389
+ if (element.value) fields.push(`[value=${quote(element.value)}]`);
390
+ return fields.join(" ");
391
+ }
392
+ var AgentObservation = class {
393
+ generation;
394
+ text;
395
+ elements;
396
+ constructor(generation, elements) {
397
+ this.generation = generation;
398
+ this.elements = Object.freeze(elements.map((element) => Object.freeze(element)));
399
+ this.text = this.elements.map(formatElement).join("\n");
400
+ Object.freeze(this);
401
+ }
402
+ get(ref) {
403
+ return exactlyOne(this.elements.filter((element) => element.ref === normalizeRef(ref)), `ref ${ref}`);
404
+ }
405
+ findByRole(role, options = {}) {
406
+ const candidates = this.elements.filter(
407
+ (element) => element.role === role && (options.name === void 0 || matches(element.name, options.name))
408
+ );
409
+ const named = options.name === void 0 ? role : `${role} named ${String(options.name)}`;
410
+ return exactlyOne(candidates, `role ${named}`);
411
+ }
412
+ findByLabel(label) {
413
+ return exactlyOne(
414
+ this.elements.filter((element) => element.interactive && matches(element.name, label)),
415
+ `label ${String(label)}`
416
+ );
417
+ }
418
+ findByText(text) {
419
+ return exactlyOne(this.elements.filter((element) => matches(element.name, text)), `text ${String(text)}`);
420
+ }
421
+ };
422
+ function normalizeRef(ref) {
423
+ return ref.startsWith("@") ? ref.slice(1) : ref;
424
+ }
425
+ function buildObservation(generation, defaultRoot, options = {}) {
426
+ const refs = /* @__PURE__ */ new Map();
427
+ const records = [];
428
+ const root = options.root ?? defaultRoot;
429
+ const maxNameLength = options.maxNameLength ?? 160;
430
+ let refNumber = 0;
431
+ for (const { element, depth } of walkElements(root)) {
432
+ if (!options.includeHidden && isHidden(element)) continue;
433
+ const role = roleOf(element);
434
+ if (!role) continue;
435
+ const interactive = isInteractive(element, role);
436
+ if (options.interactiveOnly && !interactive) continue;
437
+ const name = nameOf(element, role, maxNameLength);
438
+ const ref = `e${++refNumber}`;
439
+ refs.set(ref, element);
440
+ const description = descriptionOf(element, maxNameLength);
441
+ const record = {
442
+ ref,
443
+ role,
444
+ name,
445
+ tag: element.localName,
446
+ interactive,
447
+ depth,
448
+ ...stateOf(element, role),
449
+ ...description ? { description } : {}
450
+ };
451
+ records.push(record);
452
+ }
453
+ return { observation: new AgentObservation(generation, records), refs };
454
+ }
455
+
456
+ // src/page.ts
457
+ function ownerDocument(root) {
458
+ return root.ownerDocument ?? root;
459
+ }
460
+ var AgentPage = class {
461
+ window;
462
+ root;
463
+ #documentGeneration = 0;
464
+ #snapshotGeneration = 0;
465
+ #refState;
466
+ #observation;
467
+ #observer;
468
+ constructor(window, options = {}) {
469
+ this.window = window;
470
+ this.root = options.root ?? window.document;
471
+ const document = ownerDocument(this.root);
472
+ if (document.defaultView !== window) {
473
+ throw new TypeError("The root must belong to the supplied window.");
474
+ }
475
+ this.#observer = new window.MutationObserver(() => {
476
+ this.#documentGeneration++;
477
+ });
478
+ this.#observer.observe(this.root, {
479
+ subtree: true,
480
+ childList: true,
481
+ attributes: true,
482
+ characterData: true
483
+ });
484
+ }
485
+ observe(options = {}) {
486
+ this.#syncMutations();
487
+ const generation = ++this.#snapshotGeneration;
488
+ const built = buildObservation(generation, this.root, options);
489
+ this.#observation = built.observation;
490
+ this.#refState = {
491
+ snapshotGeneration: generation,
492
+ documentGeneration: this.#documentGeneration,
493
+ refs: built.refs
494
+ };
495
+ return built.observation;
496
+ }
497
+ snapshot(options = {}) {
498
+ return this.observe(options);
499
+ }
500
+ getByRole(role, options = {}) {
501
+ return this.#freshObservation().findByRole(role, options).ref;
502
+ }
503
+ getByLabel(label) {
504
+ return this.#freshObservation().findByLabel(label).ref;
505
+ }
506
+ getByText(text) {
507
+ return this.#freshObservation().findByText(text).ref;
508
+ }
509
+ click(ref) {
510
+ clickElement(this.#resolve(ref));
511
+ }
512
+ fill(ref, value) {
513
+ fillElement(this.#resolve(ref), value);
514
+ }
515
+ select(ref, value) {
516
+ selectElement(this.#resolve(ref), value);
517
+ }
518
+ check(ref) {
519
+ checkElement(this.#resolve(ref), true);
520
+ }
521
+ uncheck(ref) {
522
+ checkElement(this.#resolve(ref), false);
523
+ }
524
+ focus(ref) {
525
+ focusElement(this.#resolve(ref));
526
+ }
527
+ scroll(ref, block, inline) {
528
+ scrollElement(this.#resolve(ref), block, inline);
529
+ }
530
+ press(ref, key) {
531
+ pressElement(this.#resolve(ref), key);
532
+ }
533
+ act(action) {
534
+ switch (action.type) {
535
+ case "click":
536
+ this.click(action.ref);
537
+ return;
538
+ case "fill":
539
+ this.fill(action.ref, action.value);
540
+ return;
541
+ case "select":
542
+ this.select(action.ref, action.value);
543
+ return;
544
+ case "check":
545
+ this.check(action.ref);
546
+ return;
547
+ case "uncheck":
548
+ this.uncheck(action.ref);
549
+ return;
550
+ case "focus":
551
+ this.focus(action.ref);
552
+ return;
553
+ case "scroll":
554
+ this.scroll(action.ref, action.block, action.inline);
555
+ return;
556
+ case "press":
557
+ this.press(action.ref, action.key);
558
+ }
559
+ }
560
+ destroy() {
561
+ this.#observer.disconnect();
562
+ this.#refState = void 0;
563
+ this.#observation = void 0;
564
+ }
565
+ #syncMutations() {
566
+ if (this.#observer.takeRecords().length > 0) this.#documentGeneration++;
567
+ }
568
+ #freshObservation() {
569
+ this.#syncMutations();
570
+ if (!this.#observation || !this.#refState) return this.observe();
571
+ if (this.#refState.documentGeneration !== this.#documentGeneration) return this.observe();
572
+ return this.#observation;
573
+ }
574
+ #resolve(ref) {
575
+ this.#syncMutations();
576
+ const normalized = normalizeRef(ref);
577
+ const state = this.#refState;
578
+ if (!state) throw new ElementNotFoundError("Observe the page before using a ref.");
579
+ if (state.documentGeneration !== this.#documentGeneration) {
580
+ throw new StaleElementReferenceError(normalized, state.snapshotGeneration, this.#snapshotGeneration + 1);
581
+ }
582
+ const element = state.refs.get(normalized);
583
+ if (!element) throw new ElementNotFoundError(`Unknown ref ${ref}.`);
584
+ if (!element.isConnected) {
585
+ this.#documentGeneration++;
586
+ throw new StaleElementReferenceError(normalized, state.snapshotGeneration, this.#snapshotGeneration + 1);
587
+ }
588
+ return element;
589
+ }
590
+ };
591
+ function createAgentPage(window, options = {}) {
592
+ return new AgentPage(window, options);
593
+ }
594
+ // Annotate the CommonJS export names for ESM import in node:
595
+ 0 && (module.exports = {
596
+ ActionError,
597
+ AgentDomError,
598
+ AgentObservation,
599
+ AgentPage,
600
+ ElementNotFoundError,
601
+ StaleElementReferenceError,
602
+ createAgentPage
603
+ });