@hasna/browser 0.3.7 → 0.4.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/cli/index.js +557 -395
- package/dist/engines/selector.d.ts.map +1 -1
- package/dist/engines/tui.d.ts +49 -0
- package/dist/engines/tui.d.ts.map +1 -0
- package/dist/engines/tui.test.d.ts +2 -0
- package/dist/engines/tui.test.d.ts.map +1 -0
- package/dist/index.js +8362 -7856
- package/dist/lib/actions.d.ts +1 -0
- package/dist/lib/actions.d.ts.map +1 -1
- package/dist/lib/coordination.d.ts.map +1 -1
- package/dist/lib/login-scripts.d.ts +89 -0
- package/dist/lib/login-scripts.d.ts.map +1 -0
- package/dist/lib/network.d.ts.map +1 -1
- package/dist/lib/page-memory.d.ts.map +1 -1
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/task-queue.d.ts.map +1 -1
- package/dist/mcp/index.js +553 -391
- package/dist/server/index.js +1157 -327
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/server/index.js
CHANGED
|
@@ -3,44 +3,41 @@ var __create = Object.create;
|
|
|
3
3
|
var __getProtoOf = Object.getPrototypeOf;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
function __accessProp(key) {
|
|
8
|
-
return this[key];
|
|
9
|
-
}
|
|
10
|
-
var __toESMCache_node;
|
|
11
|
-
var __toESMCache_esm;
|
|
12
8
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
-
var canCache = mod != null && typeof mod === "object";
|
|
14
|
-
if (canCache) {
|
|
15
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
-
var cached = cache.get(mod);
|
|
17
|
-
if (cached)
|
|
18
|
-
return cached;
|
|
19
|
-
}
|
|
20
9
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
10
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
11
|
for (let key of __getOwnPropNames(mod))
|
|
23
12
|
if (!__hasOwnProp.call(to, key))
|
|
24
13
|
__defProp(to, key, {
|
|
25
|
-
get:
|
|
14
|
+
get: () => mod[key],
|
|
26
15
|
enumerable: true
|
|
27
16
|
});
|
|
28
|
-
if (canCache)
|
|
29
|
-
cache.set(mod, to);
|
|
30
17
|
return to;
|
|
31
18
|
};
|
|
19
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
20
|
+
var __toCommonJS = (from) => {
|
|
21
|
+
var entry = __moduleCache.get(from), desc;
|
|
22
|
+
if (entry)
|
|
23
|
+
return entry;
|
|
24
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
25
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
26
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
27
|
+
get: () => from[key],
|
|
28
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
29
|
+
}));
|
|
30
|
+
__moduleCache.set(from, entry);
|
|
31
|
+
return entry;
|
|
32
|
+
};
|
|
32
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
-
var __returnValue = (v) => v;
|
|
34
|
-
function __exportSetter(name, newValue) {
|
|
35
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
36
|
-
}
|
|
37
34
|
var __export = (target, all) => {
|
|
38
35
|
for (var name in all)
|
|
39
36
|
__defProp(target, name, {
|
|
40
37
|
get: all[name],
|
|
41
38
|
enumerable: true,
|
|
42
39
|
configurable: true,
|
|
43
|
-
set:
|
|
40
|
+
set: (newValue) => all[name] = () => newValue
|
|
44
41
|
});
|
|
45
42
|
};
|
|
46
43
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -124,11 +121,11 @@ import { homedir as homedir4 } from "os";
|
|
|
124
121
|
import { join as join4 } from "path";
|
|
125
122
|
import { join as join6, dirname } from "path";
|
|
126
123
|
import { homedir as homedir5, platform } from "os";
|
|
127
|
-
function
|
|
124
|
+
function __accessProp(key) {
|
|
128
125
|
return this[key];
|
|
129
126
|
}
|
|
130
|
-
function
|
|
131
|
-
this[name] =
|
|
127
|
+
function __exportSetter(name, newValue) {
|
|
128
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
132
129
|
}
|
|
133
130
|
function translateSql(sql, dialect) {
|
|
134
131
|
if (dialect === "sqlite")
|
|
@@ -1158,10 +1155,10 @@ class SyncProgressTracker {
|
|
|
1158
1155
|
}
|
|
1159
1156
|
}
|
|
1160
1157
|
}
|
|
1161
|
-
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2,
|
|
1158
|
+
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node, __toESMCache_esm, __toESM2 = (mod, isNodeMode, target) => {
|
|
1162
1159
|
var canCache = mod != null && typeof mod === "object";
|
|
1163
1160
|
if (canCache) {
|
|
1164
|
-
var cache = isNodeMode ?
|
|
1161
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
1165
1162
|
var cached = cache.get(mod);
|
|
1166
1163
|
if (cached)
|
|
1167
1164
|
return cached;
|
|
@@ -1171,19 +1168,19 @@ var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __t
|
|
|
1171
1168
|
for (let key of __getOwnPropNames2(mod))
|
|
1172
1169
|
if (!__hasOwnProp2.call(to, key))
|
|
1173
1170
|
__defProp2(to, key, {
|
|
1174
|
-
get:
|
|
1171
|
+
get: __accessProp.bind(mod, key),
|
|
1175
1172
|
enumerable: true
|
|
1176
1173
|
});
|
|
1177
1174
|
if (canCache)
|
|
1178
1175
|
cache.set(mod, to);
|
|
1179
1176
|
return to;
|
|
1180
|
-
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports),
|
|
1177
|
+
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue = (v) => v, __export2 = (target, all) => {
|
|
1181
1178
|
for (var name in all)
|
|
1182
1179
|
__defProp2(target, name, {
|
|
1183
1180
|
get: all[name],
|
|
1184
1181
|
enumerable: true,
|
|
1185
1182
|
configurable: true,
|
|
1186
|
-
set:
|
|
1183
|
+
set: __exportSetter.bind(all, name)
|
|
1187
1184
|
});
|
|
1188
1185
|
}, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), __require2, require_postgres_array, require_arrayParser, require_postgres_date, require_mutable, require_postgres_interval, require_postgres_bytea, require_textParsers, require_pg_int8, require_binaryParsers, require_builtins, require_pg_types, require_defaults, require_utils, require_utils_legacy, require_utils_webcrypto, require_utils2, require_cert_signatures, require_sasl, require_type_overrides, require_pg_connection_string, require_connection_parameters, require_result, require_query, require_messages, require_buffer_writer, require_serializer, require_buffer_reader, require_parser, require_dist, require_empty, require_stream, require_connection, require_split2, require_helper, require_lib, require_client, require_pg_pool, require_query2, require_client2, require_lib2, import_lib, Client, Pool, Connection, types, Query, DatabaseError, escapeIdentifier, escapeLiteral, Result, TypeOverrides, defaults, esm_default, init_esm, init_adapter, util, objectUtil, ZodParsedType, getParsedType = (data) => {
|
|
1189
1186
|
const t = typeof data;
|
|
@@ -9487,6 +9484,12 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
9487
9484
|
});
|
|
9488
9485
|
|
|
9489
9486
|
// src/db/schema.ts
|
|
9487
|
+
var exports_schema = {};
|
|
9488
|
+
__export(exports_schema, {
|
|
9489
|
+
resetDatabase: () => resetDatabase,
|
|
9490
|
+
getDatabase: () => getDatabase,
|
|
9491
|
+
getDataDir: () => getDataDir2
|
|
9492
|
+
});
|
|
9490
9493
|
import { join as join5 } from "path";
|
|
9491
9494
|
import { mkdirSync as mkdirSync3, existsSync as existsSync4, readdirSync as readdirSync3, copyFileSync as copyFileSync2, statSync } from "fs";
|
|
9492
9495
|
import { homedir as homedir6 } from "os";
|
|
@@ -9531,6 +9534,15 @@ function getDatabase(path) {
|
|
|
9531
9534
|
runMigrations(_db);
|
|
9532
9535
|
return _db;
|
|
9533
9536
|
}
|
|
9537
|
+
function resetDatabase() {
|
|
9538
|
+
if (_db) {
|
|
9539
|
+
try {
|
|
9540
|
+
_db.close();
|
|
9541
|
+
} catch {}
|
|
9542
|
+
}
|
|
9543
|
+
_db = null;
|
|
9544
|
+
_dbPath = null;
|
|
9545
|
+
}
|
|
9534
9546
|
function runMigrations(db) {
|
|
9535
9547
|
db.exec(`
|
|
9536
9548
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -9884,6 +9896,94 @@ var init_console_log = __esm(() => {
|
|
|
9884
9896
|
init_schema();
|
|
9885
9897
|
});
|
|
9886
9898
|
|
|
9899
|
+
// src/lib/dialogs.ts
|
|
9900
|
+
var exports_dialogs = {};
|
|
9901
|
+
__export(exports_dialogs, {
|
|
9902
|
+
setupDialogHandler: () => setupDialogHandler,
|
|
9903
|
+
handleDialog: () => handleDialog,
|
|
9904
|
+
getDialogs: () => getDialogs,
|
|
9905
|
+
clearDialogs: () => clearDialogs
|
|
9906
|
+
});
|
|
9907
|
+
function setupDialogHandler(page, sessionId) {
|
|
9908
|
+
const onDialog = (dialog) => {
|
|
9909
|
+
const info = {
|
|
9910
|
+
type: dialog.type(),
|
|
9911
|
+
message: dialog.message(),
|
|
9912
|
+
default_value: dialog.defaultValue(),
|
|
9913
|
+
timestamp: new Date().toISOString()
|
|
9914
|
+
};
|
|
9915
|
+
const autoTimer = setTimeout(() => {
|
|
9916
|
+
try {
|
|
9917
|
+
dialog.dismiss().catch(() => {});
|
|
9918
|
+
} catch {}
|
|
9919
|
+
const list = pendingDialogs.get(sessionId);
|
|
9920
|
+
if (list) {
|
|
9921
|
+
const idx = list.findIndex((p) => p.dialog === dialog);
|
|
9922
|
+
if (idx >= 0)
|
|
9923
|
+
list.splice(idx, 1);
|
|
9924
|
+
if (list.length === 0)
|
|
9925
|
+
pendingDialogs.delete(sessionId);
|
|
9926
|
+
}
|
|
9927
|
+
}, AUTO_DISMISS_MS);
|
|
9928
|
+
const pending = { dialog, info, autoTimer };
|
|
9929
|
+
if (!pendingDialogs.has(sessionId)) {
|
|
9930
|
+
pendingDialogs.set(sessionId, []);
|
|
9931
|
+
}
|
|
9932
|
+
pendingDialogs.get(sessionId).push(pending);
|
|
9933
|
+
};
|
|
9934
|
+
page.on("dialog", onDialog);
|
|
9935
|
+
return () => {
|
|
9936
|
+
page.off("dialog", onDialog);
|
|
9937
|
+
const list = pendingDialogs.get(sessionId);
|
|
9938
|
+
if (list) {
|
|
9939
|
+
for (const p of list)
|
|
9940
|
+
clearTimeout(p.autoTimer);
|
|
9941
|
+
pendingDialogs.delete(sessionId);
|
|
9942
|
+
}
|
|
9943
|
+
};
|
|
9944
|
+
}
|
|
9945
|
+
function getDialogs(sessionId) {
|
|
9946
|
+
const list = pendingDialogs.get(sessionId);
|
|
9947
|
+
if (!list)
|
|
9948
|
+
return [];
|
|
9949
|
+
return list.map((p) => p.info);
|
|
9950
|
+
}
|
|
9951
|
+
async function handleDialog(sessionId, action, promptText) {
|
|
9952
|
+
const list = pendingDialogs.get(sessionId);
|
|
9953
|
+
if (!list || list.length === 0) {
|
|
9954
|
+
return { handled: false };
|
|
9955
|
+
}
|
|
9956
|
+
const pending = list.shift();
|
|
9957
|
+
clearTimeout(pending.autoTimer);
|
|
9958
|
+
if (list.length === 0) {
|
|
9959
|
+
pendingDialogs.delete(sessionId);
|
|
9960
|
+
}
|
|
9961
|
+
try {
|
|
9962
|
+
if (action === "accept") {
|
|
9963
|
+
await pending.dialog.accept(promptText);
|
|
9964
|
+
} else {
|
|
9965
|
+
await pending.dialog.dismiss();
|
|
9966
|
+
}
|
|
9967
|
+
} catch {}
|
|
9968
|
+
return { handled: true, dialog: pending.info };
|
|
9969
|
+
}
|
|
9970
|
+
function clearDialogs(sessionId) {
|
|
9971
|
+
const list = pendingDialogs.get(sessionId);
|
|
9972
|
+
if (list) {
|
|
9973
|
+
for (const p of list) {
|
|
9974
|
+
clearTimeout(p.autoTimer);
|
|
9975
|
+
try {
|
|
9976
|
+
p.dialog.dismiss().catch(() => {});
|
|
9977
|
+
} catch {}
|
|
9978
|
+
}
|
|
9979
|
+
pendingDialogs.delete(sessionId);
|
|
9980
|
+
}
|
|
9981
|
+
}
|
|
9982
|
+
var pendingDialogs, AUTO_DISMISS_MS = 5000;
|
|
9983
|
+
var init_dialogs = __esm(() => {
|
|
9984
|
+
pendingDialogs = new Map;
|
|
9985
|
+
});
|
|
9986
|
+
|
|
9887
9987
|
// src/engines/cdp.ts
|
|
9888
9988
|
var exports_cdp = {};
|
|
9889
9989
|
__export(exports_cdp, {
|
|
@@ -10066,133 +10166,887 @@ var init_storage_state = __esm(() => {
|
|
|
10066
10166
|
STATES_DIR = join8(getDataDir2(), "states");
|
|
10067
10167
|
});
|
|
10068
10168
|
|
|
10069
|
-
//
|
|
10070
|
-
var
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
switch (val.constructor) {
|
|
10084
|
-
case Uint8Array:
|
|
10085
|
-
case Uint8ClampedArray:
|
|
10086
|
-
case Int8Array:
|
|
10087
|
-
case Uint16Array:
|
|
10088
|
-
case Int16Array:
|
|
10089
|
-
case Uint32Array:
|
|
10090
|
-
case Int32Array:
|
|
10091
|
-
case Float32Array:
|
|
10092
|
-
case Float64Array:
|
|
10093
|
-
return true;
|
|
10094
|
-
}
|
|
10095
|
-
}
|
|
10096
|
-
return false;
|
|
10097
|
-
};
|
|
10098
|
-
var arrayBuffer = (val) => val instanceof ArrayBuffer;
|
|
10099
|
-
var string = (val) => typeof val === "string" && val.length > 0;
|
|
10100
|
-
var number = (val) => typeof val === "number" && !Number.isNaN(val);
|
|
10101
|
-
var integer = (val) => Number.isInteger(val);
|
|
10102
|
-
var inRange = (val, min, max) => val >= min && val <= max;
|
|
10103
|
-
var inArray = (val, list) => list.includes(val);
|
|
10104
|
-
var invalidParameterError = (name, expected, actual) => new Error(`Expected ${expected} for ${name} but received ${actual} of type ${typeof actual}`);
|
|
10105
|
-
var nativeError = (native, context) => {
|
|
10106
|
-
context.message = native.message;
|
|
10107
|
-
return context;
|
|
10108
|
-
};
|
|
10109
|
-
module.exports = {
|
|
10110
|
-
defined,
|
|
10111
|
-
object,
|
|
10112
|
-
plainObject,
|
|
10113
|
-
fn,
|
|
10114
|
-
bool,
|
|
10115
|
-
buffer,
|
|
10116
|
-
typedArray,
|
|
10117
|
-
arrayBuffer,
|
|
10118
|
-
string,
|
|
10119
|
-
number,
|
|
10120
|
-
integer,
|
|
10121
|
-
inRange,
|
|
10122
|
-
inArray,
|
|
10123
|
-
invalidParameterError,
|
|
10124
|
-
nativeError
|
|
10125
|
-
};
|
|
10169
|
+
// src/lib/snapshot.ts
|
|
10170
|
+
var exports_snapshot = {};
|
|
10171
|
+
__export(exports_snapshot, {
|
|
10172
|
+
takeSnapshot: () => takeSnapshot,
|
|
10173
|
+
takeBunSnapshot: () => takeBunSnapshot,
|
|
10174
|
+
setLastSnapshot: () => setLastSnapshot,
|
|
10175
|
+
hasRefs: () => hasRefs,
|
|
10176
|
+
getSessionRefs: () => getSessionRefs,
|
|
10177
|
+
getRefLocator: () => getRefLocator,
|
|
10178
|
+
getRefInfo: () => getRefInfo,
|
|
10179
|
+
getLastSnapshot: () => getLastSnapshot,
|
|
10180
|
+
diffSnapshots: () => diffSnapshots,
|
|
10181
|
+
clearSessionRefs: () => clearSessionRefs,
|
|
10182
|
+
clearLastSnapshot: () => clearLastSnapshot
|
|
10126
10183
|
});
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10184
|
+
function getLastSnapshot(sessionId) {
|
|
10185
|
+
return lastSnapshots.get(sessionId) ?? null;
|
|
10186
|
+
}
|
|
10187
|
+
function setLastSnapshot(sessionId, snapshot) {
|
|
10188
|
+
lastSnapshots.set(sessionId, snapshot);
|
|
10189
|
+
}
|
|
10190
|
+
function clearLastSnapshot(sessionId) {
|
|
10191
|
+
lastSnapshots.delete(sessionId);
|
|
10192
|
+
}
|
|
10193
|
+
async function takeSnapshot(page, sessionId) {
|
|
10194
|
+
const isBunView = typeof page.getNativeView === "function" || typeof page.bunView !== "undefined";
|
|
10195
|
+
if (isBunView) {
|
|
10196
|
+
return takeBunSnapshot(page, sessionId);
|
|
10197
|
+
}
|
|
10198
|
+
let ariaTree;
|
|
10199
|
+
try {
|
|
10200
|
+
ariaTree = await page.locator("body").ariaSnapshot();
|
|
10201
|
+
} catch {
|
|
10202
|
+
ariaTree = "";
|
|
10203
|
+
}
|
|
10204
|
+
const refs = {};
|
|
10205
|
+
const refMap = new Map;
|
|
10206
|
+
let refCounter = 0;
|
|
10207
|
+
for (const role of INTERACTIVE_ROLES) {
|
|
10208
|
+
const locators = page.getByRole(role);
|
|
10209
|
+
const count = await locators.count();
|
|
10210
|
+
for (let i = 0;i < count; i++) {
|
|
10211
|
+
const el = locators.nth(i);
|
|
10212
|
+
let name = "";
|
|
10213
|
+
let visible = false;
|
|
10214
|
+
let enabled = true;
|
|
10215
|
+
let value;
|
|
10216
|
+
let checked;
|
|
10217
|
+
try {
|
|
10218
|
+
visible = await el.isVisible();
|
|
10219
|
+
if (!visible)
|
|
10220
|
+
continue;
|
|
10221
|
+
} catch {
|
|
10222
|
+
continue;
|
|
10223
|
+
}
|
|
10224
|
+
try {
|
|
10225
|
+
name = await el.evaluate((e) => {
|
|
10226
|
+
const el2 = e;
|
|
10227
|
+
return el2.getAttribute("aria-label") ?? el2.textContent?.trim().slice(0, 80) ?? el2.getAttribute("title") ?? el2.getAttribute("placeholder") ?? "";
|
|
10228
|
+
});
|
|
10229
|
+
} catch {
|
|
10230
|
+
continue;
|
|
10141
10231
|
}
|
|
10232
|
+
if (!name)
|
|
10233
|
+
continue;
|
|
10234
|
+
try {
|
|
10235
|
+
enabled = await el.isEnabled();
|
|
10236
|
+
} catch {}
|
|
10237
|
+
try {
|
|
10238
|
+
if (role === "checkbox" || role === "radio" || role === "switch") {
|
|
10239
|
+
checked = await el.isChecked();
|
|
10240
|
+
}
|
|
10241
|
+
} catch {}
|
|
10242
|
+
try {
|
|
10243
|
+
if (role === "textbox" || role === "searchbox" || role === "spinbutton" || role === "combobox") {
|
|
10244
|
+
value = await el.inputValue();
|
|
10245
|
+
}
|
|
10246
|
+
} catch {}
|
|
10247
|
+
const ref = `@e${refCounter}`;
|
|
10248
|
+
refCounter++;
|
|
10249
|
+
refs[ref] = { role, name, visible, enabled, value, checked };
|
|
10250
|
+
const escapedName = name.replace(/"/g, "\\\"");
|
|
10251
|
+
refMap.set(ref, { role, name, locatorSelector: `role=${role}[name="${escapedName}"]` });
|
|
10252
|
+
}
|
|
10253
|
+
}
|
|
10254
|
+
let annotatedTree = ariaTree;
|
|
10255
|
+
for (const [ref, info] of Object.entries(refs)) {
|
|
10256
|
+
const escapedName = info.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10257
|
+
const pattern = new RegExp(`(${info.role}\\s+"${escapedName.slice(0, 40)}[^"]*")`, "m");
|
|
10258
|
+
const match = annotatedTree.match(pattern);
|
|
10259
|
+
if (match) {
|
|
10260
|
+
annotatedTree = annotatedTree.replace(match[0], `${match[0]} [${ref}]`);
|
|
10142
10261
|
}
|
|
10143
|
-
|
|
10144
|
-
};
|
|
10145
|
-
|
|
10146
|
-
|
|
10262
|
+
}
|
|
10263
|
+
const unmatchedRefs = Object.entries(refs).filter(([ref]) => !annotatedTree.includes(`[${ref}]`));
|
|
10264
|
+
if (unmatchedRefs.length > 0) {
|
|
10265
|
+
annotatedTree += `
|
|
10147
10266
|
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10267
|
+
--- Interactive elements ---`;
|
|
10268
|
+
for (const [ref, info] of unmatchedRefs) {
|
|
10269
|
+
const extras = [];
|
|
10270
|
+
if (info.checked !== undefined)
|
|
10271
|
+
extras.push(`checked=${info.checked}`);
|
|
10272
|
+
if (!info.enabled)
|
|
10273
|
+
extras.push("disabled");
|
|
10274
|
+
if (info.value)
|
|
10275
|
+
extras.push(`value="${info.value}"`);
|
|
10276
|
+
const extrasStr = extras.length ? ` (${extras.join(", ")})` : "";
|
|
10277
|
+
annotatedTree += `
|
|
10278
|
+
${info.role} "${info.name}" [${ref}]${extrasStr}`;
|
|
10279
|
+
}
|
|
10280
|
+
}
|
|
10281
|
+
if (sessionId) {
|
|
10282
|
+
sessionRefMaps.set(sessionId, refMap);
|
|
10283
|
+
}
|
|
10284
|
+
return {
|
|
10285
|
+
tree: annotatedTree,
|
|
10286
|
+
refs,
|
|
10287
|
+
interactive_count: refCounter
|
|
10160
10288
|
};
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10289
|
+
}
|
|
10290
|
+
function getRefLocator(page, sessionId, ref) {
|
|
10291
|
+
const refMap = sessionRefMaps.get(sessionId);
|
|
10292
|
+
if (!refMap)
|
|
10293
|
+
throw new Error(`No snapshot taken for session ${sessionId}. Call browser_snapshot first.`);
|
|
10294
|
+
const entry = refMap.get(ref);
|
|
10295
|
+
if (!entry)
|
|
10296
|
+
throw new Error(`Ref ${ref} not found. Available refs: ${[...refMap.keys()].slice(0, 20).join(", ")}`);
|
|
10297
|
+
return page.getByRole(entry.role, { name: entry.name }).first();
|
|
10298
|
+
}
|
|
10299
|
+
function getRefInfo(sessionId, ref) {
|
|
10300
|
+
const refMap = sessionRefMaps.get(sessionId);
|
|
10301
|
+
if (!refMap)
|
|
10302
|
+
return null;
|
|
10303
|
+
return refMap.get(ref) ?? null;
|
|
10304
|
+
}
|
|
10305
|
+
function getSessionRefs(sessionId) {
|
|
10306
|
+
return sessionRefMaps.get(sessionId) ?? null;
|
|
10307
|
+
}
|
|
10308
|
+
function clearSessionRefs(sessionId) {
|
|
10309
|
+
sessionRefMaps.delete(sessionId);
|
|
10310
|
+
}
|
|
10311
|
+
function hasRefs(sessionId) {
|
|
10312
|
+
return sessionRefMaps.has(sessionId) && (sessionRefMaps.get(sessionId)?.size ?? 0) > 0;
|
|
10313
|
+
}
|
|
10314
|
+
function refKey(info) {
|
|
10315
|
+
return `${info.role}::${info.name}`;
|
|
10316
|
+
}
|
|
10317
|
+
function diffSnapshots(before, after) {
|
|
10318
|
+
const beforeMap = new Map;
|
|
10319
|
+
for (const [ref, info] of Object.entries(before.refs)) {
|
|
10320
|
+
beforeMap.set(refKey(info), { ref, info });
|
|
10321
|
+
}
|
|
10322
|
+
const afterMap = new Map;
|
|
10323
|
+
for (const [ref, info] of Object.entries(after.refs)) {
|
|
10324
|
+
afterMap.set(refKey(info), { ref, info });
|
|
10325
|
+
}
|
|
10326
|
+
const added = [];
|
|
10327
|
+
const removed = [];
|
|
10328
|
+
const modified = [];
|
|
10329
|
+
for (const [key, afterEntry] of afterMap) {
|
|
10330
|
+
const beforeEntry = beforeMap.get(key);
|
|
10331
|
+
if (!beforeEntry) {
|
|
10332
|
+
added.push({ ref: afterEntry.ref, info: afterEntry.info });
|
|
10333
|
+
} else {
|
|
10334
|
+
const b = beforeEntry.info;
|
|
10335
|
+
const a = afterEntry.info;
|
|
10336
|
+
if (b.visible !== a.visible || b.enabled !== a.enabled || b.value !== a.value || b.checked !== a.checked || b.description !== a.description) {
|
|
10337
|
+
modified.push({ ref: afterEntry.ref, before: b, after: a });
|
|
10171
10338
|
}
|
|
10172
|
-
});
|
|
10173
|
-
});
|
|
10174
|
-
module.exports = {
|
|
10175
|
-
LDD_PATH,
|
|
10176
|
-
SELF_PATH,
|
|
10177
|
-
readFileSync: readFileSync2,
|
|
10178
|
-
readFile
|
|
10179
|
-
};
|
|
10180
|
-
});
|
|
10181
|
-
|
|
10182
|
-
// node_modules/detect-libc/lib/elf.js
|
|
10183
|
-
var require_elf = __commonJS((exports, module) => {
|
|
10184
|
-
var interpreterPath = (elf) => {
|
|
10185
|
-
if (elf.length < 64) {
|
|
10186
|
-
return null;
|
|
10187
10339
|
}
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
return null;
|
|
10340
|
+
}
|
|
10341
|
+
for (const [key, beforeEntry] of beforeMap) {
|
|
10342
|
+
if (!afterMap.has(key)) {
|
|
10343
|
+
removed.push({ ref: beforeEntry.ref, info: beforeEntry.info });
|
|
10193
10344
|
}
|
|
10194
|
-
|
|
10195
|
-
|
|
10345
|
+
}
|
|
10346
|
+
const url_changed = before.tree.split(`
|
|
10347
|
+
`)[0] !== after.tree.split(`
|
|
10348
|
+
`)[0];
|
|
10349
|
+
const title_changed = before.tree !== after.tree && (added.length > 0 || removed.length > 0 || modified.length > 0);
|
|
10350
|
+
return { added, removed, modified, url_changed, title_changed };
|
|
10351
|
+
}
|
|
10352
|
+
async function takeBunSnapshot(page, sessionId) {
|
|
10353
|
+
const refs = {};
|
|
10354
|
+
const refMap = new Map;
|
|
10355
|
+
let refCounter = 0;
|
|
10356
|
+
const lines = [];
|
|
10357
|
+
try {
|
|
10358
|
+
const elements = await page.evaluate(`
|
|
10359
|
+
(() => {
|
|
10360
|
+
const SELECTOR = 'a[href], button, input:not([type=hidden]), select, textarea, [role=button], [role=link], [role=checkbox], [role=combobox], [role=menuitem], [role=tab], [role=option]';
|
|
10361
|
+
const els = Array.from(document.querySelectorAll(SELECTOR));
|
|
10362
|
+
return els.slice(0, 100).map(el => {
|
|
10363
|
+
const tag = el.tagName.toLowerCase();
|
|
10364
|
+
const inputType = el.getAttribute('type') ?? '';
|
|
10365
|
+
let role = el.getAttribute('role') || (['a'].includes(tag) ? 'link' : ['button'].includes(tag) ? 'button' : ['input'].includes(tag) ? (inputType === 'checkbox' ? 'checkbox' : inputType === 'radio' ? 'radio' : 'textbox') : ['select'].includes(tag) ? 'combobox' : ['textarea'].includes(tag) ? 'textbox' : tag);
|
|
10366
|
+
const name = (el.getAttribute('aria-label') || el.textContent?.trim() || el.getAttribute('placeholder') || el.getAttribute('title') || el.getAttribute('value') || el.id || '').slice(0, 80);
|
|
10367
|
+
const enabled = !el.disabled && !el.getAttribute('disabled');
|
|
10368
|
+
const style = window.getComputedStyle(el);
|
|
10369
|
+
const visible = style.display !== 'none' && style.visibility !== 'hidden' && el.offsetWidth > 0;
|
|
10370
|
+
const checked = el.type === 'checkbox' || el.type === 'radio' ? el.checked : undefined;
|
|
10371
|
+
const value = ['input', 'select', 'textarea'].includes(tag) && el.type !== 'checkbox' && el.type !== 'radio' ? el.value : undefined;
|
|
10372
|
+
const selector = el.id ? '#' + el.id : (el.getAttribute('aria-label') ? '[aria-label="' + el.getAttribute('aria-label') + '"]' : tag);
|
|
10373
|
+
return { role, name, enabled, visible, checked, value, selector };
|
|
10374
|
+
}).filter(e => e.visible && e.name);
|
|
10375
|
+
})()
|
|
10376
|
+
`);
|
|
10377
|
+
const pageTitle = await page.evaluate("document.title");
|
|
10378
|
+
const pageUrl = typeof page.url === "function" ? page.url() : "";
|
|
10379
|
+
lines.push(`# ${pageTitle || "Page"} (${pageUrl})`);
|
|
10380
|
+
for (const el of elements) {
|
|
10381
|
+
if (!el.name)
|
|
10382
|
+
continue;
|
|
10383
|
+
const ref = `@e${refCounter}`;
|
|
10384
|
+
refCounter++;
|
|
10385
|
+
refs[ref] = {
|
|
10386
|
+
role: el.role,
|
|
10387
|
+
name: el.name,
|
|
10388
|
+
visible: el.visible,
|
|
10389
|
+
enabled: el.enabled,
|
|
10390
|
+
value: el.value,
|
|
10391
|
+
checked: el.checked
|
|
10392
|
+
};
|
|
10393
|
+
refMap.set(ref, { role: el.role, name: el.name, locatorSelector: el.selector });
|
|
10394
|
+
const extras = [];
|
|
10395
|
+
if (el.checked !== undefined)
|
|
10396
|
+
extras.push(`checked=${el.checked}`);
|
|
10397
|
+
if (!el.enabled)
|
|
10398
|
+
extras.push("disabled");
|
|
10399
|
+
if (el.value && el.value !== el.name)
|
|
10400
|
+
extras.push(`value="${el.value.slice(0, 30)}"`);
|
|
10401
|
+
const extrasStr = extras.length ? ` (${extras.join(", ")})` : "";
|
|
10402
|
+
lines.push(`${el.role} "${el.name}" [${ref}]${extrasStr}`);
|
|
10403
|
+
}
|
|
10404
|
+
} catch (err) {
|
|
10405
|
+
lines.push(`# (snapshot error: ${err instanceof Error ? err.message : String(err)})`);
|
|
10406
|
+
}
|
|
10407
|
+
if (sessionId) {
|
|
10408
|
+
sessionRefMaps.set(sessionId, refMap);
|
|
10409
|
+
}
|
|
10410
|
+
return {
|
|
10411
|
+
tree: lines.join(`
|
|
10412
|
+
`),
|
|
10413
|
+
refs,
|
|
10414
|
+
interactive_count: refCounter
|
|
10415
|
+
};
|
|
10416
|
+
}
|
|
10417
|
+
var lastSnapshots, sessionRefMaps, INTERACTIVE_ROLES;
|
|
10418
|
+
var init_snapshot = __esm(() => {
|
|
10419
|
+
lastSnapshots = new Map;
|
|
10420
|
+
sessionRefMaps = new Map;
|
|
10421
|
+
INTERACTIVE_ROLES = [
|
|
10422
|
+
"button",
|
|
10423
|
+
"link",
|
|
10424
|
+
"textbox",
|
|
10425
|
+
"checkbox",
|
|
10426
|
+
"radio",
|
|
10427
|
+
"combobox",
|
|
10428
|
+
"menuitem",
|
|
10429
|
+
"menuitemcheckbox",
|
|
10430
|
+
"menuitemradio",
|
|
10431
|
+
"option",
|
|
10432
|
+
"searchbox",
|
|
10433
|
+
"slider",
|
|
10434
|
+
"spinbutton",
|
|
10435
|
+
"switch",
|
|
10436
|
+
"tab",
|
|
10437
|
+
"treeitem",
|
|
10438
|
+
"listbox",
|
|
10439
|
+
"menu"
|
|
10440
|
+
];
|
|
10441
|
+
});
|
|
10442
|
+
|
|
10443
|
+
// src/lib/self-heal.ts
|
|
10444
|
+
async function healSelector(page, selector, sessionId) {
|
|
10445
|
+
const attempts = [];
|
|
10446
|
+
attempts.push(`selector: ${selector}`);
|
|
10447
|
+
try {
|
|
10448
|
+
const loc = page.locator(selector).first();
|
|
10449
|
+
if (await loc.count() > 0) {
|
|
10450
|
+
return { found: true, locator: loc, method: "original", healed: false, attempts };
|
|
10451
|
+
}
|
|
10452
|
+
} catch {}
|
|
10453
|
+
if (!selector.startsWith("#") && !selector.startsWith(".") && !selector.startsWith("[") && !selector.includes(">") && !selector.includes(" ")) {
|
|
10454
|
+
attempts.push(`text: "${selector}"`);
|
|
10455
|
+
try {
|
|
10456
|
+
const loc = page.getByText(selector, { exact: false }).first();
|
|
10457
|
+
if (await loc.count() > 0) {
|
|
10458
|
+
return { found: true, locator: loc, method: "text", healed: true, attempts };
|
|
10459
|
+
}
|
|
10460
|
+
} catch {}
|
|
10461
|
+
}
|
|
10462
|
+
const roleMap = {
|
|
10463
|
+
button: ["button", "submit", "reset"],
|
|
10464
|
+
link: ["a"],
|
|
10465
|
+
input: ["input", "textarea"],
|
|
10466
|
+
heading: ["h1", "h2", "h3", "h4", "h5", "h6"]
|
|
10467
|
+
};
|
|
10468
|
+
const nameHint = selector.replace(/^[#.]/, "").replace(/[-_]/g, " ").toLowerCase();
|
|
10469
|
+
for (const [role, tags] of Object.entries(roleMap)) {
|
|
10470
|
+
attempts.push(`role: ${role} name~="${nameHint}"`);
|
|
10471
|
+
try {
|
|
10472
|
+
const loc = page.getByRole(role, { name: new RegExp(nameHint.split(" ")[0], "i") }).first();
|
|
10473
|
+
if (await loc.count() > 0) {
|
|
10474
|
+
return { found: true, locator: loc, method: "role", healed: true, attempts };
|
|
10475
|
+
}
|
|
10476
|
+
} catch {}
|
|
10477
|
+
}
|
|
10478
|
+
if (selector.startsWith("#")) {
|
|
10479
|
+
const idPart = selector.slice(1).split("-").pop() ?? selector.slice(1);
|
|
10480
|
+
const partialSel = `[id*="${idPart}"]`;
|
|
10481
|
+
attempts.push(`partial_id: ${partialSel}`);
|
|
10482
|
+
try {
|
|
10483
|
+
const loc = page.locator(partialSel).first();
|
|
10484
|
+
if (await loc.count() > 0) {
|
|
10485
|
+
return { found: true, locator: loc, method: "partial_id", healed: true, attempts };
|
|
10486
|
+
}
|
|
10487
|
+
} catch {}
|
|
10488
|
+
}
|
|
10489
|
+
if (selector.startsWith(".")) {
|
|
10490
|
+
const classPart = selector.slice(1).split("-").pop() ?? selector.slice(1);
|
|
10491
|
+
const partialSel = `[class*="${classPart}"]`;
|
|
10492
|
+
attempts.push(`partial_class: ${partialSel}`);
|
|
10493
|
+
try {
|
|
10494
|
+
const loc = page.locator(partialSel).first();
|
|
10495
|
+
if (await loc.count() > 0) {
|
|
10496
|
+
return { found: true, locator: loc, method: "partial_class", healed: true, attempts };
|
|
10497
|
+
}
|
|
10498
|
+
} catch {}
|
|
10499
|
+
}
|
|
10500
|
+
return { found: false, locator: null, method: "none", healed: false, attempts };
|
|
10501
|
+
}
|
|
10502
|
+
|
|
10503
|
+
// src/lib/actions.ts
|
|
10504
|
+
var exports_actions = {};
|
|
10505
|
+
__export(exports_actions, {
|
|
10506
|
+
withRetry: () => withRetry,
|
|
10507
|
+
watchPage: () => watchPage,
|
|
10508
|
+
waitForText: () => waitForText,
|
|
10509
|
+
waitForSelector: () => waitForSelector,
|
|
10510
|
+
waitForNavigation: () => waitForNavigation,
|
|
10511
|
+
uploadFile: () => uploadFile,
|
|
10512
|
+
typeRef: () => typeRef,
|
|
10513
|
+
type: () => type,
|
|
10514
|
+
stopWatch: () => stopWatch,
|
|
10515
|
+
stopAllWatchesForSession: () => stopAllWatchesForSession,
|
|
10516
|
+
selectRef: () => selectRef,
|
|
10517
|
+
selectOption: () => selectOption,
|
|
10518
|
+
scrollTo: () => scrollTo,
|
|
10519
|
+
scroll: () => scroll,
|
|
10520
|
+
reload: () => reload,
|
|
10521
|
+
pressKey: () => pressKey,
|
|
10522
|
+
navigate: () => navigate,
|
|
10523
|
+
hoverRef: () => hoverRef,
|
|
10524
|
+
hover: () => hover,
|
|
10525
|
+
goForward: () => goForward,
|
|
10526
|
+
goBack: () => goBack,
|
|
10527
|
+
getWatchChanges: () => getWatchChanges,
|
|
10528
|
+
fillRef: () => fillRef,
|
|
10529
|
+
fillForm: () => fillForm,
|
|
10530
|
+
fill: () => fill,
|
|
10531
|
+
clickText: () => clickText,
|
|
10532
|
+
clickRef: () => clickRef,
|
|
10533
|
+
click: () => click,
|
|
10534
|
+
checkRef: () => checkRef,
|
|
10535
|
+
checkBox: () => checkBox
|
|
10536
|
+
});
|
|
10537
|
+
async function click(page, selector, opts) {
|
|
10538
|
+
try {
|
|
10539
|
+
await page.click(selector, {
|
|
10540
|
+
button: opts?.button ?? "left",
|
|
10541
|
+
clickCount: opts?.clickCount ?? 1,
|
|
10542
|
+
delay: opts?.delay,
|
|
10543
|
+
timeout: opts?.timeout ?? 1e4
|
|
10544
|
+
});
|
|
10545
|
+
return {};
|
|
10546
|
+
} catch (originalError) {
|
|
10547
|
+
if (opts?.selfHeal !== false) {
|
|
10548
|
+
const result = await healSelector(page, selector);
|
|
10549
|
+
if (result.found && result.locator) {
|
|
10550
|
+
await result.locator.click({
|
|
10551
|
+
button: opts?.button ?? "left",
|
|
10552
|
+
timeout: opts?.timeout ?? 1e4
|
|
10553
|
+
});
|
|
10554
|
+
return { healed: true, method: result.method, attempts: result.attempts };
|
|
10555
|
+
}
|
|
10556
|
+
}
|
|
10557
|
+
if (originalError instanceof Error && originalError.message.includes("not found")) {
|
|
10558
|
+
throw new ElementNotFoundError(selector);
|
|
10559
|
+
}
|
|
10560
|
+
throw new BrowserError(`Click failed on '${selector}': ${originalError instanceof Error ? originalError.message : String(originalError)}`, "CLICK_FAILED");
|
|
10561
|
+
}
|
|
10562
|
+
}
|
|
10563
|
+
async function type(page, selector, text, opts) {
|
|
10564
|
+
try {
|
|
10565
|
+
if (opts?.clear) {
|
|
10566
|
+
await page.fill(selector, "", { timeout: opts?.timeout ?? 1e4 });
|
|
10567
|
+
}
|
|
10568
|
+
await page.type(selector, text, { delay: opts?.delay, timeout: opts?.timeout ?? 1e4 });
|
|
10569
|
+
return {};
|
|
10570
|
+
} catch (originalError) {
|
|
10571
|
+
if (opts?.selfHeal !== false) {
|
|
10572
|
+
const result = await healSelector(page, selector);
|
|
10573
|
+
if (result.found && result.locator) {
|
|
10574
|
+
if (opts?.clear)
|
|
10575
|
+
await result.locator.fill("", { timeout: opts?.timeout ?? 1e4 });
|
|
10576
|
+
await result.locator.pressSequentially(text, { delay: opts?.delay, timeout: opts?.timeout ?? 1e4 });
|
|
10577
|
+
return { healed: true, method: result.method, attempts: result.attempts };
|
|
10578
|
+
}
|
|
10579
|
+
}
|
|
10580
|
+
if (originalError instanceof Error && originalError.message.includes("not found")) {
|
|
10581
|
+
throw new ElementNotFoundError(selector);
|
|
10582
|
+
}
|
|
10583
|
+
throw new BrowserError(`Type failed on '${selector}': ${originalError instanceof Error ? originalError.message : String(originalError)}`, "TYPE_FAILED");
|
|
10584
|
+
}
|
|
10585
|
+
}
|
|
10586
|
+
async function fill(page, selector, value, timeout = 1e4, selfHeal = true) {
|
|
10587
|
+
try {
|
|
10588
|
+
await page.fill(selector, value, { timeout });
|
|
10589
|
+
return {};
|
|
10590
|
+
} catch (originalError) {
|
|
10591
|
+
if (selfHeal) {
|
|
10592
|
+
const result = await healSelector(page, selector);
|
|
10593
|
+
if (result.found && result.locator) {
|
|
10594
|
+
await result.locator.fill(value, { timeout });
|
|
10595
|
+
return { healed: true, method: result.method, attempts: result.attempts };
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
throw new ElementNotFoundError(selector);
|
|
10599
|
+
}
|
|
10600
|
+
}
|
|
10601
|
+
async function scroll(page, direction = "down", amount = 300) {
|
|
10602
|
+
const x = direction === "left" ? -amount : direction === "right" ? amount : 0;
|
|
10603
|
+
const y = direction === "up" ? -amount : direction === "down" ? amount : 0;
|
|
10604
|
+
await page.evaluate(({ x: x2, y: y2 }) => window.scrollBy(x2, y2), { x, y });
|
|
10605
|
+
}
|
|
10606
|
+
async function scrollTo(page, selector) {
|
|
10607
|
+
try {
|
|
10608
|
+
await page.locator(selector).scrollIntoViewIfNeeded();
|
|
10609
|
+
} catch (err) {
|
|
10610
|
+
throw new ElementNotFoundError(selector);
|
|
10611
|
+
}
|
|
10612
|
+
}
|
|
10613
|
+
async function hover(page, selector, timeout = 1e4) {
|
|
10614
|
+
try {
|
|
10615
|
+
await page.hover(selector, { timeout });
|
|
10616
|
+
} catch (err) {
|
|
10617
|
+
throw new ElementNotFoundError(selector);
|
|
10618
|
+
}
|
|
10619
|
+
}
|
|
10620
|
+
async function selectOption(page, selector, value, timeout = 1e4) {
|
|
10621
|
+
try {
|
|
10622
|
+
return await page.selectOption(selector, value, { timeout });
|
|
10623
|
+
} catch (err) {
|
|
10624
|
+
throw new ElementNotFoundError(selector);
|
|
10625
|
+
}
|
|
10626
|
+
}
|
|
10627
|
+
async function checkBox(page, selector, checked, timeout = 1e4) {
|
|
10628
|
+
try {
|
|
10629
|
+
if (checked) {
|
|
10630
|
+
await page.check(selector, { timeout });
|
|
10631
|
+
} else {
|
|
10632
|
+
await page.uncheck(selector, { timeout });
|
|
10633
|
+
}
|
|
10634
|
+
} catch (err) {
|
|
10635
|
+
throw new ElementNotFoundError(selector);
|
|
10636
|
+
}
|
|
10637
|
+
}
|
|
10638
|
+
async function uploadFile(page, selector, filePaths, timeout = 1e4) {
|
|
10639
|
+
try {
|
|
10640
|
+
await page.setInputFiles(selector, filePaths, { timeout });
|
|
10641
|
+
} catch (err) {
|
|
10642
|
+
throw new ElementNotFoundError(selector);
|
|
10643
|
+
}
|
|
10644
|
+
}
|
|
10645
|
+
async function goBack(page, timeout = 1e4) {
|
|
10646
|
+
try {
|
|
10647
|
+
await page.goBack({ timeout, waitUntil: "domcontentloaded" });
|
|
10648
|
+
} catch (err) {
|
|
10649
|
+
throw new NavigationError("back", err instanceof Error ? err.message : String(err));
|
|
10650
|
+
}
|
|
10651
|
+
}
|
|
10652
|
+
async function goForward(page, timeout = 1e4) {
|
|
10653
|
+
try {
|
|
10654
|
+
await page.goForward({ timeout, waitUntil: "domcontentloaded" });
|
|
10655
|
+
} catch (err) {
|
|
10656
|
+
throw new NavigationError("forward", err instanceof Error ? err.message : String(err));
|
|
10657
|
+
}
|
|
10658
|
+
}
|
|
10659
|
+
async function reload(page, timeout = 1e4) {
|
|
10660
|
+
try {
|
|
10661
|
+
await page.reload({ timeout, waitUntil: "domcontentloaded" });
|
|
10662
|
+
} catch (err) {
|
|
10663
|
+
throw new NavigationError("reload", err instanceof Error ? err.message : String(err));
|
|
10664
|
+
}
|
|
10665
|
+
}
|
|
10666
|
+
async function navigate(page, url, timeout = 30000) {
|
|
10667
|
+
try {
|
|
10668
|
+
await page.goto(url, { waitUntil: "domcontentloaded", timeout });
|
|
10669
|
+
} catch (err) {
|
|
10670
|
+
throw new NavigationError(url, err instanceof Error ? err.message : String(err));
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
async function waitForSelector(page, selector, opts) {
|
|
10674
|
+
try {
|
|
10675
|
+
await page.waitForSelector(selector, {
|
|
10676
|
+
state: opts?.state ?? "visible",
|
|
10677
|
+
timeout: opts?.timeout ?? 1e4
|
|
10678
|
+
});
|
|
10679
|
+
} catch (err) {
|
|
10680
|
+
throw new ElementNotFoundError(selector);
|
|
10681
|
+
}
|
|
10682
|
+
}
|
|
10683
|
+
async function waitForNavigation(page, timeout = 30000) {
|
|
10684
|
+
try {
|
|
10685
|
+
await page.waitForLoadState("domcontentloaded", { timeout });
|
|
10686
|
+
} catch (err) {
|
|
10687
|
+
throw new NavigationError("navigation", err instanceof Error ? err.message : String(err));
|
|
10688
|
+
}
|
|
10689
|
+
}
|
|
10690
|
+
async function pressKey(page, key) {
|
|
10691
|
+
await page.keyboard.press(key);
|
|
10692
|
+
}
|
|
10693
|
+
async function withRetry(fn, opts) {
|
|
10694
|
+
const retries = opts?.retries ?? 2;
|
|
10695
|
+
const delay = opts?.delay ?? 300;
|
|
10696
|
+
const retryOn = opts?.retryOn ?? RETRYABLE_ERRORS;
|
|
10697
|
+
let lastErr;
|
|
10698
|
+
for (let attempt = 0;attempt <= retries; attempt++) {
|
|
10699
|
+
try {
|
|
10700
|
+
return await fn();
|
|
10701
|
+
} catch (err) {
|
|
10702
|
+
lastErr = err;
|
|
10703
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10704
|
+
const shouldRetry = retryOn.some((pattern) => msg.includes(pattern));
|
|
10705
|
+
if (!shouldRetry || err instanceof ElementNotFoundError)
|
|
10706
|
+
throw err;
|
|
10707
|
+
if (attempt < retries)
|
|
10708
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
10709
|
+
}
|
|
10710
|
+
}
|
|
10711
|
+
throw lastErr;
|
|
10712
|
+
}
|
|
10713
|
+
async function clickText(page, text, opts) {
|
|
10714
|
+
await withRetry(async () => {
|
|
10715
|
+
try {
|
|
10716
|
+
await page.getByText(text, { exact: opts?.exact ?? false }).first().click({ timeout: opts?.timeout ?? 1e4 });
|
|
10717
|
+
} catch (err) {
|
|
10718
|
+
throw new BrowserError(`clickText: could not find or click text "${text}": ${err instanceof Error ? err.message : String(err)}`, "CLICK_TEXT_FAILED");
|
|
10719
|
+
}
|
|
10720
|
+
}, { retries: opts?.retries ?? 1 });
|
|
10721
|
+
}
|
|
10722
|
+
async function fillForm(page, fields, submitSelector, selfHeal = true) {
|
|
10723
|
+
let filled = 0;
|
|
10724
|
+
const errors = [];
|
|
10725
|
+
const healedFields = [];
|
|
10726
|
+
for (const [selector, value] of Object.entries(fields)) {
|
|
10727
|
+
try {
|
|
10728
|
+
let el = await page.$(selector);
|
|
10729
|
+
if (!el && selfHeal) {
|
|
10730
|
+
const result = await healSelector(page, selector);
|
|
10731
|
+
if (result.found && result.locator) {
|
|
10732
|
+
const handle = await result.locator.elementHandle();
|
|
10733
|
+
if (handle) {
|
|
10734
|
+
el = handle;
|
|
10735
|
+
healedFields.push(selector);
|
|
10736
|
+
const tagName2 = await result.locator.evaluate((e) => e.tagName.toLowerCase());
|
|
10737
|
+
const inputType2 = await result.locator.evaluate((e) => e.type?.toLowerCase() ?? "text");
|
|
10738
|
+
if (tagName2 === "select") {
|
|
10739
|
+
await result.locator.selectOption(String(value));
|
|
10740
|
+
} else if (tagName2 === "input" && (inputType2 === "checkbox" || inputType2 === "radio")) {
|
|
10741
|
+
if (Boolean(value))
|
|
10742
|
+
await result.locator.check();
|
|
10743
|
+
else
|
|
10744
|
+
await result.locator.uncheck();
|
|
10745
|
+
} else {
|
|
10746
|
+
await result.locator.fill(String(value));
|
|
10747
|
+
}
|
|
10748
|
+
filled++;
|
|
10749
|
+
continue;
|
|
10750
|
+
}
|
|
10751
|
+
}
|
|
10752
|
+
errors.push(`${selector}: element not found`);
|
|
10753
|
+
continue;
|
|
10754
|
+
}
|
|
10755
|
+
if (!el) {
|
|
10756
|
+
errors.push(`${selector}: element not found`);
|
|
10757
|
+
continue;
|
|
10758
|
+
}
|
|
10759
|
+
const tagName = await el.evaluate((e) => e.tagName.toLowerCase());
|
|
10760
|
+
const inputType = await el.evaluate((e) => e.type?.toLowerCase() ?? "text");
|
|
10761
|
+
if (tagName === "select") {
|
|
10762
|
+
await page.selectOption(selector, String(value));
|
|
10763
|
+
} else if (tagName === "input" && (inputType === "checkbox" || inputType === "radio")) {
|
|
10764
|
+
const checked = Boolean(value);
|
|
10765
|
+
if (checked) {
|
|
10766
|
+
await page.check(selector);
|
|
10767
|
+
} else {
|
|
10768
|
+
await page.uncheck(selector);
|
|
10769
|
+
}
|
|
10770
|
+
} else {
|
|
10771
|
+
await page.fill(selector, String(value));
|
|
10772
|
+
}
|
|
10773
|
+
filled++;
|
|
10774
|
+
} catch (err) {
|
|
10775
|
+
errors.push(`${selector}: ${err instanceof Error ? err.message : String(err)}`);
|
|
10776
|
+
}
|
|
10777
|
+
}
|
|
10778
|
+
if (submitSelector) {
|
|
10779
|
+
try {
|
|
10780
|
+
await page.click(submitSelector);
|
|
10781
|
+
} catch (submitErr) {
|
|
10782
|
+
if (selfHeal) {
|
|
10783
|
+
const result = await healSelector(page, submitSelector);
|
|
10784
|
+
if (result.found && result.locator) {
|
|
10785
|
+
await result.locator.click();
|
|
10786
|
+
healedFields.push(submitSelector);
|
|
10787
|
+
} else {
|
|
10788
|
+
errors.push(`submit(${submitSelector}): ${submitErr instanceof Error ? submitErr.message : String(submitErr)}`);
|
|
10789
|
+
}
|
|
10790
|
+
} else {
|
|
10791
|
+
errors.push(`submit(${submitSelector}): ${submitErr instanceof Error ? submitErr.message : String(submitErr)}`);
|
|
10792
|
+
}
|
|
10793
|
+
}
|
|
10794
|
+
}
|
|
10795
|
+
return { filled, errors, fields_attempted: Object.keys(fields).length, ...healedFields.length > 0 ? { healed_fields: healedFields } : {} };
|
|
10796
|
+
}
|
|
10797
|
+
async function waitForText(page, text, opts) {
|
|
10798
|
+
const timeout = opts?.timeout ?? 1e4;
|
|
10799
|
+
try {
|
|
10800
|
+
await page.getByText(text, { exact: opts?.exact ?? false }).first().waitFor({ state: "visible", timeout });
|
|
10801
|
+
} catch (err) {
|
|
10802
|
+
throw new ElementNotFoundError(`text:"${text}"`);
|
|
10803
|
+
}
|
|
10804
|
+
}
|
|
10805
|
+
function watchPage(page, opts) {
|
|
10806
|
+
const id = `watch-${Date.now()}`;
|
|
10807
|
+
const changes = [];
|
|
10808
|
+
const intervalMs = opts?.intervalMs ?? 500;
|
|
10809
|
+
const maxChanges = opts?.maxChanges ?? 50;
|
|
10810
|
+
const interval = setInterval(async () => {
|
|
10811
|
+
if (changes.length >= maxChanges)
|
|
10812
|
+
return;
|
|
10813
|
+
try {
|
|
10814
|
+
const change = await page.evaluate((sel) => {
|
|
10815
|
+
const el = sel ? document.querySelector(sel) : document.body;
|
|
10816
|
+
return el ? `${new Date().toISOString()}:${el.textContent?.slice(0, 100)}` : null;
|
|
10817
|
+
}, opts?.selector ?? null);
|
|
10818
|
+
if (change && (changes.length === 0 || changes[changes.length - 1] !== change)) {
|
|
10819
|
+
changes.push(change);
|
|
10820
|
+
}
|
|
10821
|
+
} catch {}
|
|
10822
|
+
}, intervalMs);
|
|
10823
|
+
activeWatches.set(id, { interval, changes });
|
|
10824
|
+
return {
|
|
10825
|
+
id,
|
|
10826
|
+
stop: () => {
|
|
10827
|
+
clearInterval(interval);
|
|
10828
|
+
activeWatches.delete(id);
|
|
10829
|
+
}
|
|
10830
|
+
};
|
|
10831
|
+
}
|
|
10832
|
+
function getWatchChanges(watchId) {
|
|
10833
|
+
return activeWatches.get(watchId)?.changes ?? [];
|
|
10834
|
+
}
|
|
10835
|
+
function stopWatch(watchId) {
|
|
10836
|
+
const w = activeWatches.get(watchId);
|
|
10837
|
+
if (w) {
|
|
10838
|
+
clearInterval(w.interval);
|
|
10839
|
+
activeWatches.delete(watchId);
|
|
10840
|
+
}
|
|
10841
|
+
}
|
|
10842
|
+
function stopAllWatchesForSession(_sessionId) {
|
|
10843
|
+
for (const [id, w] of activeWatches) {
|
|
10844
|
+
clearInterval(w.interval);
|
|
10845
|
+
activeWatches.delete(id);
|
|
10846
|
+
}
|
|
10847
|
+
}
|
|
10848
|
+
async function clickRef(page, sessionId, ref, opts) {
|
|
10849
|
+
try {
|
|
10850
|
+
const locator = getRefLocator(page, sessionId, ref);
|
|
10851
|
+
await locator.click({ timeout: opts?.timeout ?? 1e4 });
|
|
10852
|
+
} catch (err) {
|
|
10853
|
+
if (err instanceof Error && err.message.includes("Ref "))
|
|
10854
|
+
throw new ElementNotFoundError(ref);
|
|
10855
|
+
if (err instanceof Error && err.message.includes("No snapshot"))
|
|
10856
|
+
throw new BrowserError(err.message, "NO_SNAPSHOT");
|
|
10857
|
+
throw new BrowserError(`clickRef ${ref} failed: ${err instanceof Error ? err.message : String(err)}`, "CLICK_REF_FAILED");
|
|
10858
|
+
}
|
|
10859
|
+
}
|
|
10860
|
+
async function typeRef(page, sessionId, ref, text, opts) {
|
|
10861
|
+
try {
|
|
10862
|
+
const locator = getRefLocator(page, sessionId, ref);
|
|
10863
|
+
if (opts?.clear)
|
|
10864
|
+
await locator.fill("", { timeout: opts.timeout ?? 1e4 });
|
|
10865
|
+
await locator.pressSequentially(text, { delay: opts?.delay, timeout: opts?.timeout ?? 1e4 });
|
|
10866
|
+
} catch (err) {
|
|
10867
|
+
if (err instanceof Error && err.message.includes("Ref "))
|
|
10868
|
+
throw new ElementNotFoundError(ref);
|
|
10869
|
+
throw new BrowserError(`typeRef ${ref} failed: ${err instanceof Error ? err.message : String(err)}`, "TYPE_REF_FAILED");
|
|
10870
|
+
}
|
|
10871
|
+
}
|
|
10872
|
+
async function fillRef(page, sessionId, ref, value, timeout = 1e4) {
|
|
10873
|
+
try {
|
|
10874
|
+
const locator = getRefLocator(page, sessionId, ref);
|
|
10875
|
+
await locator.fill(value, { timeout });
|
|
10876
|
+
} catch (err) {
|
|
10877
|
+
if (err instanceof Error && err.message.includes("Ref "))
|
|
10878
|
+
throw new ElementNotFoundError(ref);
|
|
10879
|
+
throw new BrowserError(`fillRef ${ref} failed: ${err instanceof Error ? err.message : String(err)}`, "FILL_REF_FAILED");
|
|
10880
|
+
}
|
|
10881
|
+
}
|
|
10882
|
+
async function selectRef(page, sessionId, ref, value, timeout = 1e4) {
|
|
10883
|
+
try {
|
|
10884
|
+
const locator = getRefLocator(page, sessionId, ref);
|
|
10885
|
+
return await locator.selectOption(value, { timeout });
|
|
10886
|
+
} catch (err) {
|
|
10887
|
+
if (err instanceof Error && err.message.includes("Ref "))
|
|
10888
|
+
throw new ElementNotFoundError(ref);
|
|
10889
|
+
throw new BrowserError(`selectRef ${ref} failed: ${err instanceof Error ? err.message : String(err)}`, "SELECT_REF_FAILED");
|
|
10890
|
+
}
|
|
10891
|
+
}
|
|
10892
|
+
async function checkRef(page, sessionId, ref, checked, timeout = 1e4) {
|
|
10893
|
+
try {
|
|
10894
|
+
const locator = getRefLocator(page, sessionId, ref);
|
|
10895
|
+
if (checked)
|
|
10896
|
+
await locator.check({ timeout });
|
|
10897
|
+
else
|
|
10898
|
+
await locator.uncheck({ timeout });
|
|
10899
|
+
} catch (err) {
|
|
10900
|
+
if (err instanceof Error && err.message.includes("Ref "))
|
|
10901
|
+
throw new ElementNotFoundError(ref);
|
|
10902
|
+
throw new BrowserError(`checkRef ${ref} failed: ${err instanceof Error ? err.message : String(err)}`, "CHECK_REF_FAILED");
|
|
10903
|
+
}
|
|
10904
|
+
}
|
|
10905
|
+
async function hoverRef(page, sessionId, ref, timeout = 1e4) {
|
|
10906
|
+
try {
|
|
10907
|
+
const locator = getRefLocator(page, sessionId, ref);
|
|
10908
|
+
await locator.hover({ timeout });
|
|
10909
|
+
} catch (err) {
|
|
10910
|
+
if (err instanceof Error && err.message.includes("Ref "))
|
|
10911
|
+
throw new ElementNotFoundError(ref);
|
|
10912
|
+
throw new BrowserError(`hoverRef ${ref} failed: ${err instanceof Error ? err.message : String(err)}`, "HOVER_REF_FAILED");
|
|
10913
|
+
}
|
|
10914
|
+
}
|
|
10915
|
+
var RETRYABLE_ERRORS, activeWatches;
|
|
10916
|
+
var init_actions = __esm(() => {
|
|
10917
|
+
init_types();
|
|
10918
|
+
init_snapshot();
|
|
10919
|
+
RETRYABLE_ERRORS = ["Timeout", "timeout", "navigation", "net::ERR", "Target closed"];
|
|
10920
|
+
activeWatches = new Map;
|
|
10921
|
+
});
|
|
10922
|
+
|
|
10923
|
+
// node_modules/sharp/lib/is.js
|
|
10924
|
+
var require_is = __commonJS((exports, module) => {
|
|
10925
|
+
/*!
|
|
10926
|
+
Copyright 2013 Lovell Fuller and others.
|
|
10927
|
+
SPDX-License-Identifier: Apache-2.0
|
|
10928
|
+
*/
|
|
10929
|
+
var defined = (val) => typeof val !== "undefined" && val !== null;
|
|
10930
|
+
var object = (val) => typeof val === "object";
|
|
10931
|
+
var plainObject = (val) => Object.prototype.toString.call(val) === "[object Object]";
|
|
10932
|
+
var fn = (val) => typeof val === "function";
|
|
10933
|
+
var bool = (val) => typeof val === "boolean";
|
|
10934
|
+
var buffer = (val) => val instanceof Buffer;
|
|
10935
|
+
var typedArray = (val) => {
|
|
10936
|
+
if (defined(val)) {
|
|
10937
|
+
switch (val.constructor) {
|
|
10938
|
+
case Uint8Array:
|
|
10939
|
+
case Uint8ClampedArray:
|
|
10940
|
+
case Int8Array:
|
|
10941
|
+
case Uint16Array:
|
|
10942
|
+
case Int16Array:
|
|
10943
|
+
case Uint32Array:
|
|
10944
|
+
case Int32Array:
|
|
10945
|
+
case Float32Array:
|
|
10946
|
+
case Float64Array:
|
|
10947
|
+
return true;
|
|
10948
|
+
}
|
|
10949
|
+
}
|
|
10950
|
+
return false;
|
|
10951
|
+
};
|
|
10952
|
+
var arrayBuffer = (val) => val instanceof ArrayBuffer;
|
|
10953
|
+
var string = (val) => typeof val === "string" && val.length > 0;
|
|
10954
|
+
var number = (val) => typeof val === "number" && !Number.isNaN(val);
|
|
10955
|
+
var integer = (val) => Number.isInteger(val);
|
|
10956
|
+
var inRange = (val, min, max) => val >= min && val <= max;
|
|
10957
|
+
var inArray = (val, list) => list.includes(val);
|
|
10958
|
+
var invalidParameterError = (name, expected, actual) => new Error(`Expected ${expected} for ${name} but received ${actual} of type ${typeof actual}`);
|
|
10959
|
+
var nativeError = (native, context) => {
|
|
10960
|
+
context.message = native.message;
|
|
10961
|
+
return context;
|
|
10962
|
+
};
|
|
10963
|
+
module.exports = {
|
|
10964
|
+
defined,
|
|
10965
|
+
object,
|
|
10966
|
+
plainObject,
|
|
10967
|
+
fn,
|
|
10968
|
+
bool,
|
|
10969
|
+
buffer,
|
|
10970
|
+
typedArray,
|
|
10971
|
+
arrayBuffer,
|
|
10972
|
+
string,
|
|
10973
|
+
number,
|
|
10974
|
+
integer,
|
|
10975
|
+
inRange,
|
|
10976
|
+
inArray,
|
|
10977
|
+
invalidParameterError,
|
|
10978
|
+
nativeError
|
|
10979
|
+
};
|
|
10980
|
+
});
|
|
10981
|
+
|
|
10982
|
+
// node_modules/detect-libc/lib/process.js
|
|
10983
|
+
var require_process = __commonJS((exports, module) => {
|
|
10984
|
+
var isLinux = () => process.platform === "linux";
|
|
10985
|
+
var report = null;
|
|
10986
|
+
var getReport = () => {
|
|
10987
|
+
if (!report) {
|
|
10988
|
+
if (isLinux() && process.report) {
|
|
10989
|
+
const orig = process.report.excludeNetwork;
|
|
10990
|
+
process.report.excludeNetwork = true;
|
|
10991
|
+
report = process.report.getReport();
|
|
10992
|
+
process.report.excludeNetwork = orig;
|
|
10993
|
+
} else {
|
|
10994
|
+
report = {};
|
|
10995
|
+
}
|
|
10996
|
+
}
|
|
10997
|
+
return report;
|
|
10998
|
+
};
|
|
10999
|
+
module.exports = { isLinux, getReport };
|
|
11000
|
+
});
|
|
11001
|
+
|
|
11002
|
+
// node_modules/detect-libc/lib/filesystem.js
|
|
11003
|
+
var require_filesystem = __commonJS((exports, module) => {
|
|
11004
|
+
var fs = __require("fs");
|
|
11005
|
+
var LDD_PATH = "/usr/bin/ldd";
|
|
11006
|
+
var SELF_PATH = "/proc/self/exe";
|
|
11007
|
+
var MAX_LENGTH = 2048;
|
|
11008
|
+
var readFileSync2 = (path) => {
|
|
11009
|
+
const fd = fs.openSync(path, "r");
|
|
11010
|
+
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
11011
|
+
const bytesRead = fs.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
11012
|
+
fs.close(fd, () => {});
|
|
11013
|
+
return buffer.subarray(0, bytesRead);
|
|
11014
|
+
};
|
|
11015
|
+
var readFile = (path) => new Promise((resolve, reject) => {
|
|
11016
|
+
fs.open(path, "r", (err, fd) => {
|
|
11017
|
+
if (err) {
|
|
11018
|
+
reject(err);
|
|
11019
|
+
} else {
|
|
11020
|
+
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
11021
|
+
fs.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
|
|
11022
|
+
resolve(buffer.subarray(0, bytesRead));
|
|
11023
|
+
fs.close(fd, () => {});
|
|
11024
|
+
});
|
|
11025
|
+
}
|
|
11026
|
+
});
|
|
11027
|
+
});
|
|
11028
|
+
module.exports = {
|
|
11029
|
+
LDD_PATH,
|
|
11030
|
+
SELF_PATH,
|
|
11031
|
+
readFileSync: readFileSync2,
|
|
11032
|
+
readFile
|
|
11033
|
+
};
|
|
11034
|
+
});
|
|
11035
|
+
|
|
11036
|
+
// node_modules/detect-libc/lib/elf.js
|
|
11037
|
+
var require_elf = __commonJS((exports, module) => {
|
|
11038
|
+
var interpreterPath = (elf) => {
|
|
11039
|
+
if (elf.length < 64) {
|
|
11040
|
+
return null;
|
|
11041
|
+
}
|
|
11042
|
+
if (elf.readUInt32BE(0) !== 2135247942) {
|
|
11043
|
+
return null;
|
|
11044
|
+
}
|
|
11045
|
+
if (elf.readUInt8(4) !== 2) {
|
|
11046
|
+
return null;
|
|
11047
|
+
}
|
|
11048
|
+
if (elf.readUInt8(5) !== 1) {
|
|
11049
|
+
return null;
|
|
10196
11050
|
}
|
|
10197
11051
|
const offset = elf.readUInt32LE(32);
|
|
10198
11052
|
const size = elf.readUInt16LE(54);
|
|
@@ -13725,7 +14579,7 @@ var require_operation = __commonJS((exports, module) => {
|
|
|
13725
14579
|
// node_modules/@img/colour/color.cjs
|
|
13726
14580
|
var require_color = __commonJS((exports, module) => {
|
|
13727
14581
|
var __defProp3 = Object.defineProperty;
|
|
13728
|
-
var
|
|
14582
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
13729
14583
|
var __getOwnPropNames3 = Object.getOwnPropertyNames;
|
|
13730
14584
|
var __hasOwnProp3 = Object.prototype.hasOwnProperty;
|
|
13731
14585
|
var __export3 = (target, all) => {
|
|
@@ -13736,16 +14590,16 @@ var require_color = __commonJS((exports, module) => {
|
|
|
13736
14590
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
13737
14591
|
for (let key of __getOwnPropNames3(from))
|
|
13738
14592
|
if (!__hasOwnProp3.call(to, key) && key !== except)
|
|
13739
|
-
__defProp3(to, key, { get: () => from[key], enumerable: !(desc =
|
|
14593
|
+
__defProp3(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
13740
14594
|
}
|
|
13741
14595
|
return to;
|
|
13742
14596
|
};
|
|
13743
|
-
var
|
|
14597
|
+
var __toCommonJS2 = (mod) => __copyProps(__defProp3({}, "__esModule", { value: true }), mod);
|
|
13744
14598
|
var index_exports = {};
|
|
13745
14599
|
__export3(index_exports, {
|
|
13746
14600
|
default: () => index_default
|
|
13747
14601
|
});
|
|
13748
|
-
module.exports =
|
|
14602
|
+
module.exports = __toCommonJS2(index_exports);
|
|
13749
14603
|
var colors = {
|
|
13750
14604
|
aliceblue: [240, 248, 255],
|
|
13751
14605
|
antiquewhite: [250, 235, 215],
|
|
@@ -17293,6 +18147,88 @@ class BunWebViewSession {
|
|
|
17293
18147
|
|
|
17294
18148
|
// src/engines/selector.ts
|
|
17295
18149
|
init_types();
|
|
18150
|
+
|
|
18151
|
+
// src/engines/tui.ts
|
|
18152
|
+
init_types();
|
|
18153
|
+
import { execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
18154
|
+
var DEFAULT_TTYD_PORT_START = 7780;
|
|
18155
|
+
var nextPort = DEFAULT_TTYD_PORT_START;
|
|
18156
|
+
function isTuiAvailable() {
|
|
18157
|
+
try {
|
|
18158
|
+
execSync2("which ttyd", { stdio: "ignore" });
|
|
18159
|
+
return true;
|
|
18160
|
+
} catch {
|
|
18161
|
+
return false;
|
|
18162
|
+
}
|
|
18163
|
+
}
|
|
18164
|
+
async function findAvailablePort(startPort) {
|
|
18165
|
+
let port = startPort;
|
|
18166
|
+
for (let i = 0;i < 100; i++) {
|
|
18167
|
+
try {
|
|
18168
|
+
const resp = await fetch(`http://localhost:${port}`);
|
|
18169
|
+
port++;
|
|
18170
|
+
} catch {
|
|
18171
|
+
return port;
|
|
18172
|
+
}
|
|
18173
|
+
}
|
|
18174
|
+
throw new BrowserError("No available port found for ttyd", "TUI_PORT_EXHAUSTED");
|
|
18175
|
+
}
|
|
18176
|
+
async function waitForTtyd(port, timeoutMs = 1e4) {
|
|
18177
|
+
const start = Date.now();
|
|
18178
|
+
while (Date.now() - start < timeoutMs) {
|
|
18179
|
+
try {
|
|
18180
|
+
const resp = await fetch(`http://localhost:${port}`);
|
|
18181
|
+
if (resp.ok || resp.status === 200)
|
|
18182
|
+
return;
|
|
18183
|
+
} catch {}
|
|
18184
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
18185
|
+
}
|
|
18186
|
+
throw new BrowserError(`ttyd did not start within ${timeoutMs}ms`, "TUI_TIMEOUT");
|
|
18187
|
+
}
|
|
18188
|
+
async function launchTui(command, options = {}) {
|
|
18189
|
+
if (!isTuiAvailable()) {
|
|
18190
|
+
throw new BrowserError("ttyd not found \u2014 install with: brew install ttyd", "TUI_NOT_AVAILABLE");
|
|
18191
|
+
}
|
|
18192
|
+
const port = await findAvailablePort(nextPort);
|
|
18193
|
+
nextPort = port + 1;
|
|
18194
|
+
const ttydProcess = spawn2("ttyd", ["--writable", "--port", String(port), "/bin/sh", "-c", command], {
|
|
18195
|
+
stdio: "ignore",
|
|
18196
|
+
detached: false
|
|
18197
|
+
});
|
|
18198
|
+
ttydProcess.on("error", (err) => {
|
|
18199
|
+
console.error(`[tui] ttyd process error: ${err.message}`);
|
|
18200
|
+
});
|
|
18201
|
+
try {
|
|
18202
|
+
await waitForTtyd(port);
|
|
18203
|
+
const viewport = options.viewport ?? { width: 1280, height: 720 };
|
|
18204
|
+
const browser = await launchPlaywright({
|
|
18205
|
+
headless: options.headless ?? true,
|
|
18206
|
+
viewport
|
|
18207
|
+
});
|
|
18208
|
+
const page = await getPage(browser, { viewport });
|
|
18209
|
+
await page.goto(`http://localhost:${port}`, {
|
|
18210
|
+
waitUntil: "domcontentloaded"
|
|
18211
|
+
});
|
|
18212
|
+
await page.waitForSelector(".xterm-screen", { timeout: 1e4 });
|
|
18213
|
+
return { ttydProcess, port, browser, page };
|
|
18214
|
+
} catch (err) {
|
|
18215
|
+
ttydProcess.kill();
|
|
18216
|
+
throw err;
|
|
18217
|
+
}
|
|
18218
|
+
}
|
|
18219
|
+
async function closeTui(session) {
|
|
18220
|
+
try {
|
|
18221
|
+
await session.page.close();
|
|
18222
|
+
} catch {}
|
|
18223
|
+
try {
|
|
18224
|
+
await session.browser.close();
|
|
18225
|
+
} catch {}
|
|
18226
|
+
try {
|
|
18227
|
+
session.ttydProcess.kill("SIGTERM");
|
|
18228
|
+
} catch {}
|
|
18229
|
+
}
|
|
18230
|
+
|
|
18231
|
+
// src/engines/selector.ts
|
|
17296
18232
|
var ENGINE_MAP = {
|
|
17297
18233
|
["scrape" /* SCRAPE */]: "bun",
|
|
17298
18234
|
["extract_links" /* EXTRACT_LINKS */]: "bun",
|
|
@@ -17303,6 +18239,7 @@ var ENGINE_MAP = {
|
|
|
17303
18239
|
["auth_flow" /* AUTH_FLOW */]: "playwright",
|
|
17304
18240
|
["multi_tab" /* MULTI_TAB */]: "playwright",
|
|
17305
18241
|
["record_replay" /* RECORD_REPLAY */]: "playwright",
|
|
18242
|
+
["terminal_test" /* TERMINAL_TEST */]: "tui",
|
|
17306
18243
|
["network_monitor" /* NETWORK_MONITOR */]: "cdp",
|
|
17307
18244
|
["har_capture" /* HAR_CAPTURE */]: "cdp",
|
|
17308
18245
|
["perf_profile" /* PERF_PROFILE */]: "cdp",
|
|
@@ -17389,6 +18326,7 @@ function enableNetworkLogging(page, sessionId) {
|
|
|
17389
18326
|
requestStart.clear();
|
|
17390
18327
|
};
|
|
17391
18328
|
}
|
|
18329
|
+
var HAR_MAX_ENTRIES = 5000;
|
|
17392
18330
|
function startHAR(page) {
|
|
17393
18331
|
const entries = [];
|
|
17394
18332
|
const requestStart = new Map;
|
|
@@ -17427,7 +18365,8 @@ function startHAR(page) {
|
|
|
17427
18365
|
},
|
|
17428
18366
|
timings: { send: 0, wait: duration, receive: 0 }
|
|
17429
18367
|
};
|
|
17430
|
-
entries.
|
|
18368
|
+
if (entries.length < HAR_MAX_ENTRIES)
|
|
18369
|
+
entries.push(entry);
|
|
17431
18370
|
};
|
|
17432
18371
|
const onRequestFailed = (req) => {
|
|
17433
18372
|
requestStart.delete(req.url() + req.method());
|
|
@@ -17545,49 +18484,8 @@ async function applyStealthPatches(page) {
|
|
|
17545
18484
|
});
|
|
17546
18485
|
}
|
|
17547
18486
|
|
|
17548
|
-
// src/lib/dialogs.ts
|
|
17549
|
-
var pendingDialogs = new Map;
|
|
17550
|
-
var AUTO_DISMISS_MS = 5000;
|
|
17551
|
-
function setupDialogHandler(page, sessionId) {
|
|
17552
|
-
const onDialog = (dialog) => {
|
|
17553
|
-
const info = {
|
|
17554
|
-
type: dialog.type(),
|
|
17555
|
-
message: dialog.message(),
|
|
17556
|
-
default_value: dialog.defaultValue(),
|
|
17557
|
-
timestamp: new Date().toISOString()
|
|
17558
|
-
};
|
|
17559
|
-
const autoTimer = setTimeout(() => {
|
|
17560
|
-
try {
|
|
17561
|
-
dialog.dismiss().catch(() => {});
|
|
17562
|
-
} catch {}
|
|
17563
|
-
const list = pendingDialogs.get(sessionId);
|
|
17564
|
-
if (list) {
|
|
17565
|
-
const idx = list.findIndex((p) => p.dialog === dialog);
|
|
17566
|
-
if (idx >= 0)
|
|
17567
|
-
list.splice(idx, 1);
|
|
17568
|
-
if (list.length === 0)
|
|
17569
|
-
pendingDialogs.delete(sessionId);
|
|
17570
|
-
}
|
|
17571
|
-
}, AUTO_DISMISS_MS);
|
|
17572
|
-
const pending = { dialog, info, autoTimer };
|
|
17573
|
-
if (!pendingDialogs.has(sessionId)) {
|
|
17574
|
-
pendingDialogs.set(sessionId, []);
|
|
17575
|
-
}
|
|
17576
|
-
pendingDialogs.get(sessionId).push(pending);
|
|
17577
|
-
};
|
|
17578
|
-
page.on("dialog", onDialog);
|
|
17579
|
-
return () => {
|
|
17580
|
-
page.off("dialog", onDialog);
|
|
17581
|
-
const list = pendingDialogs.get(sessionId);
|
|
17582
|
-
if (list) {
|
|
17583
|
-
for (const p of list)
|
|
17584
|
-
clearTimeout(p.autoTimer);
|
|
17585
|
-
pendingDialogs.delete(sessionId);
|
|
17586
|
-
}
|
|
17587
|
-
};
|
|
17588
|
-
}
|
|
17589
|
-
|
|
17590
18487
|
// src/lib/session.ts
|
|
18488
|
+
init_dialogs();
|
|
17591
18489
|
var handles = new Map;
|
|
17592
18490
|
var pool = new BrowserPool(5);
|
|
17593
18491
|
var SESSION_TTL_MS = parseInt(process.env["SESSION_TTL_MINUTES"] ?? "10", 10) * 60000;
|
|
@@ -17603,6 +18501,20 @@ var ttlInterval = setInterval(async () => {
|
|
|
17603
18501
|
}, 60000);
|
|
17604
18502
|
if (ttlInterval.unref)
|
|
17605
18503
|
ttlInterval.unref();
|
|
18504
|
+
var DB_PRUNE_INTERVAL_MS = 30 * 60000;
|
|
18505
|
+
var DB_RETENTION_HOURS = 24;
|
|
18506
|
+
var dbPruneInterval = setInterval(() => {
|
|
18507
|
+
try {
|
|
18508
|
+
const { getDatabase: getDatabase2 } = (init_schema(), __toCommonJS(exports_schema));
|
|
18509
|
+
const db = getDatabase2();
|
|
18510
|
+
const cutoff = new Date(Date.now() - DB_RETENTION_HOURS * 3600000).toISOString();
|
|
18511
|
+
db.prepare("DELETE FROM network_log WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
18512
|
+
db.prepare("DELETE FROM console_log WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
18513
|
+
db.prepare("DELETE FROM snapshots WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
18514
|
+
} catch {}
|
|
18515
|
+
}, DB_PRUNE_INTERVAL_MS);
|
|
18516
|
+
if (dbPruneInterval.unref)
|
|
18517
|
+
dbPruneInterval.unref();
|
|
17606
18518
|
function createBunProxy(view) {
|
|
17607
18519
|
return view;
|
|
17608
18520
|
}
|
|
@@ -17635,7 +18547,7 @@ async function createSession2(opts = {}) {
|
|
|
17635
18547
|
try {
|
|
17636
18548
|
cleanups2.push(setupDialogHandler(page2, session2.id));
|
|
17637
18549
|
} catch {}
|
|
17638
|
-
handles.set(session2.id, { browser: cdpBrowser, bunView: null, page: page2, engine: "cdp", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
18550
|
+
handles.set(session2.id, { browser: cdpBrowser, bunView: null, tuiSession: null, page: page2, engine: "cdp", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
17639
18551
|
return { session: session2, page: page2 };
|
|
17640
18552
|
}
|
|
17641
18553
|
const engine = opts.engine === "auto" || !opts.engine ? selectEngine(opts.useCase ?? "spa_navigate" /* SPA_NAVIGATE */, opts.engine) : opts.engine;
|
|
@@ -17661,6 +18573,38 @@ async function createSession2(opts = {}) {
|
|
|
17661
18573
|
browser = await connectLightpanda();
|
|
17662
18574
|
const context = await browser.newContext({ viewport: opts.viewport ?? { width: 1280, height: 720 } });
|
|
17663
18575
|
page = await context.newPage();
|
|
18576
|
+
} else if (resolvedEngine === "tui") {
|
|
18577
|
+
const command = opts.startUrl ?? "bash";
|
|
18578
|
+
const tuiSess = await launchTui(command, {
|
|
18579
|
+
headless: opts.headless ?? true,
|
|
18580
|
+
viewport: opts.viewport
|
|
18581
|
+
});
|
|
18582
|
+
browser = tuiSess.browser;
|
|
18583
|
+
page = tuiSess.page;
|
|
18584
|
+
const session2 = createSession({
|
|
18585
|
+
engine: "tui",
|
|
18586
|
+
projectId: opts.projectId,
|
|
18587
|
+
agentId: opts.agentId,
|
|
18588
|
+
startUrl: opts.startUrl,
|
|
18589
|
+
name: opts.name ?? "tui"
|
|
18590
|
+
});
|
|
18591
|
+
const cleanups2 = [];
|
|
18592
|
+
cleanups2.push(() => closeTui(tuiSess));
|
|
18593
|
+
if (opts.captureNetwork !== false) {
|
|
18594
|
+
try {
|
|
18595
|
+
cleanups2.push(enableNetworkLogging(page, session2.id));
|
|
18596
|
+
} catch {}
|
|
18597
|
+
}
|
|
18598
|
+
if (opts.captureConsole !== false) {
|
|
18599
|
+
try {
|
|
18600
|
+
cleanups2.push(enableConsoleCapture(page, session2.id));
|
|
18601
|
+
} catch {}
|
|
18602
|
+
}
|
|
18603
|
+
try {
|
|
18604
|
+
cleanups2.push(setupDialogHandler(page, session2.id));
|
|
18605
|
+
} catch {}
|
|
18606
|
+
handles.set(session2.id, { browser, bunView: null, tuiSession: tuiSess, page, engine: "tui", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
18607
|
+
return { session: session2, page };
|
|
17664
18608
|
} else {
|
|
17665
18609
|
browser = await pool.acquire(opts.headless ?? true);
|
|
17666
18610
|
if (opts.storageState) {
|
|
@@ -17731,7 +18675,7 @@ async function createSession2(opts = {}) {
|
|
|
17731
18675
|
} catch {}
|
|
17732
18676
|
}
|
|
17733
18677
|
}
|
|
17734
|
-
handles.set(session.id, { browser, bunView, page, engine: bunView ? "bun" : resolvedEngine, cleanups, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
18678
|
+
handles.set(session.id, { browser, bunView, tuiSession: null, page, engine: bunView ? "bun" : resolvedEngine, cleanups, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
17735
18679
|
if (opts.startUrl) {
|
|
17736
18680
|
try {
|
|
17737
18681
|
if (bunView) {
|
|
@@ -17772,7 +18716,7 @@ async function closeSession2(sessionId) {
|
|
|
17772
18716
|
try {
|
|
17773
18717
|
await handle.bunView.close();
|
|
17774
18718
|
} catch {}
|
|
17775
|
-
} else {
|
|
18719
|
+
} else if (handle.tuiSession) {} else {
|
|
17776
18720
|
try {
|
|
17777
18721
|
await handle.page.context().close();
|
|
17778
18722
|
} catch {}
|
|
@@ -17781,142 +18725,27 @@ async function closeSession2(sessionId) {
|
|
|
17781
18725
|
}
|
|
17782
18726
|
handles.delete(sessionId);
|
|
17783
18727
|
}
|
|
17784
|
-
return closeSession(sessionId);
|
|
17785
|
-
}
|
|
17786
|
-
function listSessions2(filter) {
|
|
17787
|
-
return listSessions(filter);
|
|
17788
|
-
}
|
|
17789
|
-
|
|
17790
|
-
// src/lib/actions.ts
|
|
17791
|
-
init_types();
|
|
17792
|
-
|
|
17793
|
-
// src/lib/snapshot.ts
|
|
17794
|
-
var lastSnapshots = new Map;
|
|
17795
|
-
var sessionRefMaps = new Map;
|
|
17796
|
-
|
|
17797
|
-
// src/lib/self-heal.ts
|
|
17798
|
-
async function healSelector(page, selector, sessionId) {
|
|
17799
|
-
const attempts = [];
|
|
17800
|
-
attempts.push(`selector: ${selector}`);
|
|
17801
18728
|
try {
|
|
17802
|
-
const
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
}
|
|
18729
|
+
const { clearLastSnapshot: clearLastSnapshot2, clearSessionRefs: clearSessionRefs2 } = await Promise.resolve().then(() => (init_snapshot(), exports_snapshot));
|
|
18730
|
+
clearLastSnapshot2(sessionId);
|
|
18731
|
+
clearSessionRefs2(sessionId);
|
|
17806
18732
|
} catch {}
|
|
17807
|
-
if (!selector.startsWith("#") && !selector.startsWith(".") && !selector.startsWith("[") && !selector.includes(">") && !selector.includes(" ")) {
|
|
17808
|
-
attempts.push(`text: "${selector}"`);
|
|
17809
|
-
try {
|
|
17810
|
-
const loc = page.getByText(selector, { exact: false }).first();
|
|
17811
|
-
if (await loc.count() > 0) {
|
|
17812
|
-
return { found: true, locator: loc, method: "text", healed: true, attempts };
|
|
17813
|
-
}
|
|
17814
|
-
} catch {}
|
|
17815
|
-
}
|
|
17816
|
-
const roleMap = {
|
|
17817
|
-
button: ["button", "submit", "reset"],
|
|
17818
|
-
link: ["a"],
|
|
17819
|
-
input: ["input", "textarea"],
|
|
17820
|
-
heading: ["h1", "h2", "h3", "h4", "h5", "h6"]
|
|
17821
|
-
};
|
|
17822
|
-
const nameHint = selector.replace(/^[#.]/, "").replace(/[-_]/g, " ").toLowerCase();
|
|
17823
|
-
for (const [role, tags] of Object.entries(roleMap)) {
|
|
17824
|
-
attempts.push(`role: ${role} name~="${nameHint}"`);
|
|
17825
|
-
try {
|
|
17826
|
-
const loc = page.getByRole(role, { name: new RegExp(nameHint.split(" ")[0], "i") }).first();
|
|
17827
|
-
if (await loc.count() > 0) {
|
|
17828
|
-
return { found: true, locator: loc, method: "role", healed: true, attempts };
|
|
17829
|
-
}
|
|
17830
|
-
} catch {}
|
|
17831
|
-
}
|
|
17832
|
-
if (selector.startsWith("#")) {
|
|
17833
|
-
const idPart = selector.slice(1).split("-").pop() ?? selector.slice(1);
|
|
17834
|
-
const partialSel = `[id*="${idPart}"]`;
|
|
17835
|
-
attempts.push(`partial_id: ${partialSel}`);
|
|
17836
|
-
try {
|
|
17837
|
-
const loc = page.locator(partialSel).first();
|
|
17838
|
-
if (await loc.count() > 0) {
|
|
17839
|
-
return { found: true, locator: loc, method: "partial_id", healed: true, attempts };
|
|
17840
|
-
}
|
|
17841
|
-
} catch {}
|
|
17842
|
-
}
|
|
17843
|
-
if (selector.startsWith(".")) {
|
|
17844
|
-
const classPart = selector.slice(1).split("-").pop() ?? selector.slice(1);
|
|
17845
|
-
const partialSel = `[class*="${classPart}"]`;
|
|
17846
|
-
attempts.push(`partial_class: ${partialSel}`);
|
|
17847
|
-
try {
|
|
17848
|
-
const loc = page.locator(partialSel).first();
|
|
17849
|
-
if (await loc.count() > 0) {
|
|
17850
|
-
return { found: true, locator: loc, method: "partial_class", healed: true, attempts };
|
|
17851
|
-
}
|
|
17852
|
-
} catch {}
|
|
17853
|
-
}
|
|
17854
|
-
return { found: false, locator: null, method: "none", healed: false, attempts };
|
|
17855
|
-
}
|
|
17856
|
-
|
|
17857
|
-
// src/lib/actions.ts
|
|
17858
|
-
async function click(page, selector, opts) {
|
|
17859
18733
|
try {
|
|
17860
|
-
await
|
|
17861
|
-
|
|
17862
|
-
|
|
17863
|
-
delay: opts?.delay,
|
|
17864
|
-
timeout: opts?.timeout ?? 1e4
|
|
17865
|
-
});
|
|
17866
|
-
return {};
|
|
17867
|
-
} catch (originalError) {
|
|
17868
|
-
if (opts?.selfHeal !== false) {
|
|
17869
|
-
const result = await healSelector(page, selector);
|
|
17870
|
-
if (result.found && result.locator) {
|
|
17871
|
-
await result.locator.click({
|
|
17872
|
-
button: opts?.button ?? "left",
|
|
17873
|
-
timeout: opts?.timeout ?? 1e4
|
|
17874
|
-
});
|
|
17875
|
-
return { healed: true, method: result.method, attempts: result.attempts };
|
|
17876
|
-
}
|
|
17877
|
-
}
|
|
17878
|
-
if (originalError instanceof Error && originalError.message.includes("not found")) {
|
|
17879
|
-
throw new ElementNotFoundError(selector);
|
|
17880
|
-
}
|
|
17881
|
-
throw new BrowserError(`Click failed on '${selector}': ${originalError instanceof Error ? originalError.message : String(originalError)}`, "CLICK_FAILED");
|
|
17882
|
-
}
|
|
17883
|
-
}
|
|
17884
|
-
async function type(page, selector, text, opts) {
|
|
18734
|
+
const { stopAllWatchesForSession: stopAllWatchesForSession2 } = await Promise.resolve().then(() => (init_actions(), exports_actions));
|
|
18735
|
+
stopAllWatchesForSession2(sessionId);
|
|
18736
|
+
} catch {}
|
|
17885
18737
|
try {
|
|
17886
|
-
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
return {};
|
|
17891
|
-
} catch (originalError) {
|
|
17892
|
-
if (opts?.selfHeal !== false) {
|
|
17893
|
-
const result = await healSelector(page, selector);
|
|
17894
|
-
if (result.found && result.locator) {
|
|
17895
|
-
if (opts?.clear)
|
|
17896
|
-
await result.locator.fill("", { timeout: opts?.timeout ?? 1e4 });
|
|
17897
|
-
await result.locator.pressSequentially(text, { delay: opts?.delay, timeout: opts?.timeout ?? 1e4 });
|
|
17898
|
-
return { healed: true, method: result.method, attempts: result.attempts };
|
|
17899
|
-
}
|
|
17900
|
-
}
|
|
17901
|
-
if (originalError instanceof Error && originalError.message.includes("not found")) {
|
|
17902
|
-
throw new ElementNotFoundError(selector);
|
|
17903
|
-
}
|
|
17904
|
-
throw new BrowserError(`Type failed on '${selector}': ${originalError instanceof Error ? originalError.message : String(originalError)}`, "TYPE_FAILED");
|
|
17905
|
-
}
|
|
17906
|
-
}
|
|
17907
|
-
async function scroll(page, direction = "down", amount = 300) {
|
|
17908
|
-
const x = direction === "left" ? -amount : direction === "right" ? amount : 0;
|
|
17909
|
-
const y = direction === "up" ? -amount : direction === "down" ? amount : 0;
|
|
17910
|
-
await page.evaluate(({ x: x2, y: y2 }) => window.scrollBy(x2, y2), { x, y });
|
|
18738
|
+
const { clearDialogs: clearDialogs2 } = await Promise.resolve().then(() => (init_dialogs(), exports_dialogs));
|
|
18739
|
+
clearDialogs2(sessionId);
|
|
18740
|
+
} catch {}
|
|
18741
|
+
return closeSession(sessionId);
|
|
17911
18742
|
}
|
|
17912
|
-
|
|
17913
|
-
|
|
17914
|
-
await page.goto(url, { waitUntil: "domcontentloaded", timeout });
|
|
17915
|
-
} catch (err) {
|
|
17916
|
-
throw new NavigationError(url, err instanceof Error ? err.message : String(err));
|
|
17917
|
-
}
|
|
18743
|
+
function listSessions2(filter) {
|
|
18744
|
+
return listSessions(filter);
|
|
17918
18745
|
}
|
|
17919
|
-
|
|
18746
|
+
|
|
18747
|
+
// src/server/index.ts
|
|
18748
|
+
init_actions();
|
|
17920
18749
|
|
|
17921
18750
|
// src/lib/extractor.ts
|
|
17922
18751
|
async function getText(page, selector) {
|
|
@@ -18398,6 +19227,7 @@ async function crawl(startUrl, opts = {}) {
|
|
|
18398
19227
|
|
|
18399
19228
|
// src/lib/recorder.ts
|
|
18400
19229
|
init_recordings();
|
|
19230
|
+
init_actions();
|
|
18401
19231
|
init_types();
|
|
18402
19232
|
var activeRecordings = new Map;
|
|
18403
19233
|
async function replayRecording(recordingId, page) {
|