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/cli/server.cjs
CHANGED
|
@@ -952,11 +952,33 @@ function parseMode(value, source) {
|
|
|
952
952
|
`Invalid ${source} value "${value}". Use "local" or "remote".`
|
|
953
953
|
);
|
|
954
954
|
}
|
|
955
|
+
function parseAuthScheme(value, source) {
|
|
956
|
+
if (value == null) return void 0;
|
|
957
|
+
if (typeof value !== "string") {
|
|
958
|
+
throw new Error(
|
|
959
|
+
`Invalid ${source} value "${String(value)}". Use "api-key" or "bearer".`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
const normalized = value.trim().toLowerCase();
|
|
963
|
+
if (!normalized) return void 0;
|
|
964
|
+
if (normalized === "api-key" || normalized === "bearer") {
|
|
965
|
+
return normalized;
|
|
966
|
+
}
|
|
967
|
+
throw new Error(
|
|
968
|
+
`Invalid ${source} value "${value}". Use "api-key" or "bearer".`
|
|
969
|
+
);
|
|
970
|
+
}
|
|
955
971
|
function resolveOpensteerApiKey() {
|
|
956
972
|
const value = process.env.OPENSTEER_API_KEY?.trim();
|
|
957
973
|
if (!value) return void 0;
|
|
958
974
|
return value;
|
|
959
975
|
}
|
|
976
|
+
function resolveOpensteerAuthScheme() {
|
|
977
|
+
return parseAuthScheme(
|
|
978
|
+
process.env.OPENSTEER_AUTH_SCHEME,
|
|
979
|
+
"OPENSTEER_AUTH_SCHEME"
|
|
980
|
+
);
|
|
981
|
+
}
|
|
960
982
|
function normalizeRemoteOptions(value) {
|
|
961
983
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
962
984
|
return void 0;
|
|
@@ -1016,7 +1038,12 @@ function resolveConfig(input = {}) {
|
|
|
1016
1038
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
1017
1039
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
1018
1040
|
const envApiKey = resolveOpensteerApiKey();
|
|
1041
|
+
const envAuthScheme = resolveOpensteerAuthScheme();
|
|
1019
1042
|
const inputRemoteOptions = normalizeRemoteOptions(input.remote);
|
|
1043
|
+
const inputAuthScheme = parseAuthScheme(
|
|
1044
|
+
inputRemoteOptions?.authScheme,
|
|
1045
|
+
"remote.authScheme"
|
|
1046
|
+
);
|
|
1020
1047
|
const inputHasRemoteApiKey = Boolean(
|
|
1021
1048
|
inputRemoteOptions && Object.prototype.hasOwnProperty.call(inputRemoteOptions, "apiKey")
|
|
1022
1049
|
);
|
|
@@ -1024,8 +1051,12 @@ function resolveConfig(input = {}) {
|
|
|
1024
1051
|
mode: resolved.mode
|
|
1025
1052
|
});
|
|
1026
1053
|
if (modeSelection.mode === "remote") {
|
|
1027
|
-
const resolvedRemote = normalizeRemoteOptions(resolved.remote);
|
|
1028
|
-
|
|
1054
|
+
const resolvedRemote = normalizeRemoteOptions(resolved.remote) ?? {};
|
|
1055
|
+
const authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedRemote.authScheme, "remote.authScheme") ?? "api-key";
|
|
1056
|
+
resolved.remote = {
|
|
1057
|
+
...resolvedRemote,
|
|
1058
|
+
authScheme
|
|
1059
|
+
};
|
|
1029
1060
|
}
|
|
1030
1061
|
if (envApiKey && modeSelection.mode === "remote" && !inputHasRemoteApiKey) {
|
|
1031
1062
|
resolved.remote = {
|
|
@@ -1072,15 +1103,52 @@ function getCallerFilePath() {
|
|
|
1072
1103
|
// src/navigation.ts
|
|
1073
1104
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1074
1105
|
var DEFAULT_SETTLE_MS = 750;
|
|
1106
|
+
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
1107
|
+
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
1108
|
+
var StealthWaitUnavailableError = class extends Error {
|
|
1109
|
+
constructor(cause) {
|
|
1110
|
+
super("Stealth visual wait requires Chromium CDP support.", { cause });
|
|
1111
|
+
this.name = "StealthWaitUnavailableError";
|
|
1112
|
+
}
|
|
1113
|
+
};
|
|
1114
|
+
function isStealthWaitUnavailableError(error) {
|
|
1115
|
+
return error instanceof StealthWaitUnavailableError;
|
|
1116
|
+
}
|
|
1117
|
+
var FRAME_OWNER_VISIBILITY_FUNCTION = `function() {
|
|
1118
|
+
if (!(this instanceof HTMLElement)) return false;
|
|
1119
|
+
|
|
1120
|
+
var rect = this.getBoundingClientRect();
|
|
1121
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
1122
|
+
if (
|
|
1123
|
+
rect.bottom <= 0 ||
|
|
1124
|
+
rect.right <= 0 ||
|
|
1125
|
+
rect.top >= window.innerHeight ||
|
|
1126
|
+
rect.left >= window.innerWidth
|
|
1127
|
+
) {
|
|
1128
|
+
return false;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
var style = window.getComputedStyle(this);
|
|
1132
|
+
if (
|
|
1133
|
+
style.display === 'none' ||
|
|
1134
|
+
style.visibility === 'hidden' ||
|
|
1135
|
+
Number(style.opacity) === 0
|
|
1136
|
+
) {
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
return true;
|
|
1141
|
+
}`;
|
|
1075
1142
|
function buildStabilityScript(timeout, settleMs) {
|
|
1076
1143
|
return `new Promise(function(resolve) {
|
|
1077
1144
|
var deadline = Date.now() + ${timeout};
|
|
1078
|
-
var timer = null;
|
|
1079
1145
|
var resolved = false;
|
|
1146
|
+
var timer = null;
|
|
1080
1147
|
var observers = [];
|
|
1081
1148
|
var observedShadowRoots = [];
|
|
1082
1149
|
var fonts = document.fonts;
|
|
1083
1150
|
var fontsReady = !fonts || fonts.status === 'loaded';
|
|
1151
|
+
var lastRelevantMutationAt = Date.now();
|
|
1084
1152
|
|
|
1085
1153
|
function clearObservers() {
|
|
1086
1154
|
for (var i = 0; i < observers.length; i++) {
|
|
@@ -1098,9 +1166,87 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1098
1166
|
resolve();
|
|
1099
1167
|
}
|
|
1100
1168
|
|
|
1169
|
+
function isElementVisiblyIntersectingViewport(element) {
|
|
1170
|
+
if (!(element instanceof Element)) return false;
|
|
1171
|
+
|
|
1172
|
+
var rect = element.getBoundingClientRect();
|
|
1173
|
+
var inViewport =
|
|
1174
|
+
rect.width > 0 &&
|
|
1175
|
+
rect.height > 0 &&
|
|
1176
|
+
rect.bottom > 0 &&
|
|
1177
|
+
rect.right > 0 &&
|
|
1178
|
+
rect.top < window.innerHeight &&
|
|
1179
|
+
rect.left < window.innerWidth;
|
|
1180
|
+
|
|
1181
|
+
if (!inViewport) return false;
|
|
1182
|
+
|
|
1183
|
+
var style = window.getComputedStyle(element);
|
|
1184
|
+
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
1185
|
+
return false;
|
|
1186
|
+
}
|
|
1187
|
+
if (Number(style.opacity) === 0) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
return true;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
function resolveRelevantElement(node) {
|
|
1195
|
+
if (!node) return null;
|
|
1196
|
+
if (node instanceof Element) return node;
|
|
1197
|
+
if (typeof ShadowRoot !== 'undefined' && node instanceof ShadowRoot) {
|
|
1198
|
+
return node.host instanceof Element ? node.host : null;
|
|
1199
|
+
}
|
|
1200
|
+
var parentElement = node.parentElement;
|
|
1201
|
+
return parentElement instanceof Element ? parentElement : null;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
function isNodeVisiblyRelevant(node) {
|
|
1205
|
+
var element = resolveRelevantElement(node);
|
|
1206
|
+
if (!element) return false;
|
|
1207
|
+
return isElementVisiblyIntersectingViewport(element);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
function hasRelevantMutation(records) {
|
|
1211
|
+
for (var i = 0; i < records.length; i++) {
|
|
1212
|
+
var record = records[i];
|
|
1213
|
+
if (isNodeVisiblyRelevant(record.target)) return true;
|
|
1214
|
+
|
|
1215
|
+
var addedNodes = record.addedNodes;
|
|
1216
|
+
for (var j = 0; j < addedNodes.length; j++) {
|
|
1217
|
+
if (isNodeVisiblyRelevant(addedNodes[j])) return true;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
var removedNodes = record.removedNodes;
|
|
1221
|
+
for (var k = 0; k < removedNodes.length; k++) {
|
|
1222
|
+
if (isNodeVisiblyRelevant(removedNodes[k])) return true;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
return false;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
function scheduleCheck() {
|
|
1230
|
+
if (resolved) return;
|
|
1231
|
+
if (timer) clearTimeout(timer);
|
|
1232
|
+
|
|
1233
|
+
var remaining = deadline - Date.now();
|
|
1234
|
+
if (remaining <= 0) {
|
|
1235
|
+
done();
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
var checkDelay = Math.min(120, Math.max(16, ${settleMs}));
|
|
1240
|
+
timer = setTimeout(checkNow, checkDelay);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1101
1243
|
function observeMutations(target) {
|
|
1102
1244
|
if (!target) return;
|
|
1103
|
-
var observer = new MutationObserver(function() {
|
|
1245
|
+
var observer = new MutationObserver(function(records) {
|
|
1246
|
+
if (!hasRelevantMutation(records)) return;
|
|
1247
|
+
lastRelevantMutationAt = Date.now();
|
|
1248
|
+
scheduleCheck();
|
|
1249
|
+
});
|
|
1104
1250
|
observer.observe(target, {
|
|
1105
1251
|
childList: true,
|
|
1106
1252
|
subtree: true,
|
|
@@ -1138,18 +1284,25 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1138
1284
|
var images = root.querySelectorAll('img');
|
|
1139
1285
|
for (var i = 0; i < images.length; i++) {
|
|
1140
1286
|
var img = images[i];
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
rect.bottom > 0 &&
|
|
1144
|
-
rect.right > 0 &&
|
|
1145
|
-
rect.top < window.innerHeight &&
|
|
1146
|
-
rect.left < window.innerWidth;
|
|
1147
|
-
if (inViewport && !img.complete) return false;
|
|
1287
|
+
if (!isElementVisiblyIntersectingViewport(img)) continue;
|
|
1288
|
+
if (!img.complete) return false;
|
|
1148
1289
|
}
|
|
1149
1290
|
return true;
|
|
1150
1291
|
}
|
|
1151
1292
|
|
|
1152
|
-
function
|
|
1293
|
+
function getAnimationTarget(effect) {
|
|
1294
|
+
if (!effect) return null;
|
|
1295
|
+
var target = effect.target;
|
|
1296
|
+
if (target instanceof Element) return target;
|
|
1297
|
+
|
|
1298
|
+
if (target && target.element instanceof Element) {
|
|
1299
|
+
return target.element;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
function hasRunningVisibleFiniteAnimations() {
|
|
1153
1306
|
if (typeof document.getAnimations !== 'function') return false;
|
|
1154
1307
|
var animations = document.getAnimations();
|
|
1155
1308
|
|
|
@@ -1163,6 +1316,9 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1163
1316
|
? timing.endTime
|
|
1164
1317
|
: Number.POSITIVE_INFINITY;
|
|
1165
1318
|
if (Number.isFinite(endTime) && endTime > 0) {
|
|
1319
|
+
var target = getAnimationTarget(effect);
|
|
1320
|
+
if (!target) continue;
|
|
1321
|
+
if (!isElementVisiblyIntersectingViewport(target)) continue;
|
|
1166
1322
|
return true;
|
|
1167
1323
|
}
|
|
1168
1324
|
}
|
|
@@ -1173,21 +1329,29 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1173
1329
|
function isVisuallyReady() {
|
|
1174
1330
|
if (!fontsReady) return false;
|
|
1175
1331
|
if (!checkViewportImages(document)) return false;
|
|
1176
|
-
if (
|
|
1332
|
+
if (hasRunningVisibleFiniteAnimations()) return false;
|
|
1177
1333
|
return true;
|
|
1178
1334
|
}
|
|
1179
1335
|
|
|
1180
|
-
function
|
|
1181
|
-
if (Date.now()
|
|
1182
|
-
|
|
1336
|
+
function checkNow() {
|
|
1337
|
+
if (Date.now() >= deadline) {
|
|
1338
|
+
done();
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1183
1342
|
observeOpenShadowRoots();
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1343
|
+
|
|
1344
|
+
if (!isVisuallyReady()) {
|
|
1345
|
+
scheduleCheck();
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
if (Date.now() - lastRelevantMutationAt >= ${settleMs}) {
|
|
1350
|
+
done();
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
scheduleCheck();
|
|
1191
1355
|
}
|
|
1192
1356
|
|
|
1193
1357
|
observeMutations(document.documentElement);
|
|
@@ -1196,67 +1360,266 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1196
1360
|
if (fonts && fonts.ready && typeof fonts.ready.then === 'function') {
|
|
1197
1361
|
fonts.ready.then(function() {
|
|
1198
1362
|
fontsReady = true;
|
|
1199
|
-
|
|
1363
|
+
scheduleCheck();
|
|
1364
|
+
}, function() {
|
|
1365
|
+
fontsReady = true;
|
|
1366
|
+
scheduleCheck();
|
|
1200
1367
|
});
|
|
1201
1368
|
}
|
|
1202
1369
|
|
|
1203
1370
|
var safetyTimer = setTimeout(done, ${timeout});
|
|
1204
1371
|
|
|
1205
|
-
|
|
1372
|
+
scheduleCheck();
|
|
1206
1373
|
})`;
|
|
1207
1374
|
}
|
|
1375
|
+
var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
1376
|
+
constructor(session2) {
|
|
1377
|
+
this.session = session2;
|
|
1378
|
+
}
|
|
1379
|
+
contextsByFrame = /* @__PURE__ */ new Map();
|
|
1380
|
+
disposed = false;
|
|
1381
|
+
static async create(page) {
|
|
1382
|
+
let session2;
|
|
1383
|
+
try {
|
|
1384
|
+
session2 = await page.context().newCDPSession(page);
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
throw new StealthWaitUnavailableError(error);
|
|
1387
|
+
}
|
|
1388
|
+
const runtime = new _StealthCdpRuntime(session2);
|
|
1389
|
+
try {
|
|
1390
|
+
await runtime.initialize();
|
|
1391
|
+
return runtime;
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
await runtime.dispose();
|
|
1394
|
+
throw new StealthWaitUnavailableError(error);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
async dispose() {
|
|
1398
|
+
if (this.disposed) return;
|
|
1399
|
+
this.disposed = true;
|
|
1400
|
+
this.contextsByFrame.clear();
|
|
1401
|
+
await this.session.detach().catch(() => void 0);
|
|
1402
|
+
}
|
|
1403
|
+
async waitForMainFrameVisualStability(options) {
|
|
1404
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
1405
|
+
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1406
|
+
if (timeout <= 0) return;
|
|
1407
|
+
const frameRecords = await this.getFrameRecords();
|
|
1408
|
+
const mainFrame = frameRecords[0];
|
|
1409
|
+
if (!mainFrame) return;
|
|
1410
|
+
await this.waitForFrameVisualStability(mainFrame.frameId, timeout, settleMs);
|
|
1411
|
+
}
|
|
1412
|
+
async collectVisibleFrameIds() {
|
|
1413
|
+
const frameRecords = await this.getFrameRecords();
|
|
1414
|
+
if (frameRecords.length === 0) return [];
|
|
1415
|
+
const visibleFrameIds = [];
|
|
1416
|
+
for (const frameRecord of frameRecords) {
|
|
1417
|
+
if (!frameRecord.parentFrameId) {
|
|
1418
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
1419
|
+
continue;
|
|
1420
|
+
}
|
|
1421
|
+
try {
|
|
1422
|
+
const parentContextId = await this.ensureFrameContextId(
|
|
1423
|
+
frameRecord.parentFrameId
|
|
1424
|
+
);
|
|
1425
|
+
const visible = await this.isFrameOwnerVisible(
|
|
1426
|
+
frameRecord.frameId,
|
|
1427
|
+
parentContextId
|
|
1428
|
+
);
|
|
1429
|
+
if (visible) {
|
|
1430
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
1431
|
+
}
|
|
1432
|
+
} catch (error) {
|
|
1433
|
+
if (isIgnorableFrameError(error)) continue;
|
|
1434
|
+
throw error;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return visibleFrameIds;
|
|
1438
|
+
}
|
|
1439
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs) {
|
|
1440
|
+
if (timeout <= 0) return;
|
|
1441
|
+
const script = buildStabilityScript(timeout, settleMs);
|
|
1442
|
+
let contextId = await this.ensureFrameContextId(frameId);
|
|
1443
|
+
try {
|
|
1444
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
if (!isMissingExecutionContextError(error)) {
|
|
1447
|
+
throw error;
|
|
1448
|
+
}
|
|
1449
|
+
this.contextsByFrame.delete(frameId);
|
|
1450
|
+
contextId = await this.ensureFrameContextId(frameId);
|
|
1451
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
async initialize() {
|
|
1455
|
+
await this.session.send("Page.enable");
|
|
1456
|
+
await this.session.send("Runtime.enable");
|
|
1457
|
+
await this.session.send("DOM.enable");
|
|
1458
|
+
}
|
|
1459
|
+
async getFrameRecords() {
|
|
1460
|
+
const treeResult = await this.session.send("Page.getFrameTree");
|
|
1461
|
+
const records = [];
|
|
1462
|
+
walkFrameTree(treeResult.frameTree, null, records);
|
|
1463
|
+
return records;
|
|
1464
|
+
}
|
|
1465
|
+
async ensureFrameContextId(frameId) {
|
|
1466
|
+
const cached = this.contextsByFrame.get(frameId);
|
|
1467
|
+
if (cached != null) {
|
|
1468
|
+
return cached;
|
|
1469
|
+
}
|
|
1470
|
+
const world = await this.session.send("Page.createIsolatedWorld", {
|
|
1471
|
+
frameId,
|
|
1472
|
+
worldName: STEALTH_WORLD_NAME
|
|
1473
|
+
});
|
|
1474
|
+
this.contextsByFrame.set(frameId, world.executionContextId);
|
|
1475
|
+
return world.executionContextId;
|
|
1476
|
+
}
|
|
1477
|
+
async evaluateWithGuard(contextId, script, timeout) {
|
|
1478
|
+
const evaluationPromise = this.evaluateScript(contextId, script);
|
|
1479
|
+
const settledPromise = evaluationPromise.then(
|
|
1480
|
+
() => ({ kind: "resolved" }),
|
|
1481
|
+
(error) => ({ kind: "rejected", error })
|
|
1482
|
+
);
|
|
1483
|
+
const timeoutPromise = sleep(
|
|
1484
|
+
timeout + FRAME_EVALUATE_GRACE_MS
|
|
1485
|
+
).then(() => ({ kind: "timeout" }));
|
|
1486
|
+
const result = await Promise.race([
|
|
1487
|
+
settledPromise,
|
|
1488
|
+
timeoutPromise
|
|
1489
|
+
]);
|
|
1490
|
+
if (result.kind === "rejected") {
|
|
1491
|
+
throw result.error;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
async evaluateScript(contextId, expression) {
|
|
1495
|
+
const result = await this.session.send("Runtime.evaluate", {
|
|
1496
|
+
contextId,
|
|
1497
|
+
expression,
|
|
1498
|
+
awaitPromise: true,
|
|
1499
|
+
returnByValue: true
|
|
1500
|
+
});
|
|
1501
|
+
if (result.exceptionDetails) {
|
|
1502
|
+
throw new Error(formatCdpException(result.exceptionDetails));
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
async isFrameOwnerVisible(frameId, parentContextId) {
|
|
1506
|
+
const owner = await this.session.send("DOM.getFrameOwner", {
|
|
1507
|
+
frameId
|
|
1508
|
+
});
|
|
1509
|
+
const resolveParams = {
|
|
1510
|
+
executionContextId: parentContextId
|
|
1511
|
+
};
|
|
1512
|
+
if (typeof owner.backendNodeId === "number") {
|
|
1513
|
+
resolveParams.backendNodeId = owner.backendNodeId;
|
|
1514
|
+
} else if (typeof owner.nodeId === "number") {
|
|
1515
|
+
resolveParams.nodeId = owner.nodeId;
|
|
1516
|
+
} else {
|
|
1517
|
+
return false;
|
|
1518
|
+
}
|
|
1519
|
+
const resolved = await this.session.send(
|
|
1520
|
+
"DOM.resolveNode",
|
|
1521
|
+
resolveParams
|
|
1522
|
+
);
|
|
1523
|
+
const objectId = resolved.object?.objectId;
|
|
1524
|
+
if (!objectId) return false;
|
|
1525
|
+
try {
|
|
1526
|
+
const callResult = await this.session.send("Runtime.callFunctionOn", {
|
|
1527
|
+
objectId,
|
|
1528
|
+
functionDeclaration: FRAME_OWNER_VISIBILITY_FUNCTION,
|
|
1529
|
+
returnByValue: true
|
|
1530
|
+
});
|
|
1531
|
+
if (callResult.exceptionDetails) {
|
|
1532
|
+
throw new Error(formatCdpException(callResult.exceptionDetails));
|
|
1533
|
+
}
|
|
1534
|
+
return callResult.result.value === true;
|
|
1535
|
+
} finally {
|
|
1536
|
+
await this.releaseObject(objectId);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
async releaseObject(objectId) {
|
|
1540
|
+
await this.session.send("Runtime.releaseObject", {
|
|
1541
|
+
objectId
|
|
1542
|
+
}).catch(() => void 0);
|
|
1543
|
+
}
|
|
1544
|
+
};
|
|
1208
1545
|
async function waitForVisualStability(page, options = {}) {
|
|
1209
|
-
const
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1546
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
1547
|
+
try {
|
|
1548
|
+
await runtime.waitForMainFrameVisualStability(options);
|
|
1549
|
+
} finally {
|
|
1550
|
+
await runtime.dispose();
|
|
1551
|
+
}
|
|
1215
1552
|
}
|
|
1216
1553
|
async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
1217
1554
|
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
1218
1555
|
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1556
|
+
if (timeout <= 0) return;
|
|
1219
1557
|
const deadline = Date.now() + timeout;
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1558
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
1559
|
+
try {
|
|
1560
|
+
while (true) {
|
|
1561
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
1562
|
+
if (remaining === 0) return;
|
|
1563
|
+
const frameIds = await runtime.collectVisibleFrameIds();
|
|
1564
|
+
if (frameIds.length === 0) return;
|
|
1565
|
+
await Promise.all(
|
|
1566
|
+
frameIds.map(async (frameId) => {
|
|
1567
|
+
try {
|
|
1568
|
+
await runtime.waitForFrameVisualStability(
|
|
1569
|
+
frameId,
|
|
1570
|
+
remaining,
|
|
1571
|
+
settleMs
|
|
1572
|
+
);
|
|
1573
|
+
} catch (error) {
|
|
1574
|
+
if (isIgnorableFrameError(error)) return;
|
|
1575
|
+
throw error;
|
|
1576
|
+
}
|
|
1577
|
+
})
|
|
1578
|
+
);
|
|
1579
|
+
const currentFrameIds = await runtime.collectVisibleFrameIds();
|
|
1580
|
+
if (sameFrameIds(frameIds, currentFrameIds)) {
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1240
1583
|
}
|
|
1584
|
+
} finally {
|
|
1585
|
+
await runtime.dispose();
|
|
1241
1586
|
}
|
|
1242
1587
|
}
|
|
1243
|
-
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1588
|
+
function walkFrameTree(node, parentFrameId, records) {
|
|
1589
|
+
const frameId = node.frame?.id;
|
|
1590
|
+
if (!frameId) return;
|
|
1591
|
+
records.push({
|
|
1592
|
+
frameId,
|
|
1593
|
+
parentFrameId
|
|
1594
|
+
});
|
|
1595
|
+
for (const child of node.childFrames ?? []) {
|
|
1596
|
+
walkFrameTree(child, frameId, records);
|
|
1597
|
+
}
|
|
1248
1598
|
}
|
|
1249
|
-
function
|
|
1599
|
+
function sameFrameIds(before, after) {
|
|
1250
1600
|
if (before.length !== after.length) return false;
|
|
1251
|
-
for (const
|
|
1252
|
-
if (!after.includes(
|
|
1601
|
+
for (const frameId of before) {
|
|
1602
|
+
if (!after.includes(frameId)) return false;
|
|
1253
1603
|
}
|
|
1254
1604
|
return true;
|
|
1255
1605
|
}
|
|
1606
|
+
function formatCdpException(details) {
|
|
1607
|
+
return details.exception?.description || details.text || "CDP runtime evaluation failed.";
|
|
1608
|
+
}
|
|
1609
|
+
function isMissingExecutionContextError(error) {
|
|
1610
|
+
if (!(error instanceof Error)) return false;
|
|
1611
|
+
const message = error.message;
|
|
1612
|
+
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
1613
|
+
}
|
|
1256
1614
|
function isIgnorableFrameError(error) {
|
|
1257
1615
|
if (!(error instanceof Error)) return false;
|
|
1258
1616
|
const message = error.message;
|
|
1259
|
-
return message.includes("Frame was detached") || message.includes("Execution context was destroyed") || message.includes("Target page, context or browser has been closed");
|
|
1617
|
+
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");
|
|
1618
|
+
}
|
|
1619
|
+
function sleep(ms) {
|
|
1620
|
+
return new Promise((resolve) => {
|
|
1621
|
+
setTimeout(resolve, ms);
|
|
1622
|
+
});
|
|
1260
1623
|
}
|
|
1261
1624
|
|
|
1262
1625
|
// src/storage/local.ts
|
|
@@ -2157,6 +2520,66 @@ var OS_BOUNDARY_ATTR = "data-os-boundary";
|
|
|
2157
2520
|
var OS_UNAVAILABLE_ATTR = "data-os-unavailable";
|
|
2158
2521
|
var OS_IFRAME_BOUNDARY_TAG = "os-iframe-root";
|
|
2159
2522
|
var OS_SHADOW_BOUNDARY_TAG = "os-shadow-root";
|
|
2523
|
+
function decodeSerializedNodeTableEntry(nodeTable, rawIndex, label) {
|
|
2524
|
+
if (typeof rawIndex !== "number" || !Number.isInteger(rawIndex) || rawIndex < 0 || rawIndex >= nodeTable.length) {
|
|
2525
|
+
throw new Error(
|
|
2526
|
+
`Invalid serialized path node index at "${label}": expected a valid table index.`
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
2529
|
+
const node = nodeTable[rawIndex];
|
|
2530
|
+
if (!node || typeof node !== "object") {
|
|
2531
|
+
throw new Error(
|
|
2532
|
+
`Invalid serialized path node at "${label}": table entry is missing.`
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
return node;
|
|
2536
|
+
}
|
|
2537
|
+
function decodeSerializedDomPath(nodeTable, rawPath, label) {
|
|
2538
|
+
if (!Array.isArray(rawPath)) {
|
|
2539
|
+
throw new Error(
|
|
2540
|
+
`Invalid serialized path at "${label}": expected an array of node indexes.`
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
return rawPath.map(
|
|
2544
|
+
(value, index) => decodeSerializedNodeTableEntry(nodeTable, value, `${label}[${index}]`)
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
function decodeSerializedElementPath(nodeTable, rawPath, label) {
|
|
2548
|
+
if (!rawPath || typeof rawPath !== "object") {
|
|
2549
|
+
throw new Error(
|
|
2550
|
+
`Invalid serialized element path at "${label}": expected an object.`
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
if (rawPath.context !== void 0 && !Array.isArray(rawPath.context)) {
|
|
2554
|
+
throw new Error(
|
|
2555
|
+
`Invalid serialized context at "${label}.context": expected an array.`
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
const contextRaw = Array.isArray(rawPath.context) ? rawPath.context : [];
|
|
2559
|
+
const context = contextRaw.map((hop, hopIndex) => {
|
|
2560
|
+
if (!hop || typeof hop !== "object" || hop.kind !== "shadow") {
|
|
2561
|
+
throw new Error(
|
|
2562
|
+
`Invalid serialized context hop at "${label}.context[${hopIndex}]": expected a shadow hop.`
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
return {
|
|
2566
|
+
kind: "shadow",
|
|
2567
|
+
host: decodeSerializedDomPath(
|
|
2568
|
+
nodeTable,
|
|
2569
|
+
hop.host,
|
|
2570
|
+
`${label}.context[${hopIndex}].host`
|
|
2571
|
+
)
|
|
2572
|
+
};
|
|
2573
|
+
});
|
|
2574
|
+
return {
|
|
2575
|
+
context,
|
|
2576
|
+
nodes: decodeSerializedDomPath(
|
|
2577
|
+
nodeTable,
|
|
2578
|
+
rawPath.nodes,
|
|
2579
|
+
`${label}.nodes`
|
|
2580
|
+
)
|
|
2581
|
+
};
|
|
2582
|
+
}
|
|
2160
2583
|
async function serializePageHTML(page, _options = {}) {
|
|
2161
2584
|
return serializeFrameRecursive(page.mainFrame(), [], "f0");
|
|
2162
2585
|
}
|
|
@@ -2213,6 +2636,8 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2213
2636
|
(Array.isArray(deferredMatchAttrKeys) ? deferredMatchAttrKeys : []).map((key) => String(key))
|
|
2214
2637
|
);
|
|
2215
2638
|
let counter = 1;
|
|
2639
|
+
const nodeTable = [];
|
|
2640
|
+
const nodeTableIndexByKey = /* @__PURE__ */ new Map();
|
|
2216
2641
|
const entries = [];
|
|
2217
2642
|
const helpers = {
|
|
2218
2643
|
nextToken() {
|
|
@@ -2414,6 +2839,47 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2414
2839
|
nodes: target
|
|
2415
2840
|
};
|
|
2416
2841
|
},
|
|
2842
|
+
buildPathNodeKey(node) {
|
|
2843
|
+
const attrs = Object.entries(node.attrs || {}).sort(
|
|
2844
|
+
([a], [b]) => a.localeCompare(b)
|
|
2845
|
+
);
|
|
2846
|
+
const match = (node.match || []).map(
|
|
2847
|
+
(clause) => clause.kind === "attr" ? [
|
|
2848
|
+
"attr",
|
|
2849
|
+
clause.key,
|
|
2850
|
+
clause.op || "exact",
|
|
2851
|
+
clause.value ?? null
|
|
2852
|
+
] : ["position", clause.axis]
|
|
2853
|
+
);
|
|
2854
|
+
return JSON.stringify([
|
|
2855
|
+
node.tag,
|
|
2856
|
+
node.position.nthChild,
|
|
2857
|
+
node.position.nthOfType,
|
|
2858
|
+
attrs,
|
|
2859
|
+
match
|
|
2860
|
+
]);
|
|
2861
|
+
},
|
|
2862
|
+
internPathNode(node) {
|
|
2863
|
+
const key = helpers.buildPathNodeKey(node);
|
|
2864
|
+
const existing = nodeTableIndexByKey.get(key);
|
|
2865
|
+
if (existing != null) return existing;
|
|
2866
|
+
const index = nodeTable.length;
|
|
2867
|
+
nodeTable.push(node);
|
|
2868
|
+
nodeTableIndexByKey.set(key, index);
|
|
2869
|
+
return index;
|
|
2870
|
+
},
|
|
2871
|
+
packDomPath(path5) {
|
|
2872
|
+
return path5.map((node) => helpers.internPathNode(node));
|
|
2873
|
+
},
|
|
2874
|
+
packElementPath(path5) {
|
|
2875
|
+
return {
|
|
2876
|
+
context: (path5.context || []).map((hop) => ({
|
|
2877
|
+
kind: "shadow",
|
|
2878
|
+
host: helpers.packDomPath(hop.host)
|
|
2879
|
+
})),
|
|
2880
|
+
nodes: helpers.packDomPath(path5.nodes)
|
|
2881
|
+
};
|
|
2882
|
+
},
|
|
2417
2883
|
ensureNodeId(el) {
|
|
2418
2884
|
const next = `${frameKey2}_${counter++}`;
|
|
2419
2885
|
el.setAttribute(nodeAttr, next);
|
|
@@ -2443,9 +2909,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2443
2909
|
serializeElement(el) {
|
|
2444
2910
|
const nodeId = helpers.ensureNodeId(el);
|
|
2445
2911
|
const instanceToken = helpers.setInstanceToken(el);
|
|
2912
|
+
const packedPath = helpers.packElementPath(
|
|
2913
|
+
helpers.buildElementPath(el)
|
|
2914
|
+
);
|
|
2446
2915
|
entries.push({
|
|
2447
2916
|
nodeId,
|
|
2448
|
-
path:
|
|
2917
|
+
path: packedPath,
|
|
2449
2918
|
instanceToken
|
|
2450
2919
|
});
|
|
2451
2920
|
const tag = el.tagName.toLowerCase();
|
|
@@ -2473,11 +2942,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2473
2942
|
win[frameTokenKey] = frameToken;
|
|
2474
2943
|
const root = document.documentElement;
|
|
2475
2944
|
if (!root) {
|
|
2476
|
-
return { html: "", frameToken, entries };
|
|
2945
|
+
return { html: "", frameToken, nodeTable, entries };
|
|
2477
2946
|
}
|
|
2478
2947
|
return {
|
|
2479
2948
|
html: helpers.serializeElement(root),
|
|
2480
2949
|
frameToken,
|
|
2950
|
+
nodeTable,
|
|
2481
2951
|
entries
|
|
2482
2952
|
};
|
|
2483
2953
|
},
|
|
@@ -2495,13 +2965,18 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2495
2965
|
);
|
|
2496
2966
|
const nodePaths = /* @__PURE__ */ new Map();
|
|
2497
2967
|
const nodeMeta = /* @__PURE__ */ new Map();
|
|
2498
|
-
for (const entry of frameSnapshot.entries) {
|
|
2968
|
+
for (const [index, entry] of frameSnapshot.entries.entries()) {
|
|
2969
|
+
const path5 = decodeSerializedElementPath(
|
|
2970
|
+
frameSnapshot.nodeTable,
|
|
2971
|
+
entry.path,
|
|
2972
|
+
`entries[${index}].path`
|
|
2973
|
+
);
|
|
2499
2974
|
nodePaths.set(entry.nodeId, {
|
|
2500
2975
|
context: [
|
|
2501
2976
|
...baseContext,
|
|
2502
|
-
...
|
|
2977
|
+
...path5.context || []
|
|
2503
2978
|
],
|
|
2504
|
-
nodes:
|
|
2979
|
+
nodes: path5.nodes
|
|
2505
2980
|
});
|
|
2506
2981
|
nodeMeta.set(entry.nodeId, {
|
|
2507
2982
|
frameToken: frameSnapshot.frameToken,
|
|
@@ -4895,7 +5370,7 @@ async function performInput(page, path5, options) {
|
|
|
4895
5370
|
await resolved.element.type(options.text);
|
|
4896
5371
|
}
|
|
4897
5372
|
if (options.pressEnter) {
|
|
4898
|
-
await resolved.element.press("Enter");
|
|
5373
|
+
await resolved.element.press("Enter", { noWaitAfter: true });
|
|
4899
5374
|
}
|
|
4900
5375
|
return {
|
|
4901
5376
|
ok: true,
|
|
@@ -5561,7 +6036,26 @@ var ACTION_WAIT_PROFILES = {
|
|
|
5561
6036
|
type: ROBUST_PROFILE
|
|
5562
6037
|
};
|
|
5563
6038
|
var NETWORK_POLL_MS = 50;
|
|
5564
|
-
var
|
|
6039
|
+
var NETWORK_RELAX_AFTER_MS = 1800;
|
|
6040
|
+
var RELAXED_ALLOWED_PENDING = 2;
|
|
6041
|
+
var HEAVY_VISUAL_REQUEST_WINDOW_MS = 5e3;
|
|
6042
|
+
var TRACKED_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6043
|
+
"document",
|
|
6044
|
+
"fetch",
|
|
6045
|
+
"xhr",
|
|
6046
|
+
"stylesheet",
|
|
6047
|
+
"image",
|
|
6048
|
+
"font",
|
|
6049
|
+
"media"
|
|
6050
|
+
]);
|
|
6051
|
+
var HEAVY_RESOURCE_TYPES = /* @__PURE__ */ new Set(["document", "fetch", "xhr"]);
|
|
6052
|
+
var HEAVY_VISUAL_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6053
|
+
"stylesheet",
|
|
6054
|
+
"image",
|
|
6055
|
+
"font",
|
|
6056
|
+
"media"
|
|
6057
|
+
]);
|
|
6058
|
+
var IGNORED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["websocket", "eventsource", "manifest"]);
|
|
5565
6059
|
var NOOP_SESSION = {
|
|
5566
6060
|
async wait() {
|
|
5567
6061
|
},
|
|
@@ -5571,7 +6065,7 @@ var NOOP_SESSION = {
|
|
|
5571
6065
|
function createPostActionWaitSession(page, action, override) {
|
|
5572
6066
|
const profile = resolveActionWaitProfile(action, override);
|
|
5573
6067
|
if (!profile.enabled) return NOOP_SESSION;
|
|
5574
|
-
const tracker = profile.includeNetwork ? new
|
|
6068
|
+
const tracker = profile.includeNetwork ? new AdaptiveNetworkTracker(page) : null;
|
|
5575
6069
|
tracker?.start();
|
|
5576
6070
|
let settled = false;
|
|
5577
6071
|
return {
|
|
@@ -5579,19 +6073,32 @@ function createPostActionWaitSession(page, action, override) {
|
|
|
5579
6073
|
if (settled) return;
|
|
5580
6074
|
settled = true;
|
|
5581
6075
|
const deadline = Date.now() + profile.timeout;
|
|
5582
|
-
const
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
6076
|
+
const visualTimeout = profile.includeNetwork ? Math.min(
|
|
6077
|
+
profile.timeout,
|
|
6078
|
+
resolveNetworkBackedVisualTimeout(profile.settleMs)
|
|
6079
|
+
) : profile.timeout;
|
|
5586
6080
|
try {
|
|
5587
|
-
|
|
5588
|
-
waitForVisualStabilityAcrossFrames(page, {
|
|
5589
|
-
timeout:
|
|
6081
|
+
try {
|
|
6082
|
+
await waitForVisualStabilityAcrossFrames(page, {
|
|
6083
|
+
timeout: visualTimeout,
|
|
5590
6084
|
settleMs: profile.settleMs
|
|
5591
|
-
})
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
6085
|
+
});
|
|
6086
|
+
} catch (error) {
|
|
6087
|
+
if (isStealthWaitUnavailableError(error)) {
|
|
6088
|
+
throw error;
|
|
6089
|
+
}
|
|
6090
|
+
} finally {
|
|
6091
|
+
tracker?.freezeCollection();
|
|
6092
|
+
}
|
|
6093
|
+
if (tracker) {
|
|
6094
|
+
try {
|
|
6095
|
+
await tracker.waitForQuiet({
|
|
6096
|
+
deadline,
|
|
6097
|
+
quietMs: profile.networkQuietMs
|
|
6098
|
+
});
|
|
6099
|
+
} catch {
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
5595
6102
|
} finally {
|
|
5596
6103
|
tracker?.stop();
|
|
5597
6104
|
}
|
|
@@ -5631,53 +6138,70 @@ function normalizeMs(value, fallback) {
|
|
|
5631
6138
|
}
|
|
5632
6139
|
return Math.max(0, Math.floor(value));
|
|
5633
6140
|
}
|
|
5634
|
-
|
|
6141
|
+
function resolveNetworkBackedVisualTimeout(settleMs) {
|
|
6142
|
+
const derived = settleMs * 3 + 300;
|
|
6143
|
+
return Math.max(1200, Math.min(2500, derived));
|
|
6144
|
+
}
|
|
6145
|
+
var AdaptiveNetworkTracker = class {
|
|
5635
6146
|
constructor(page) {
|
|
5636
6147
|
this.page = page;
|
|
5637
6148
|
}
|
|
5638
|
-
pending = /* @__PURE__ */ new
|
|
6149
|
+
pending = /* @__PURE__ */ new Map();
|
|
5639
6150
|
started = false;
|
|
6151
|
+
collecting = false;
|
|
6152
|
+
startedAt = 0;
|
|
5640
6153
|
idleSince = Date.now();
|
|
5641
6154
|
start() {
|
|
5642
6155
|
if (this.started) return;
|
|
5643
6156
|
this.started = true;
|
|
6157
|
+
this.collecting = true;
|
|
6158
|
+
this.startedAt = Date.now();
|
|
6159
|
+
this.idleSince = this.startedAt;
|
|
5644
6160
|
this.page.on("request", this.handleRequestStarted);
|
|
5645
6161
|
this.page.on("requestfinished", this.handleRequestFinished);
|
|
5646
6162
|
this.page.on("requestfailed", this.handleRequestFinished);
|
|
5647
6163
|
}
|
|
6164
|
+
freezeCollection() {
|
|
6165
|
+
if (!this.started) return;
|
|
6166
|
+
this.collecting = false;
|
|
6167
|
+
}
|
|
5648
6168
|
stop() {
|
|
5649
6169
|
if (!this.started) return;
|
|
5650
6170
|
this.started = false;
|
|
6171
|
+
this.collecting = false;
|
|
5651
6172
|
this.page.off("request", this.handleRequestStarted);
|
|
5652
6173
|
this.page.off("requestfinished", this.handleRequestFinished);
|
|
5653
6174
|
this.page.off("requestfailed", this.handleRequestFinished);
|
|
5654
6175
|
this.pending.clear();
|
|
6176
|
+
this.startedAt = 0;
|
|
5655
6177
|
this.idleSince = Date.now();
|
|
5656
6178
|
}
|
|
5657
6179
|
async waitForQuiet(options) {
|
|
5658
6180
|
const quietMs = Math.max(0, options.quietMs);
|
|
5659
6181
|
if (quietMs === 0) return;
|
|
5660
6182
|
while (Date.now() < options.deadline) {
|
|
5661
|
-
|
|
6183
|
+
const now = Date.now();
|
|
6184
|
+
const allowedPending = this.resolveAllowedPending(now);
|
|
6185
|
+
if (this.pending.size <= allowedPending) {
|
|
5662
6186
|
if (this.idleSince === 0) {
|
|
5663
|
-
this.idleSince =
|
|
6187
|
+
this.idleSince = now;
|
|
5664
6188
|
}
|
|
5665
|
-
const idleFor =
|
|
6189
|
+
const idleFor = now - this.idleSince;
|
|
5666
6190
|
if (idleFor >= quietMs) {
|
|
5667
6191
|
return;
|
|
5668
6192
|
}
|
|
5669
6193
|
} else {
|
|
5670
6194
|
this.idleSince = 0;
|
|
5671
6195
|
}
|
|
5672
|
-
const remaining = Math.max(1, options.deadline -
|
|
5673
|
-
await
|
|
6196
|
+
const remaining = Math.max(1, options.deadline - now);
|
|
6197
|
+
await sleep2(Math.min(NETWORK_POLL_MS, remaining));
|
|
5674
6198
|
}
|
|
5675
6199
|
}
|
|
5676
6200
|
handleRequestStarted = (request) => {
|
|
5677
|
-
if (!this.started) return;
|
|
5678
|
-
const
|
|
5679
|
-
if (
|
|
5680
|
-
this.pending.
|
|
6201
|
+
if (!this.started || !this.collecting) return;
|
|
6202
|
+
const trackedRequest = this.classifyRequest(request);
|
|
6203
|
+
if (!trackedRequest) return;
|
|
6204
|
+
this.pending.set(request, trackedRequest);
|
|
5681
6205
|
this.idleSince = 0;
|
|
5682
6206
|
};
|
|
5683
6207
|
handleRequestFinished = (request) => {
|
|
@@ -5687,8 +6211,35 @@ var ScopedNetworkTracker = class {
|
|
|
5687
6211
|
this.idleSince = Date.now();
|
|
5688
6212
|
}
|
|
5689
6213
|
};
|
|
6214
|
+
classifyRequest(request) {
|
|
6215
|
+
const resourceType = request.resourceType().toLowerCase();
|
|
6216
|
+
if (IGNORED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6217
|
+
if (!TRACKED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6218
|
+
const frame = request.frame();
|
|
6219
|
+
if (!frame || frame !== this.page.mainFrame()) return null;
|
|
6220
|
+
return {
|
|
6221
|
+
resourceType,
|
|
6222
|
+
startedAt: Date.now()
|
|
6223
|
+
};
|
|
6224
|
+
}
|
|
6225
|
+
resolveAllowedPending(now) {
|
|
6226
|
+
const relaxed = now - this.startedAt >= NETWORK_RELAX_AFTER_MS ? RELAXED_ALLOWED_PENDING : 0;
|
|
6227
|
+
if (this.hasHeavyPending(now)) return 0;
|
|
6228
|
+
return relaxed;
|
|
6229
|
+
}
|
|
6230
|
+
hasHeavyPending(now) {
|
|
6231
|
+
for (const trackedRequest of this.pending.values()) {
|
|
6232
|
+
if (HEAVY_RESOURCE_TYPES.has(trackedRequest.resourceType)) {
|
|
6233
|
+
return true;
|
|
6234
|
+
}
|
|
6235
|
+
if (HEAVY_VISUAL_RESOURCE_TYPES.has(trackedRequest.resourceType) && now - trackedRequest.startedAt < HEAVY_VISUAL_REQUEST_WINDOW_MS) {
|
|
6236
|
+
return true;
|
|
6237
|
+
}
|
|
6238
|
+
}
|
|
6239
|
+
return false;
|
|
6240
|
+
}
|
|
5690
6241
|
};
|
|
5691
|
-
async function
|
|
6242
|
+
async function sleep2(ms) {
|
|
5692
6243
|
await new Promise((resolve) => {
|
|
5693
6244
|
setTimeout(resolve, ms);
|
|
5694
6245
|
});
|
|
@@ -7128,16 +7679,18 @@ var CACHE_IMPORT_BATCH_SIZE = 200;
|
|
|
7128
7679
|
var RemoteSessionClient = class {
|
|
7129
7680
|
baseUrl;
|
|
7130
7681
|
key;
|
|
7131
|
-
|
|
7682
|
+
authScheme;
|
|
7683
|
+
constructor(baseUrl, key, authScheme = "api-key") {
|
|
7132
7684
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
7133
7685
|
this.key = key;
|
|
7686
|
+
this.authScheme = authScheme;
|
|
7134
7687
|
}
|
|
7135
7688
|
async create(request) {
|
|
7136
7689
|
const response = await fetch(`${this.baseUrl}/sessions`, {
|
|
7137
7690
|
method: "POST",
|
|
7138
7691
|
headers: {
|
|
7139
7692
|
"content-type": "application/json",
|
|
7140
|
-
|
|
7693
|
+
...this.authHeaders()
|
|
7141
7694
|
},
|
|
7142
7695
|
body: JSON.stringify(request)
|
|
7143
7696
|
});
|
|
@@ -7150,7 +7703,7 @@ var RemoteSessionClient = class {
|
|
|
7150
7703
|
const response = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
|
|
7151
7704
|
method: "DELETE",
|
|
7152
7705
|
headers: {
|
|
7153
|
-
|
|
7706
|
+
...this.authHeaders()
|
|
7154
7707
|
}
|
|
7155
7708
|
});
|
|
7156
7709
|
if (response.status === 204) {
|
|
@@ -7180,7 +7733,7 @@ var RemoteSessionClient = class {
|
|
|
7180
7733
|
method: "POST",
|
|
7181
7734
|
headers: {
|
|
7182
7735
|
"content-type": "application/json",
|
|
7183
|
-
|
|
7736
|
+
...this.authHeaders()
|
|
7184
7737
|
},
|
|
7185
7738
|
body: JSON.stringify({ entries })
|
|
7186
7739
|
});
|
|
@@ -7189,6 +7742,16 @@ var RemoteSessionClient = class {
|
|
|
7189
7742
|
}
|
|
7190
7743
|
return await response.json();
|
|
7191
7744
|
}
|
|
7745
|
+
authHeaders() {
|
|
7746
|
+
if (this.authScheme === "bearer") {
|
|
7747
|
+
return {
|
|
7748
|
+
authorization: `Bearer ${this.key}`
|
|
7749
|
+
};
|
|
7750
|
+
}
|
|
7751
|
+
return {
|
|
7752
|
+
"x-api-key": this.key
|
|
7753
|
+
};
|
|
7754
|
+
}
|
|
7192
7755
|
};
|
|
7193
7756
|
function normalizeBaseUrl(baseUrl) {
|
|
7194
7757
|
return baseUrl.replace(/\/+$/, "");
|
|
@@ -7229,9 +7792,9 @@ function toRemoteErrorCode(code) {
|
|
|
7229
7792
|
|
|
7230
7793
|
// src/remote/runtime.ts
|
|
7231
7794
|
var DEFAULT_REMOTE_BASE_URL = "https://remote.opensteer.com";
|
|
7232
|
-
function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl()) {
|
|
7795
|
+
function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl(), authScheme = "api-key") {
|
|
7233
7796
|
return {
|
|
7234
|
-
sessionClient: new RemoteSessionClient(baseUrl, key),
|
|
7797
|
+
sessionClient: new RemoteSessionClient(baseUrl, key, authScheme),
|
|
7235
7798
|
cdpClient: new RemoteCdpClient(),
|
|
7236
7799
|
actionClient: null,
|
|
7237
7800
|
sessionId: null
|
|
@@ -7296,7 +7859,8 @@ var Opensteer = class _Opensteer {
|
|
|
7296
7859
|
}
|
|
7297
7860
|
this.remote = createRemoteRuntimeState(
|
|
7298
7861
|
apiKey,
|
|
7299
|
-
remoteConfig?.baseUrl
|
|
7862
|
+
remoteConfig?.baseUrl,
|
|
7863
|
+
remoteConfig?.authScheme
|
|
7300
7864
|
);
|
|
7301
7865
|
} else {
|
|
7302
7866
|
this.remote = null;
|
|
@@ -7752,7 +8316,7 @@ var Opensteer = class _Opensteer {
|
|
|
7752
8316
|
await handle.type(options.text);
|
|
7753
8317
|
}
|
|
7754
8318
|
if (options.pressEnter) {
|
|
7755
|
-
await handle.press("Enter");
|
|
8319
|
+
await handle.press("Enter", { noWaitAfter: true });
|
|
7756
8320
|
}
|
|
7757
8321
|
});
|
|
7758
8322
|
} catch (err) {
|