opensteer 0.4.5 → 0.4.6
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/bin/opensteer.mjs +0 -3
- package/dist/{chunk-2NKR4JZ6.js → chunk-MGZ3QEYT.js} +663 -99
- package/dist/cli/server.cjs +663 -99
- package/dist/cli/server.js +1 -1
- package/dist/index.cjs +663 -99
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1026,11 +1026,33 @@ function parseMode(value, source) {
|
|
|
1026
1026
|
`Invalid ${source} value "${value}". Use "local" or "remote".`
|
|
1027
1027
|
);
|
|
1028
1028
|
}
|
|
1029
|
+
function parseAuthScheme(value, source) {
|
|
1030
|
+
if (value == null) return void 0;
|
|
1031
|
+
if (typeof value !== "string") {
|
|
1032
|
+
throw new Error(
|
|
1033
|
+
`Invalid ${source} value "${String(value)}". Use "api-key" or "bearer".`
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
const normalized = value.trim().toLowerCase();
|
|
1037
|
+
if (!normalized) return void 0;
|
|
1038
|
+
if (normalized === "api-key" || normalized === "bearer") {
|
|
1039
|
+
return normalized;
|
|
1040
|
+
}
|
|
1041
|
+
throw new Error(
|
|
1042
|
+
`Invalid ${source} value "${value}". Use "api-key" or "bearer".`
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1029
1045
|
function resolveOpensteerApiKey() {
|
|
1030
1046
|
const value = process.env.OPENSTEER_API_KEY?.trim();
|
|
1031
1047
|
if (!value) return void 0;
|
|
1032
1048
|
return value;
|
|
1033
1049
|
}
|
|
1050
|
+
function resolveOpensteerAuthScheme() {
|
|
1051
|
+
return parseAuthScheme(
|
|
1052
|
+
process.env.OPENSTEER_AUTH_SCHEME,
|
|
1053
|
+
"OPENSTEER_AUTH_SCHEME"
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1034
1056
|
function normalizeRemoteOptions(value) {
|
|
1035
1057
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1036
1058
|
return void 0;
|
|
@@ -1090,7 +1112,12 @@ function resolveConfig(input = {}) {
|
|
|
1090
1112
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
1091
1113
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
1092
1114
|
const envApiKey = resolveOpensteerApiKey();
|
|
1115
|
+
const envAuthScheme = resolveOpensteerAuthScheme();
|
|
1093
1116
|
const inputRemoteOptions = normalizeRemoteOptions(input.remote);
|
|
1117
|
+
const inputAuthScheme = parseAuthScheme(
|
|
1118
|
+
inputRemoteOptions?.authScheme,
|
|
1119
|
+
"remote.authScheme"
|
|
1120
|
+
);
|
|
1094
1121
|
const inputHasRemoteApiKey = Boolean(
|
|
1095
1122
|
inputRemoteOptions && Object.prototype.hasOwnProperty.call(inputRemoteOptions, "apiKey")
|
|
1096
1123
|
);
|
|
@@ -1098,8 +1125,12 @@ function resolveConfig(input = {}) {
|
|
|
1098
1125
|
mode: resolved.mode
|
|
1099
1126
|
});
|
|
1100
1127
|
if (modeSelection.mode === "remote") {
|
|
1101
|
-
const resolvedRemote = normalizeRemoteOptions(resolved.remote);
|
|
1102
|
-
|
|
1128
|
+
const resolvedRemote = normalizeRemoteOptions(resolved.remote) ?? {};
|
|
1129
|
+
const authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedRemote.authScheme, "remote.authScheme") ?? "api-key";
|
|
1130
|
+
resolved.remote = {
|
|
1131
|
+
...resolvedRemote,
|
|
1132
|
+
authScheme
|
|
1133
|
+
};
|
|
1103
1134
|
}
|
|
1104
1135
|
if (envApiKey && modeSelection.mode === "remote" && !inputHasRemoteApiKey) {
|
|
1105
1136
|
resolved.remote = {
|
|
@@ -1146,15 +1177,52 @@ function getCallerFilePath() {
|
|
|
1146
1177
|
// src/navigation.ts
|
|
1147
1178
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1148
1179
|
var DEFAULT_SETTLE_MS = 750;
|
|
1180
|
+
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
1181
|
+
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
1182
|
+
var StealthWaitUnavailableError = class extends Error {
|
|
1183
|
+
constructor(cause) {
|
|
1184
|
+
super("Stealth visual wait requires Chromium CDP support.", { cause });
|
|
1185
|
+
this.name = "StealthWaitUnavailableError";
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
function isStealthWaitUnavailableError(error) {
|
|
1189
|
+
return error instanceof StealthWaitUnavailableError;
|
|
1190
|
+
}
|
|
1191
|
+
var FRAME_OWNER_VISIBILITY_FUNCTION = `function() {
|
|
1192
|
+
if (!(this instanceof HTMLElement)) return false;
|
|
1193
|
+
|
|
1194
|
+
var rect = this.getBoundingClientRect();
|
|
1195
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
1196
|
+
if (
|
|
1197
|
+
rect.bottom <= 0 ||
|
|
1198
|
+
rect.right <= 0 ||
|
|
1199
|
+
rect.top >= window.innerHeight ||
|
|
1200
|
+
rect.left >= window.innerWidth
|
|
1201
|
+
) {
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
var style = window.getComputedStyle(this);
|
|
1206
|
+
if (
|
|
1207
|
+
style.display === 'none' ||
|
|
1208
|
+
style.visibility === 'hidden' ||
|
|
1209
|
+
Number(style.opacity) === 0
|
|
1210
|
+
) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
return true;
|
|
1215
|
+
}`;
|
|
1149
1216
|
function buildStabilityScript(timeout, settleMs) {
|
|
1150
1217
|
return `new Promise(function(resolve) {
|
|
1151
1218
|
var deadline = Date.now() + ${timeout};
|
|
1152
|
-
var timer = null;
|
|
1153
1219
|
var resolved = false;
|
|
1220
|
+
var timer = null;
|
|
1154
1221
|
var observers = [];
|
|
1155
1222
|
var observedShadowRoots = [];
|
|
1156
1223
|
var fonts = document.fonts;
|
|
1157
1224
|
var fontsReady = !fonts || fonts.status === 'loaded';
|
|
1225
|
+
var lastRelevantMutationAt = Date.now();
|
|
1158
1226
|
|
|
1159
1227
|
function clearObservers() {
|
|
1160
1228
|
for (var i = 0; i < observers.length; i++) {
|
|
@@ -1172,9 +1240,87 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1172
1240
|
resolve();
|
|
1173
1241
|
}
|
|
1174
1242
|
|
|
1243
|
+
function isElementVisiblyIntersectingViewport(element) {
|
|
1244
|
+
if (!(element instanceof Element)) return false;
|
|
1245
|
+
|
|
1246
|
+
var rect = element.getBoundingClientRect();
|
|
1247
|
+
var inViewport =
|
|
1248
|
+
rect.width > 0 &&
|
|
1249
|
+
rect.height > 0 &&
|
|
1250
|
+
rect.bottom > 0 &&
|
|
1251
|
+
rect.right > 0 &&
|
|
1252
|
+
rect.top < window.innerHeight &&
|
|
1253
|
+
rect.left < window.innerWidth;
|
|
1254
|
+
|
|
1255
|
+
if (!inViewport) return false;
|
|
1256
|
+
|
|
1257
|
+
var style = window.getComputedStyle(element);
|
|
1258
|
+
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1261
|
+
if (Number(style.opacity) === 0) {
|
|
1262
|
+
return false;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
return true;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
function resolveRelevantElement(node) {
|
|
1269
|
+
if (!node) return null;
|
|
1270
|
+
if (node instanceof Element) return node;
|
|
1271
|
+
if (typeof ShadowRoot !== 'undefined' && node instanceof ShadowRoot) {
|
|
1272
|
+
return node.host instanceof Element ? node.host : null;
|
|
1273
|
+
}
|
|
1274
|
+
var parentElement = node.parentElement;
|
|
1275
|
+
return parentElement instanceof Element ? parentElement : null;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
function isNodeVisiblyRelevant(node) {
|
|
1279
|
+
var element = resolveRelevantElement(node);
|
|
1280
|
+
if (!element) return false;
|
|
1281
|
+
return isElementVisiblyIntersectingViewport(element);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
function hasRelevantMutation(records) {
|
|
1285
|
+
for (var i = 0; i < records.length; i++) {
|
|
1286
|
+
var record = records[i];
|
|
1287
|
+
if (isNodeVisiblyRelevant(record.target)) return true;
|
|
1288
|
+
|
|
1289
|
+
var addedNodes = record.addedNodes;
|
|
1290
|
+
for (var j = 0; j < addedNodes.length; j++) {
|
|
1291
|
+
if (isNodeVisiblyRelevant(addedNodes[j])) return true;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
var removedNodes = record.removedNodes;
|
|
1295
|
+
for (var k = 0; k < removedNodes.length; k++) {
|
|
1296
|
+
if (isNodeVisiblyRelevant(removedNodes[k])) return true;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
function scheduleCheck() {
|
|
1304
|
+
if (resolved) return;
|
|
1305
|
+
if (timer) clearTimeout(timer);
|
|
1306
|
+
|
|
1307
|
+
var remaining = deadline - Date.now();
|
|
1308
|
+
if (remaining <= 0) {
|
|
1309
|
+
done();
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
var checkDelay = Math.min(120, Math.max(16, ${settleMs}));
|
|
1314
|
+
timer = setTimeout(checkNow, checkDelay);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1175
1317
|
function observeMutations(target) {
|
|
1176
1318
|
if (!target) return;
|
|
1177
|
-
var observer = new MutationObserver(function() {
|
|
1319
|
+
var observer = new MutationObserver(function(records) {
|
|
1320
|
+
if (!hasRelevantMutation(records)) return;
|
|
1321
|
+
lastRelevantMutationAt = Date.now();
|
|
1322
|
+
scheduleCheck();
|
|
1323
|
+
});
|
|
1178
1324
|
observer.observe(target, {
|
|
1179
1325
|
childList: true,
|
|
1180
1326
|
subtree: true,
|
|
@@ -1212,18 +1358,25 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1212
1358
|
var images = root.querySelectorAll('img');
|
|
1213
1359
|
for (var i = 0; i < images.length; i++) {
|
|
1214
1360
|
var img = images[i];
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
rect.bottom > 0 &&
|
|
1218
|
-
rect.right > 0 &&
|
|
1219
|
-
rect.top < window.innerHeight &&
|
|
1220
|
-
rect.left < window.innerWidth;
|
|
1221
|
-
if (inViewport && !img.complete) return false;
|
|
1361
|
+
if (!isElementVisiblyIntersectingViewport(img)) continue;
|
|
1362
|
+
if (!img.complete) return false;
|
|
1222
1363
|
}
|
|
1223
1364
|
return true;
|
|
1224
1365
|
}
|
|
1225
1366
|
|
|
1226
|
-
function
|
|
1367
|
+
function getAnimationTarget(effect) {
|
|
1368
|
+
if (!effect) return null;
|
|
1369
|
+
var target = effect.target;
|
|
1370
|
+
if (target instanceof Element) return target;
|
|
1371
|
+
|
|
1372
|
+
if (target && target.element instanceof Element) {
|
|
1373
|
+
return target.element;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
return null;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
function hasRunningVisibleFiniteAnimations() {
|
|
1227
1380
|
if (typeof document.getAnimations !== 'function') return false;
|
|
1228
1381
|
var animations = document.getAnimations();
|
|
1229
1382
|
|
|
@@ -1237,6 +1390,9 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1237
1390
|
? timing.endTime
|
|
1238
1391
|
: Number.POSITIVE_INFINITY;
|
|
1239
1392
|
if (Number.isFinite(endTime) && endTime > 0) {
|
|
1393
|
+
var target = getAnimationTarget(effect);
|
|
1394
|
+
if (!target) continue;
|
|
1395
|
+
if (!isElementVisiblyIntersectingViewport(target)) continue;
|
|
1240
1396
|
return true;
|
|
1241
1397
|
}
|
|
1242
1398
|
}
|
|
@@ -1247,21 +1403,29 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1247
1403
|
function isVisuallyReady() {
|
|
1248
1404
|
if (!fontsReady) return false;
|
|
1249
1405
|
if (!checkViewportImages(document)) return false;
|
|
1250
|
-
if (
|
|
1406
|
+
if (hasRunningVisibleFiniteAnimations()) return false;
|
|
1251
1407
|
return true;
|
|
1252
1408
|
}
|
|
1253
1409
|
|
|
1254
|
-
function
|
|
1255
|
-
if (Date.now()
|
|
1256
|
-
|
|
1410
|
+
function checkNow() {
|
|
1411
|
+
if (Date.now() >= deadline) {
|
|
1412
|
+
done();
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1257
1416
|
observeOpenShadowRoots();
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1417
|
+
|
|
1418
|
+
if (!isVisuallyReady()) {
|
|
1419
|
+
scheduleCheck();
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
if (Date.now() - lastRelevantMutationAt >= ${settleMs}) {
|
|
1424
|
+
done();
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
scheduleCheck();
|
|
1265
1429
|
}
|
|
1266
1430
|
|
|
1267
1431
|
observeMutations(document.documentElement);
|
|
@@ -1270,67 +1434,266 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1270
1434
|
if (fonts && fonts.ready && typeof fonts.ready.then === 'function') {
|
|
1271
1435
|
fonts.ready.then(function() {
|
|
1272
1436
|
fontsReady = true;
|
|
1273
|
-
|
|
1437
|
+
scheduleCheck();
|
|
1438
|
+
}, function() {
|
|
1439
|
+
fontsReady = true;
|
|
1440
|
+
scheduleCheck();
|
|
1274
1441
|
});
|
|
1275
1442
|
}
|
|
1276
1443
|
|
|
1277
1444
|
var safetyTimer = setTimeout(done, ${timeout});
|
|
1278
1445
|
|
|
1279
|
-
|
|
1446
|
+
scheduleCheck();
|
|
1280
1447
|
})`;
|
|
1281
1448
|
}
|
|
1449
|
+
var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
1450
|
+
constructor(session) {
|
|
1451
|
+
this.session = session;
|
|
1452
|
+
}
|
|
1453
|
+
contextsByFrame = /* @__PURE__ */ new Map();
|
|
1454
|
+
disposed = false;
|
|
1455
|
+
static async create(page) {
|
|
1456
|
+
let session;
|
|
1457
|
+
try {
|
|
1458
|
+
session = await page.context().newCDPSession(page);
|
|
1459
|
+
} catch (error) {
|
|
1460
|
+
throw new StealthWaitUnavailableError(error);
|
|
1461
|
+
}
|
|
1462
|
+
const runtime = new _StealthCdpRuntime(session);
|
|
1463
|
+
try {
|
|
1464
|
+
await runtime.initialize();
|
|
1465
|
+
return runtime;
|
|
1466
|
+
} catch (error) {
|
|
1467
|
+
await runtime.dispose();
|
|
1468
|
+
throw new StealthWaitUnavailableError(error);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
async dispose() {
|
|
1472
|
+
if (this.disposed) return;
|
|
1473
|
+
this.disposed = true;
|
|
1474
|
+
this.contextsByFrame.clear();
|
|
1475
|
+
await this.session.detach().catch(() => void 0);
|
|
1476
|
+
}
|
|
1477
|
+
async waitForMainFrameVisualStability(options) {
|
|
1478
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
1479
|
+
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1480
|
+
if (timeout <= 0) return;
|
|
1481
|
+
const frameRecords = await this.getFrameRecords();
|
|
1482
|
+
const mainFrame = frameRecords[0];
|
|
1483
|
+
if (!mainFrame) return;
|
|
1484
|
+
await this.waitForFrameVisualStability(mainFrame.frameId, timeout, settleMs);
|
|
1485
|
+
}
|
|
1486
|
+
async collectVisibleFrameIds() {
|
|
1487
|
+
const frameRecords = await this.getFrameRecords();
|
|
1488
|
+
if (frameRecords.length === 0) return [];
|
|
1489
|
+
const visibleFrameIds = [];
|
|
1490
|
+
for (const frameRecord of frameRecords) {
|
|
1491
|
+
if (!frameRecord.parentFrameId) {
|
|
1492
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
try {
|
|
1496
|
+
const parentContextId = await this.ensureFrameContextId(
|
|
1497
|
+
frameRecord.parentFrameId
|
|
1498
|
+
);
|
|
1499
|
+
const visible = await this.isFrameOwnerVisible(
|
|
1500
|
+
frameRecord.frameId,
|
|
1501
|
+
parentContextId
|
|
1502
|
+
);
|
|
1503
|
+
if (visible) {
|
|
1504
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
1505
|
+
}
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
if (isIgnorableFrameError(error)) continue;
|
|
1508
|
+
throw error;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
return visibleFrameIds;
|
|
1512
|
+
}
|
|
1513
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs) {
|
|
1514
|
+
if (timeout <= 0) return;
|
|
1515
|
+
const script = buildStabilityScript(timeout, settleMs);
|
|
1516
|
+
let contextId = await this.ensureFrameContextId(frameId);
|
|
1517
|
+
try {
|
|
1518
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1519
|
+
} catch (error) {
|
|
1520
|
+
if (!isMissingExecutionContextError(error)) {
|
|
1521
|
+
throw error;
|
|
1522
|
+
}
|
|
1523
|
+
this.contextsByFrame.delete(frameId);
|
|
1524
|
+
contextId = await this.ensureFrameContextId(frameId);
|
|
1525
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
async initialize() {
|
|
1529
|
+
await this.session.send("Page.enable");
|
|
1530
|
+
await this.session.send("Runtime.enable");
|
|
1531
|
+
await this.session.send("DOM.enable");
|
|
1532
|
+
}
|
|
1533
|
+
async getFrameRecords() {
|
|
1534
|
+
const treeResult = await this.session.send("Page.getFrameTree");
|
|
1535
|
+
const records = [];
|
|
1536
|
+
walkFrameTree(treeResult.frameTree, null, records);
|
|
1537
|
+
return records;
|
|
1538
|
+
}
|
|
1539
|
+
async ensureFrameContextId(frameId) {
|
|
1540
|
+
const cached = this.contextsByFrame.get(frameId);
|
|
1541
|
+
if (cached != null) {
|
|
1542
|
+
return cached;
|
|
1543
|
+
}
|
|
1544
|
+
const world = await this.session.send("Page.createIsolatedWorld", {
|
|
1545
|
+
frameId,
|
|
1546
|
+
worldName: STEALTH_WORLD_NAME
|
|
1547
|
+
});
|
|
1548
|
+
this.contextsByFrame.set(frameId, world.executionContextId);
|
|
1549
|
+
return world.executionContextId;
|
|
1550
|
+
}
|
|
1551
|
+
async evaluateWithGuard(contextId, script, timeout) {
|
|
1552
|
+
const evaluationPromise = this.evaluateScript(contextId, script);
|
|
1553
|
+
const settledPromise = evaluationPromise.then(
|
|
1554
|
+
() => ({ kind: "resolved" }),
|
|
1555
|
+
(error) => ({ kind: "rejected", error })
|
|
1556
|
+
);
|
|
1557
|
+
const timeoutPromise = sleep(
|
|
1558
|
+
timeout + FRAME_EVALUATE_GRACE_MS
|
|
1559
|
+
).then(() => ({ kind: "timeout" }));
|
|
1560
|
+
const result = await Promise.race([
|
|
1561
|
+
settledPromise,
|
|
1562
|
+
timeoutPromise
|
|
1563
|
+
]);
|
|
1564
|
+
if (result.kind === "rejected") {
|
|
1565
|
+
throw result.error;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
async evaluateScript(contextId, expression) {
|
|
1569
|
+
const result = await this.session.send("Runtime.evaluate", {
|
|
1570
|
+
contextId,
|
|
1571
|
+
expression,
|
|
1572
|
+
awaitPromise: true,
|
|
1573
|
+
returnByValue: true
|
|
1574
|
+
});
|
|
1575
|
+
if (result.exceptionDetails) {
|
|
1576
|
+
throw new Error(formatCdpException(result.exceptionDetails));
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
async isFrameOwnerVisible(frameId, parentContextId) {
|
|
1580
|
+
const owner = await this.session.send("DOM.getFrameOwner", {
|
|
1581
|
+
frameId
|
|
1582
|
+
});
|
|
1583
|
+
const resolveParams = {
|
|
1584
|
+
executionContextId: parentContextId
|
|
1585
|
+
};
|
|
1586
|
+
if (typeof owner.backendNodeId === "number") {
|
|
1587
|
+
resolveParams.backendNodeId = owner.backendNodeId;
|
|
1588
|
+
} else if (typeof owner.nodeId === "number") {
|
|
1589
|
+
resolveParams.nodeId = owner.nodeId;
|
|
1590
|
+
} else {
|
|
1591
|
+
return false;
|
|
1592
|
+
}
|
|
1593
|
+
const resolved = await this.session.send(
|
|
1594
|
+
"DOM.resolveNode",
|
|
1595
|
+
resolveParams
|
|
1596
|
+
);
|
|
1597
|
+
const objectId = resolved.object?.objectId;
|
|
1598
|
+
if (!objectId) return false;
|
|
1599
|
+
try {
|
|
1600
|
+
const callResult = await this.session.send("Runtime.callFunctionOn", {
|
|
1601
|
+
objectId,
|
|
1602
|
+
functionDeclaration: FRAME_OWNER_VISIBILITY_FUNCTION,
|
|
1603
|
+
returnByValue: true
|
|
1604
|
+
});
|
|
1605
|
+
if (callResult.exceptionDetails) {
|
|
1606
|
+
throw new Error(formatCdpException(callResult.exceptionDetails));
|
|
1607
|
+
}
|
|
1608
|
+
return callResult.result.value === true;
|
|
1609
|
+
} finally {
|
|
1610
|
+
await this.releaseObject(objectId);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
async releaseObject(objectId) {
|
|
1614
|
+
await this.session.send("Runtime.releaseObject", {
|
|
1615
|
+
objectId
|
|
1616
|
+
}).catch(() => void 0);
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1282
1619
|
async function waitForVisualStability(page, options = {}) {
|
|
1283
|
-
const
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1620
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
1621
|
+
try {
|
|
1622
|
+
await runtime.waitForMainFrameVisualStability(options);
|
|
1623
|
+
} finally {
|
|
1624
|
+
await runtime.dispose();
|
|
1625
|
+
}
|
|
1289
1626
|
}
|
|
1290
1627
|
async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
1291
1628
|
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
1292
1629
|
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1630
|
+
if (timeout <= 0) return;
|
|
1293
1631
|
const deadline = Date.now() + timeout;
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1632
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
1633
|
+
try {
|
|
1634
|
+
while (true) {
|
|
1635
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
1636
|
+
if (remaining === 0) return;
|
|
1637
|
+
const frameIds = await runtime.collectVisibleFrameIds();
|
|
1638
|
+
if (frameIds.length === 0) return;
|
|
1639
|
+
await Promise.all(
|
|
1640
|
+
frameIds.map(async (frameId) => {
|
|
1641
|
+
try {
|
|
1642
|
+
await runtime.waitForFrameVisualStability(
|
|
1643
|
+
frameId,
|
|
1644
|
+
remaining,
|
|
1645
|
+
settleMs
|
|
1646
|
+
);
|
|
1647
|
+
} catch (error) {
|
|
1648
|
+
if (isIgnorableFrameError(error)) return;
|
|
1649
|
+
throw error;
|
|
1650
|
+
}
|
|
1651
|
+
})
|
|
1652
|
+
);
|
|
1653
|
+
const currentFrameIds = await runtime.collectVisibleFrameIds();
|
|
1654
|
+
if (sameFrameIds(frameIds, currentFrameIds)) {
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1314
1657
|
}
|
|
1658
|
+
} finally {
|
|
1659
|
+
await runtime.dispose();
|
|
1315
1660
|
}
|
|
1316
1661
|
}
|
|
1317
|
-
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1662
|
+
function walkFrameTree(node, parentFrameId, records) {
|
|
1663
|
+
const frameId = node.frame?.id;
|
|
1664
|
+
if (!frameId) return;
|
|
1665
|
+
records.push({
|
|
1666
|
+
frameId,
|
|
1667
|
+
parentFrameId
|
|
1668
|
+
});
|
|
1669
|
+
for (const child of node.childFrames ?? []) {
|
|
1670
|
+
walkFrameTree(child, frameId, records);
|
|
1671
|
+
}
|
|
1322
1672
|
}
|
|
1323
|
-
function
|
|
1673
|
+
function sameFrameIds(before, after) {
|
|
1324
1674
|
if (before.length !== after.length) return false;
|
|
1325
|
-
for (const
|
|
1326
|
-
if (!after.includes(
|
|
1675
|
+
for (const frameId of before) {
|
|
1676
|
+
if (!after.includes(frameId)) return false;
|
|
1327
1677
|
}
|
|
1328
1678
|
return true;
|
|
1329
1679
|
}
|
|
1680
|
+
function formatCdpException(details) {
|
|
1681
|
+
return details.exception?.description || details.text || "CDP runtime evaluation failed.";
|
|
1682
|
+
}
|
|
1683
|
+
function isMissingExecutionContextError(error) {
|
|
1684
|
+
if (!(error instanceof Error)) return false;
|
|
1685
|
+
const message = error.message;
|
|
1686
|
+
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
1687
|
+
}
|
|
1330
1688
|
function isIgnorableFrameError(error) {
|
|
1331
1689
|
if (!(error instanceof Error)) return false;
|
|
1332
1690
|
const message = error.message;
|
|
1333
|
-
return message.includes("Frame was detached") || message.includes("Execution context was destroyed") || message.includes("Target page, context or browser has been closed");
|
|
1691
|
+
return message.includes("Frame was detached") || message.includes("Execution context was destroyed") || message.includes("Target page, context or browser has been closed") || message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context") || message.includes("No frame for given id found");
|
|
1692
|
+
}
|
|
1693
|
+
function sleep(ms) {
|
|
1694
|
+
return new Promise((resolve) => {
|
|
1695
|
+
setTimeout(resolve, ms);
|
|
1696
|
+
});
|
|
1334
1697
|
}
|
|
1335
1698
|
|
|
1336
1699
|
// src/storage/local.ts
|
|
@@ -2231,6 +2594,66 @@ var OS_BOUNDARY_ATTR = "data-os-boundary";
|
|
|
2231
2594
|
var OS_UNAVAILABLE_ATTR = "data-os-unavailable";
|
|
2232
2595
|
var OS_IFRAME_BOUNDARY_TAG = "os-iframe-root";
|
|
2233
2596
|
var OS_SHADOW_BOUNDARY_TAG = "os-shadow-root";
|
|
2597
|
+
function decodeSerializedNodeTableEntry(nodeTable, rawIndex, label) {
|
|
2598
|
+
if (typeof rawIndex !== "number" || !Number.isInteger(rawIndex) || rawIndex < 0 || rawIndex >= nodeTable.length) {
|
|
2599
|
+
throw new Error(
|
|
2600
|
+
`Invalid serialized path node index at "${label}": expected a valid table index.`
|
|
2601
|
+
);
|
|
2602
|
+
}
|
|
2603
|
+
const node = nodeTable[rawIndex];
|
|
2604
|
+
if (!node || typeof node !== "object") {
|
|
2605
|
+
throw new Error(
|
|
2606
|
+
`Invalid serialized path node at "${label}": table entry is missing.`
|
|
2607
|
+
);
|
|
2608
|
+
}
|
|
2609
|
+
return node;
|
|
2610
|
+
}
|
|
2611
|
+
function decodeSerializedDomPath(nodeTable, rawPath, label) {
|
|
2612
|
+
if (!Array.isArray(rawPath)) {
|
|
2613
|
+
throw new Error(
|
|
2614
|
+
`Invalid serialized path at "${label}": expected an array of node indexes.`
|
|
2615
|
+
);
|
|
2616
|
+
}
|
|
2617
|
+
return rawPath.map(
|
|
2618
|
+
(value, index) => decodeSerializedNodeTableEntry(nodeTable, value, `${label}[${index}]`)
|
|
2619
|
+
);
|
|
2620
|
+
}
|
|
2621
|
+
function decodeSerializedElementPath(nodeTable, rawPath, label) {
|
|
2622
|
+
if (!rawPath || typeof rawPath !== "object") {
|
|
2623
|
+
throw new Error(
|
|
2624
|
+
`Invalid serialized element path at "${label}": expected an object.`
|
|
2625
|
+
);
|
|
2626
|
+
}
|
|
2627
|
+
if (rawPath.context !== void 0 && !Array.isArray(rawPath.context)) {
|
|
2628
|
+
throw new Error(
|
|
2629
|
+
`Invalid serialized context at "${label}.context": expected an array.`
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
const contextRaw = Array.isArray(rawPath.context) ? rawPath.context : [];
|
|
2633
|
+
const context = contextRaw.map((hop, hopIndex) => {
|
|
2634
|
+
if (!hop || typeof hop !== "object" || hop.kind !== "shadow") {
|
|
2635
|
+
throw new Error(
|
|
2636
|
+
`Invalid serialized context hop at "${label}.context[${hopIndex}]": expected a shadow hop.`
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
2639
|
+
return {
|
|
2640
|
+
kind: "shadow",
|
|
2641
|
+
host: decodeSerializedDomPath(
|
|
2642
|
+
nodeTable,
|
|
2643
|
+
hop.host,
|
|
2644
|
+
`${label}.context[${hopIndex}].host`
|
|
2645
|
+
)
|
|
2646
|
+
};
|
|
2647
|
+
});
|
|
2648
|
+
return {
|
|
2649
|
+
context,
|
|
2650
|
+
nodes: decodeSerializedDomPath(
|
|
2651
|
+
nodeTable,
|
|
2652
|
+
rawPath.nodes,
|
|
2653
|
+
`${label}.nodes`
|
|
2654
|
+
)
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2234
2657
|
async function serializePageHTML(page, _options = {}) {
|
|
2235
2658
|
return serializeFrameRecursive(page.mainFrame(), [], "f0");
|
|
2236
2659
|
}
|
|
@@ -2287,6 +2710,8 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2287
2710
|
(Array.isArray(deferredMatchAttrKeys) ? deferredMatchAttrKeys : []).map((key) => String(key))
|
|
2288
2711
|
);
|
|
2289
2712
|
let counter = 1;
|
|
2713
|
+
const nodeTable = [];
|
|
2714
|
+
const nodeTableIndexByKey = /* @__PURE__ */ new Map();
|
|
2290
2715
|
const entries = [];
|
|
2291
2716
|
const helpers = {
|
|
2292
2717
|
nextToken() {
|
|
@@ -2488,6 +2913,47 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2488
2913
|
nodes: target
|
|
2489
2914
|
};
|
|
2490
2915
|
},
|
|
2916
|
+
buildPathNodeKey(node) {
|
|
2917
|
+
const attrs = Object.entries(node.attrs || {}).sort(
|
|
2918
|
+
([a], [b]) => a.localeCompare(b)
|
|
2919
|
+
);
|
|
2920
|
+
const match = (node.match || []).map(
|
|
2921
|
+
(clause) => clause.kind === "attr" ? [
|
|
2922
|
+
"attr",
|
|
2923
|
+
clause.key,
|
|
2924
|
+
clause.op || "exact",
|
|
2925
|
+
clause.value ?? null
|
|
2926
|
+
] : ["position", clause.axis]
|
|
2927
|
+
);
|
|
2928
|
+
return JSON.stringify([
|
|
2929
|
+
node.tag,
|
|
2930
|
+
node.position.nthChild,
|
|
2931
|
+
node.position.nthOfType,
|
|
2932
|
+
attrs,
|
|
2933
|
+
match
|
|
2934
|
+
]);
|
|
2935
|
+
},
|
|
2936
|
+
internPathNode(node) {
|
|
2937
|
+
const key = helpers.buildPathNodeKey(node);
|
|
2938
|
+
const existing = nodeTableIndexByKey.get(key);
|
|
2939
|
+
if (existing != null) return existing;
|
|
2940
|
+
const index = nodeTable.length;
|
|
2941
|
+
nodeTable.push(node);
|
|
2942
|
+
nodeTableIndexByKey.set(key, index);
|
|
2943
|
+
return index;
|
|
2944
|
+
},
|
|
2945
|
+
packDomPath(path5) {
|
|
2946
|
+
return path5.map((node) => helpers.internPathNode(node));
|
|
2947
|
+
},
|
|
2948
|
+
packElementPath(path5) {
|
|
2949
|
+
return {
|
|
2950
|
+
context: (path5.context || []).map((hop) => ({
|
|
2951
|
+
kind: "shadow",
|
|
2952
|
+
host: helpers.packDomPath(hop.host)
|
|
2953
|
+
})),
|
|
2954
|
+
nodes: helpers.packDomPath(path5.nodes)
|
|
2955
|
+
};
|
|
2956
|
+
},
|
|
2491
2957
|
ensureNodeId(el) {
|
|
2492
2958
|
const next = `${frameKey2}_${counter++}`;
|
|
2493
2959
|
el.setAttribute(nodeAttr, next);
|
|
@@ -2517,9 +2983,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2517
2983
|
serializeElement(el) {
|
|
2518
2984
|
const nodeId = helpers.ensureNodeId(el);
|
|
2519
2985
|
const instanceToken = helpers.setInstanceToken(el);
|
|
2986
|
+
const packedPath = helpers.packElementPath(
|
|
2987
|
+
helpers.buildElementPath(el)
|
|
2988
|
+
);
|
|
2520
2989
|
entries.push({
|
|
2521
2990
|
nodeId,
|
|
2522
|
-
path:
|
|
2991
|
+
path: packedPath,
|
|
2523
2992
|
instanceToken
|
|
2524
2993
|
});
|
|
2525
2994
|
const tag = el.tagName.toLowerCase();
|
|
@@ -2547,11 +3016,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2547
3016
|
win[frameTokenKey] = frameToken;
|
|
2548
3017
|
const root = document.documentElement;
|
|
2549
3018
|
if (!root) {
|
|
2550
|
-
return { html: "", frameToken, entries };
|
|
3019
|
+
return { html: "", frameToken, nodeTable, entries };
|
|
2551
3020
|
}
|
|
2552
3021
|
return {
|
|
2553
3022
|
html: helpers.serializeElement(root),
|
|
2554
3023
|
frameToken,
|
|
3024
|
+
nodeTable,
|
|
2555
3025
|
entries
|
|
2556
3026
|
};
|
|
2557
3027
|
},
|
|
@@ -2569,13 +3039,18 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2569
3039
|
);
|
|
2570
3040
|
const nodePaths = /* @__PURE__ */ new Map();
|
|
2571
3041
|
const nodeMeta = /* @__PURE__ */ new Map();
|
|
2572
|
-
for (const entry of frameSnapshot.entries) {
|
|
3042
|
+
for (const [index, entry] of frameSnapshot.entries.entries()) {
|
|
3043
|
+
const path5 = decodeSerializedElementPath(
|
|
3044
|
+
frameSnapshot.nodeTable,
|
|
3045
|
+
entry.path,
|
|
3046
|
+
`entries[${index}].path`
|
|
3047
|
+
);
|
|
2573
3048
|
nodePaths.set(entry.nodeId, {
|
|
2574
3049
|
context: [
|
|
2575
3050
|
...baseContext,
|
|
2576
|
-
...
|
|
3051
|
+
...path5.context || []
|
|
2577
3052
|
],
|
|
2578
|
-
nodes:
|
|
3053
|
+
nodes: path5.nodes
|
|
2579
3054
|
});
|
|
2580
3055
|
nodeMeta.set(entry.nodeId, {
|
|
2581
3056
|
frameToken: frameSnapshot.frameToken,
|
|
@@ -4969,7 +5444,7 @@ async function performInput(page, path5, options) {
|
|
|
4969
5444
|
await resolved.element.type(options.text);
|
|
4970
5445
|
}
|
|
4971
5446
|
if (options.pressEnter) {
|
|
4972
|
-
await resolved.element.press("Enter");
|
|
5447
|
+
await resolved.element.press("Enter", { noWaitAfter: true });
|
|
4973
5448
|
}
|
|
4974
5449
|
return {
|
|
4975
5450
|
ok: true,
|
|
@@ -5645,7 +6120,26 @@ var ACTION_WAIT_PROFILES = {
|
|
|
5645
6120
|
type: ROBUST_PROFILE
|
|
5646
6121
|
};
|
|
5647
6122
|
var NETWORK_POLL_MS = 50;
|
|
5648
|
-
var
|
|
6123
|
+
var NETWORK_RELAX_AFTER_MS = 1800;
|
|
6124
|
+
var RELAXED_ALLOWED_PENDING = 2;
|
|
6125
|
+
var HEAVY_VISUAL_REQUEST_WINDOW_MS = 5e3;
|
|
6126
|
+
var TRACKED_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6127
|
+
"document",
|
|
6128
|
+
"fetch",
|
|
6129
|
+
"xhr",
|
|
6130
|
+
"stylesheet",
|
|
6131
|
+
"image",
|
|
6132
|
+
"font",
|
|
6133
|
+
"media"
|
|
6134
|
+
]);
|
|
6135
|
+
var HEAVY_RESOURCE_TYPES = /* @__PURE__ */ new Set(["document", "fetch", "xhr"]);
|
|
6136
|
+
var HEAVY_VISUAL_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6137
|
+
"stylesheet",
|
|
6138
|
+
"image",
|
|
6139
|
+
"font",
|
|
6140
|
+
"media"
|
|
6141
|
+
]);
|
|
6142
|
+
var IGNORED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["websocket", "eventsource", "manifest"]);
|
|
5649
6143
|
var NOOP_SESSION = {
|
|
5650
6144
|
async wait() {
|
|
5651
6145
|
},
|
|
@@ -5655,7 +6149,7 @@ var NOOP_SESSION = {
|
|
|
5655
6149
|
function createPostActionWaitSession(page, action, override) {
|
|
5656
6150
|
const profile = resolveActionWaitProfile(action, override);
|
|
5657
6151
|
if (!profile.enabled) return NOOP_SESSION;
|
|
5658
|
-
const tracker = profile.includeNetwork ? new
|
|
6152
|
+
const tracker = profile.includeNetwork ? new AdaptiveNetworkTracker(page) : null;
|
|
5659
6153
|
tracker?.start();
|
|
5660
6154
|
let settled = false;
|
|
5661
6155
|
return {
|
|
@@ -5663,19 +6157,32 @@ function createPostActionWaitSession(page, action, override) {
|
|
|
5663
6157
|
if (settled) return;
|
|
5664
6158
|
settled = true;
|
|
5665
6159
|
const deadline = Date.now() + profile.timeout;
|
|
5666
|
-
const
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
6160
|
+
const visualTimeout = profile.includeNetwork ? Math.min(
|
|
6161
|
+
profile.timeout,
|
|
6162
|
+
resolveNetworkBackedVisualTimeout(profile.settleMs)
|
|
6163
|
+
) : profile.timeout;
|
|
5670
6164
|
try {
|
|
5671
|
-
|
|
5672
|
-
waitForVisualStabilityAcrossFrames(page, {
|
|
5673
|
-
timeout:
|
|
6165
|
+
try {
|
|
6166
|
+
await waitForVisualStabilityAcrossFrames(page, {
|
|
6167
|
+
timeout: visualTimeout,
|
|
5674
6168
|
settleMs: profile.settleMs
|
|
5675
|
-
})
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
6169
|
+
});
|
|
6170
|
+
} catch (error) {
|
|
6171
|
+
if (isStealthWaitUnavailableError(error)) {
|
|
6172
|
+
throw error;
|
|
6173
|
+
}
|
|
6174
|
+
} finally {
|
|
6175
|
+
tracker?.freezeCollection();
|
|
6176
|
+
}
|
|
6177
|
+
if (tracker) {
|
|
6178
|
+
try {
|
|
6179
|
+
await tracker.waitForQuiet({
|
|
6180
|
+
deadline,
|
|
6181
|
+
quietMs: profile.networkQuietMs
|
|
6182
|
+
});
|
|
6183
|
+
} catch {
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
5679
6186
|
} finally {
|
|
5680
6187
|
tracker?.stop();
|
|
5681
6188
|
}
|
|
@@ -5715,53 +6222,70 @@ function normalizeMs(value, fallback) {
|
|
|
5715
6222
|
}
|
|
5716
6223
|
return Math.max(0, Math.floor(value));
|
|
5717
6224
|
}
|
|
5718
|
-
|
|
6225
|
+
function resolveNetworkBackedVisualTimeout(settleMs) {
|
|
6226
|
+
const derived = settleMs * 3 + 300;
|
|
6227
|
+
return Math.max(1200, Math.min(2500, derived));
|
|
6228
|
+
}
|
|
6229
|
+
var AdaptiveNetworkTracker = class {
|
|
5719
6230
|
constructor(page) {
|
|
5720
6231
|
this.page = page;
|
|
5721
6232
|
}
|
|
5722
|
-
pending = /* @__PURE__ */ new
|
|
6233
|
+
pending = /* @__PURE__ */ new Map();
|
|
5723
6234
|
started = false;
|
|
6235
|
+
collecting = false;
|
|
6236
|
+
startedAt = 0;
|
|
5724
6237
|
idleSince = Date.now();
|
|
5725
6238
|
start() {
|
|
5726
6239
|
if (this.started) return;
|
|
5727
6240
|
this.started = true;
|
|
6241
|
+
this.collecting = true;
|
|
6242
|
+
this.startedAt = Date.now();
|
|
6243
|
+
this.idleSince = this.startedAt;
|
|
5728
6244
|
this.page.on("request", this.handleRequestStarted);
|
|
5729
6245
|
this.page.on("requestfinished", this.handleRequestFinished);
|
|
5730
6246
|
this.page.on("requestfailed", this.handleRequestFinished);
|
|
5731
6247
|
}
|
|
6248
|
+
freezeCollection() {
|
|
6249
|
+
if (!this.started) return;
|
|
6250
|
+
this.collecting = false;
|
|
6251
|
+
}
|
|
5732
6252
|
stop() {
|
|
5733
6253
|
if (!this.started) return;
|
|
5734
6254
|
this.started = false;
|
|
6255
|
+
this.collecting = false;
|
|
5735
6256
|
this.page.off("request", this.handleRequestStarted);
|
|
5736
6257
|
this.page.off("requestfinished", this.handleRequestFinished);
|
|
5737
6258
|
this.page.off("requestfailed", this.handleRequestFinished);
|
|
5738
6259
|
this.pending.clear();
|
|
6260
|
+
this.startedAt = 0;
|
|
5739
6261
|
this.idleSince = Date.now();
|
|
5740
6262
|
}
|
|
5741
6263
|
async waitForQuiet(options) {
|
|
5742
6264
|
const quietMs = Math.max(0, options.quietMs);
|
|
5743
6265
|
if (quietMs === 0) return;
|
|
5744
6266
|
while (Date.now() < options.deadline) {
|
|
5745
|
-
|
|
6267
|
+
const now = Date.now();
|
|
6268
|
+
const allowedPending = this.resolveAllowedPending(now);
|
|
6269
|
+
if (this.pending.size <= allowedPending) {
|
|
5746
6270
|
if (this.idleSince === 0) {
|
|
5747
|
-
this.idleSince =
|
|
6271
|
+
this.idleSince = now;
|
|
5748
6272
|
}
|
|
5749
|
-
const idleFor =
|
|
6273
|
+
const idleFor = now - this.idleSince;
|
|
5750
6274
|
if (idleFor >= quietMs) {
|
|
5751
6275
|
return;
|
|
5752
6276
|
}
|
|
5753
6277
|
} else {
|
|
5754
6278
|
this.idleSince = 0;
|
|
5755
6279
|
}
|
|
5756
|
-
const remaining = Math.max(1, options.deadline -
|
|
5757
|
-
await
|
|
6280
|
+
const remaining = Math.max(1, options.deadline - now);
|
|
6281
|
+
await sleep2(Math.min(NETWORK_POLL_MS, remaining));
|
|
5758
6282
|
}
|
|
5759
6283
|
}
|
|
5760
6284
|
handleRequestStarted = (request) => {
|
|
5761
|
-
if (!this.started) return;
|
|
5762
|
-
const
|
|
5763
|
-
if (
|
|
5764
|
-
this.pending.
|
|
6285
|
+
if (!this.started || !this.collecting) return;
|
|
6286
|
+
const trackedRequest = this.classifyRequest(request);
|
|
6287
|
+
if (!trackedRequest) return;
|
|
6288
|
+
this.pending.set(request, trackedRequest);
|
|
5765
6289
|
this.idleSince = 0;
|
|
5766
6290
|
};
|
|
5767
6291
|
handleRequestFinished = (request) => {
|
|
@@ -5771,8 +6295,35 @@ var ScopedNetworkTracker = class {
|
|
|
5771
6295
|
this.idleSince = Date.now();
|
|
5772
6296
|
}
|
|
5773
6297
|
};
|
|
6298
|
+
classifyRequest(request) {
|
|
6299
|
+
const resourceType = request.resourceType().toLowerCase();
|
|
6300
|
+
if (IGNORED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6301
|
+
if (!TRACKED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6302
|
+
const frame = request.frame();
|
|
6303
|
+
if (!frame || frame !== this.page.mainFrame()) return null;
|
|
6304
|
+
return {
|
|
6305
|
+
resourceType,
|
|
6306
|
+
startedAt: Date.now()
|
|
6307
|
+
};
|
|
6308
|
+
}
|
|
6309
|
+
resolveAllowedPending(now) {
|
|
6310
|
+
const relaxed = now - this.startedAt >= NETWORK_RELAX_AFTER_MS ? RELAXED_ALLOWED_PENDING : 0;
|
|
6311
|
+
if (this.hasHeavyPending(now)) return 0;
|
|
6312
|
+
return relaxed;
|
|
6313
|
+
}
|
|
6314
|
+
hasHeavyPending(now) {
|
|
6315
|
+
for (const trackedRequest of this.pending.values()) {
|
|
6316
|
+
if (HEAVY_RESOURCE_TYPES.has(trackedRequest.resourceType)) {
|
|
6317
|
+
return true;
|
|
6318
|
+
}
|
|
6319
|
+
if (HEAVY_VISUAL_RESOURCE_TYPES.has(trackedRequest.resourceType) && now - trackedRequest.startedAt < HEAVY_VISUAL_REQUEST_WINDOW_MS) {
|
|
6320
|
+
return true;
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6323
|
+
return false;
|
|
6324
|
+
}
|
|
5774
6325
|
};
|
|
5775
|
-
async function
|
|
6326
|
+
async function sleep2(ms) {
|
|
5776
6327
|
await new Promise((resolve) => {
|
|
5777
6328
|
setTimeout(resolve, ms);
|
|
5778
6329
|
});
|
|
@@ -7212,16 +7763,18 @@ var CACHE_IMPORT_BATCH_SIZE = 200;
|
|
|
7212
7763
|
var RemoteSessionClient = class {
|
|
7213
7764
|
baseUrl;
|
|
7214
7765
|
key;
|
|
7215
|
-
|
|
7766
|
+
authScheme;
|
|
7767
|
+
constructor(baseUrl, key, authScheme = "api-key") {
|
|
7216
7768
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
7217
7769
|
this.key = key;
|
|
7770
|
+
this.authScheme = authScheme;
|
|
7218
7771
|
}
|
|
7219
7772
|
async create(request) {
|
|
7220
7773
|
const response = await fetch(`${this.baseUrl}/sessions`, {
|
|
7221
7774
|
method: "POST",
|
|
7222
7775
|
headers: {
|
|
7223
7776
|
"content-type": "application/json",
|
|
7224
|
-
|
|
7777
|
+
...this.authHeaders()
|
|
7225
7778
|
},
|
|
7226
7779
|
body: JSON.stringify(request)
|
|
7227
7780
|
});
|
|
@@ -7234,7 +7787,7 @@ var RemoteSessionClient = class {
|
|
|
7234
7787
|
const response = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
|
|
7235
7788
|
method: "DELETE",
|
|
7236
7789
|
headers: {
|
|
7237
|
-
|
|
7790
|
+
...this.authHeaders()
|
|
7238
7791
|
}
|
|
7239
7792
|
});
|
|
7240
7793
|
if (response.status === 204) {
|
|
@@ -7264,7 +7817,7 @@ var RemoteSessionClient = class {
|
|
|
7264
7817
|
method: "POST",
|
|
7265
7818
|
headers: {
|
|
7266
7819
|
"content-type": "application/json",
|
|
7267
|
-
|
|
7820
|
+
...this.authHeaders()
|
|
7268
7821
|
},
|
|
7269
7822
|
body: JSON.stringify({ entries })
|
|
7270
7823
|
});
|
|
@@ -7273,6 +7826,16 @@ var RemoteSessionClient = class {
|
|
|
7273
7826
|
}
|
|
7274
7827
|
return await response.json();
|
|
7275
7828
|
}
|
|
7829
|
+
authHeaders() {
|
|
7830
|
+
if (this.authScheme === "bearer") {
|
|
7831
|
+
return {
|
|
7832
|
+
authorization: `Bearer ${this.key}`
|
|
7833
|
+
};
|
|
7834
|
+
}
|
|
7835
|
+
return {
|
|
7836
|
+
"x-api-key": this.key
|
|
7837
|
+
};
|
|
7838
|
+
}
|
|
7276
7839
|
};
|
|
7277
7840
|
function normalizeBaseUrl(baseUrl) {
|
|
7278
7841
|
return baseUrl.replace(/\/+$/, "");
|
|
@@ -7313,9 +7876,9 @@ function toRemoteErrorCode(code) {
|
|
|
7313
7876
|
|
|
7314
7877
|
// src/remote/runtime.ts
|
|
7315
7878
|
var DEFAULT_REMOTE_BASE_URL = "https://remote.opensteer.com";
|
|
7316
|
-
function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl()) {
|
|
7879
|
+
function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl(), authScheme = "api-key") {
|
|
7317
7880
|
return {
|
|
7318
|
-
sessionClient: new RemoteSessionClient(baseUrl, key),
|
|
7881
|
+
sessionClient: new RemoteSessionClient(baseUrl, key, authScheme),
|
|
7319
7882
|
cdpClient: new RemoteCdpClient(),
|
|
7320
7883
|
actionClient: null,
|
|
7321
7884
|
sessionId: null
|
|
@@ -7380,7 +7943,8 @@ var Opensteer = class _Opensteer {
|
|
|
7380
7943
|
}
|
|
7381
7944
|
this.remote = createRemoteRuntimeState(
|
|
7382
7945
|
apiKey,
|
|
7383
|
-
remoteConfig?.baseUrl
|
|
7946
|
+
remoteConfig?.baseUrl,
|
|
7947
|
+
remoteConfig?.authScheme
|
|
7384
7948
|
);
|
|
7385
7949
|
} else {
|
|
7386
7950
|
this.remote = null;
|
|
@@ -7836,7 +8400,7 @@ var Opensteer = class _Opensteer {
|
|
|
7836
8400
|
await handle.type(options.text);
|
|
7837
8401
|
}
|
|
7838
8402
|
if (options.pressEnter) {
|
|
7839
|
-
await handle.press("Enter");
|
|
8403
|
+
await handle.press("Enter", { noWaitAfter: true });
|
|
7840
8404
|
}
|
|
7841
8405
|
});
|
|
7842
8406
|
} catch (err) {
|