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
|
@@ -37,15 +37,52 @@ function sanitizeNamespaceSegment(segment) {
|
|
|
37
37
|
// src/navigation.ts
|
|
38
38
|
var DEFAULT_TIMEOUT = 3e4;
|
|
39
39
|
var DEFAULT_SETTLE_MS = 750;
|
|
40
|
+
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
41
|
+
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
42
|
+
var StealthWaitUnavailableError = class extends Error {
|
|
43
|
+
constructor(cause) {
|
|
44
|
+
super("Stealth visual wait requires Chromium CDP support.", { cause });
|
|
45
|
+
this.name = "StealthWaitUnavailableError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
function isStealthWaitUnavailableError(error) {
|
|
49
|
+
return error instanceof StealthWaitUnavailableError;
|
|
50
|
+
}
|
|
51
|
+
var FRAME_OWNER_VISIBILITY_FUNCTION = `function() {
|
|
52
|
+
if (!(this instanceof HTMLElement)) return false;
|
|
53
|
+
|
|
54
|
+
var rect = this.getBoundingClientRect();
|
|
55
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
56
|
+
if (
|
|
57
|
+
rect.bottom <= 0 ||
|
|
58
|
+
rect.right <= 0 ||
|
|
59
|
+
rect.top >= window.innerHeight ||
|
|
60
|
+
rect.left >= window.innerWidth
|
|
61
|
+
) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var style = window.getComputedStyle(this);
|
|
66
|
+
if (
|
|
67
|
+
style.display === 'none' ||
|
|
68
|
+
style.visibility === 'hidden' ||
|
|
69
|
+
Number(style.opacity) === 0
|
|
70
|
+
) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return true;
|
|
75
|
+
}`;
|
|
40
76
|
function buildStabilityScript(timeout, settleMs) {
|
|
41
77
|
return `new Promise(function(resolve) {
|
|
42
78
|
var deadline = Date.now() + ${timeout};
|
|
43
|
-
var timer = null;
|
|
44
79
|
var resolved = false;
|
|
80
|
+
var timer = null;
|
|
45
81
|
var observers = [];
|
|
46
82
|
var observedShadowRoots = [];
|
|
47
83
|
var fonts = document.fonts;
|
|
48
84
|
var fontsReady = !fonts || fonts.status === 'loaded';
|
|
85
|
+
var lastRelevantMutationAt = Date.now();
|
|
49
86
|
|
|
50
87
|
function clearObservers() {
|
|
51
88
|
for (var i = 0; i < observers.length; i++) {
|
|
@@ -63,9 +100,87 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
63
100
|
resolve();
|
|
64
101
|
}
|
|
65
102
|
|
|
103
|
+
function isElementVisiblyIntersectingViewport(element) {
|
|
104
|
+
if (!(element instanceof Element)) return false;
|
|
105
|
+
|
|
106
|
+
var rect = element.getBoundingClientRect();
|
|
107
|
+
var inViewport =
|
|
108
|
+
rect.width > 0 &&
|
|
109
|
+
rect.height > 0 &&
|
|
110
|
+
rect.bottom > 0 &&
|
|
111
|
+
rect.right > 0 &&
|
|
112
|
+
rect.top < window.innerHeight &&
|
|
113
|
+
rect.left < window.innerWidth;
|
|
114
|
+
|
|
115
|
+
if (!inViewport) return false;
|
|
116
|
+
|
|
117
|
+
var style = window.getComputedStyle(element);
|
|
118
|
+
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
if (Number(style.opacity) === 0) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function resolveRelevantElement(node) {
|
|
129
|
+
if (!node) return null;
|
|
130
|
+
if (node instanceof Element) return node;
|
|
131
|
+
if (typeof ShadowRoot !== 'undefined' && node instanceof ShadowRoot) {
|
|
132
|
+
return node.host instanceof Element ? node.host : null;
|
|
133
|
+
}
|
|
134
|
+
var parentElement = node.parentElement;
|
|
135
|
+
return parentElement instanceof Element ? parentElement : null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function isNodeVisiblyRelevant(node) {
|
|
139
|
+
var element = resolveRelevantElement(node);
|
|
140
|
+
if (!element) return false;
|
|
141
|
+
return isElementVisiblyIntersectingViewport(element);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function hasRelevantMutation(records) {
|
|
145
|
+
for (var i = 0; i < records.length; i++) {
|
|
146
|
+
var record = records[i];
|
|
147
|
+
if (isNodeVisiblyRelevant(record.target)) return true;
|
|
148
|
+
|
|
149
|
+
var addedNodes = record.addedNodes;
|
|
150
|
+
for (var j = 0; j < addedNodes.length; j++) {
|
|
151
|
+
if (isNodeVisiblyRelevant(addedNodes[j])) return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
var removedNodes = record.removedNodes;
|
|
155
|
+
for (var k = 0; k < removedNodes.length; k++) {
|
|
156
|
+
if (isNodeVisiblyRelevant(removedNodes[k])) return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function scheduleCheck() {
|
|
164
|
+
if (resolved) return;
|
|
165
|
+
if (timer) clearTimeout(timer);
|
|
166
|
+
|
|
167
|
+
var remaining = deadline - Date.now();
|
|
168
|
+
if (remaining <= 0) {
|
|
169
|
+
done();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var checkDelay = Math.min(120, Math.max(16, ${settleMs}));
|
|
174
|
+
timer = setTimeout(checkNow, checkDelay);
|
|
175
|
+
}
|
|
176
|
+
|
|
66
177
|
function observeMutations(target) {
|
|
67
178
|
if (!target) return;
|
|
68
|
-
var observer = new MutationObserver(function() {
|
|
179
|
+
var observer = new MutationObserver(function(records) {
|
|
180
|
+
if (!hasRelevantMutation(records)) return;
|
|
181
|
+
lastRelevantMutationAt = Date.now();
|
|
182
|
+
scheduleCheck();
|
|
183
|
+
});
|
|
69
184
|
observer.observe(target, {
|
|
70
185
|
childList: true,
|
|
71
186
|
subtree: true,
|
|
@@ -103,18 +218,25 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
103
218
|
var images = root.querySelectorAll('img');
|
|
104
219
|
for (var i = 0; i < images.length; i++) {
|
|
105
220
|
var img = images[i];
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
rect.bottom > 0 &&
|
|
109
|
-
rect.right > 0 &&
|
|
110
|
-
rect.top < window.innerHeight &&
|
|
111
|
-
rect.left < window.innerWidth;
|
|
112
|
-
if (inViewport && !img.complete) return false;
|
|
221
|
+
if (!isElementVisiblyIntersectingViewport(img)) continue;
|
|
222
|
+
if (!img.complete) return false;
|
|
113
223
|
}
|
|
114
224
|
return true;
|
|
115
225
|
}
|
|
116
226
|
|
|
117
|
-
function
|
|
227
|
+
function getAnimationTarget(effect) {
|
|
228
|
+
if (!effect) return null;
|
|
229
|
+
var target = effect.target;
|
|
230
|
+
if (target instanceof Element) return target;
|
|
231
|
+
|
|
232
|
+
if (target && target.element instanceof Element) {
|
|
233
|
+
return target.element;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function hasRunningVisibleFiniteAnimations() {
|
|
118
240
|
if (typeof document.getAnimations !== 'function') return false;
|
|
119
241
|
var animations = document.getAnimations();
|
|
120
242
|
|
|
@@ -128,6 +250,9 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
128
250
|
? timing.endTime
|
|
129
251
|
: Number.POSITIVE_INFINITY;
|
|
130
252
|
if (Number.isFinite(endTime) && endTime > 0) {
|
|
253
|
+
var target = getAnimationTarget(effect);
|
|
254
|
+
if (!target) continue;
|
|
255
|
+
if (!isElementVisiblyIntersectingViewport(target)) continue;
|
|
131
256
|
return true;
|
|
132
257
|
}
|
|
133
258
|
}
|
|
@@ -138,21 +263,29 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
138
263
|
function isVisuallyReady() {
|
|
139
264
|
if (!fontsReady) return false;
|
|
140
265
|
if (!checkViewportImages(document)) return false;
|
|
141
|
-
if (
|
|
266
|
+
if (hasRunningVisibleFiniteAnimations()) return false;
|
|
142
267
|
return true;
|
|
143
268
|
}
|
|
144
269
|
|
|
145
|
-
function
|
|
146
|
-
if (Date.now()
|
|
147
|
-
|
|
270
|
+
function checkNow() {
|
|
271
|
+
if (Date.now() >= deadline) {
|
|
272
|
+
done();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
148
276
|
observeOpenShadowRoots();
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
277
|
+
|
|
278
|
+
if (!isVisuallyReady()) {
|
|
279
|
+
scheduleCheck();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (Date.now() - lastRelevantMutationAt >= ${settleMs}) {
|
|
284
|
+
done();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
scheduleCheck();
|
|
156
289
|
}
|
|
157
290
|
|
|
158
291
|
observeMutations(document.documentElement);
|
|
@@ -161,67 +294,266 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
161
294
|
if (fonts && fonts.ready && typeof fonts.ready.then === 'function') {
|
|
162
295
|
fonts.ready.then(function() {
|
|
163
296
|
fontsReady = true;
|
|
164
|
-
|
|
297
|
+
scheduleCheck();
|
|
298
|
+
}, function() {
|
|
299
|
+
fontsReady = true;
|
|
300
|
+
scheduleCheck();
|
|
165
301
|
});
|
|
166
302
|
}
|
|
167
303
|
|
|
168
304
|
var safetyTimer = setTimeout(done, ${timeout});
|
|
169
305
|
|
|
170
|
-
|
|
306
|
+
scheduleCheck();
|
|
171
307
|
})`;
|
|
172
308
|
}
|
|
309
|
+
var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
310
|
+
constructor(session) {
|
|
311
|
+
this.session = session;
|
|
312
|
+
}
|
|
313
|
+
contextsByFrame = /* @__PURE__ */ new Map();
|
|
314
|
+
disposed = false;
|
|
315
|
+
static async create(page) {
|
|
316
|
+
let session;
|
|
317
|
+
try {
|
|
318
|
+
session = await page.context().newCDPSession(page);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
throw new StealthWaitUnavailableError(error);
|
|
321
|
+
}
|
|
322
|
+
const runtime = new _StealthCdpRuntime(session);
|
|
323
|
+
try {
|
|
324
|
+
await runtime.initialize();
|
|
325
|
+
return runtime;
|
|
326
|
+
} catch (error) {
|
|
327
|
+
await runtime.dispose();
|
|
328
|
+
throw new StealthWaitUnavailableError(error);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async dispose() {
|
|
332
|
+
if (this.disposed) return;
|
|
333
|
+
this.disposed = true;
|
|
334
|
+
this.contextsByFrame.clear();
|
|
335
|
+
await this.session.detach().catch(() => void 0);
|
|
336
|
+
}
|
|
337
|
+
async waitForMainFrameVisualStability(options) {
|
|
338
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
339
|
+
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
340
|
+
if (timeout <= 0) return;
|
|
341
|
+
const frameRecords = await this.getFrameRecords();
|
|
342
|
+
const mainFrame = frameRecords[0];
|
|
343
|
+
if (!mainFrame) return;
|
|
344
|
+
await this.waitForFrameVisualStability(mainFrame.frameId, timeout, settleMs);
|
|
345
|
+
}
|
|
346
|
+
async collectVisibleFrameIds() {
|
|
347
|
+
const frameRecords = await this.getFrameRecords();
|
|
348
|
+
if (frameRecords.length === 0) return [];
|
|
349
|
+
const visibleFrameIds = [];
|
|
350
|
+
for (const frameRecord of frameRecords) {
|
|
351
|
+
if (!frameRecord.parentFrameId) {
|
|
352
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
const parentContextId = await this.ensureFrameContextId(
|
|
357
|
+
frameRecord.parentFrameId
|
|
358
|
+
);
|
|
359
|
+
const visible = await this.isFrameOwnerVisible(
|
|
360
|
+
frameRecord.frameId,
|
|
361
|
+
parentContextId
|
|
362
|
+
);
|
|
363
|
+
if (visible) {
|
|
364
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
365
|
+
}
|
|
366
|
+
} catch (error) {
|
|
367
|
+
if (isIgnorableFrameError(error)) continue;
|
|
368
|
+
throw error;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return visibleFrameIds;
|
|
372
|
+
}
|
|
373
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs) {
|
|
374
|
+
if (timeout <= 0) return;
|
|
375
|
+
const script = buildStabilityScript(timeout, settleMs);
|
|
376
|
+
let contextId = await this.ensureFrameContextId(frameId);
|
|
377
|
+
try {
|
|
378
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
379
|
+
} catch (error) {
|
|
380
|
+
if (!isMissingExecutionContextError(error)) {
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
this.contextsByFrame.delete(frameId);
|
|
384
|
+
contextId = await this.ensureFrameContextId(frameId);
|
|
385
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async initialize() {
|
|
389
|
+
await this.session.send("Page.enable");
|
|
390
|
+
await this.session.send("Runtime.enable");
|
|
391
|
+
await this.session.send("DOM.enable");
|
|
392
|
+
}
|
|
393
|
+
async getFrameRecords() {
|
|
394
|
+
const treeResult = await this.session.send("Page.getFrameTree");
|
|
395
|
+
const records = [];
|
|
396
|
+
walkFrameTree(treeResult.frameTree, null, records);
|
|
397
|
+
return records;
|
|
398
|
+
}
|
|
399
|
+
async ensureFrameContextId(frameId) {
|
|
400
|
+
const cached = this.contextsByFrame.get(frameId);
|
|
401
|
+
if (cached != null) {
|
|
402
|
+
return cached;
|
|
403
|
+
}
|
|
404
|
+
const world = await this.session.send("Page.createIsolatedWorld", {
|
|
405
|
+
frameId,
|
|
406
|
+
worldName: STEALTH_WORLD_NAME
|
|
407
|
+
});
|
|
408
|
+
this.contextsByFrame.set(frameId, world.executionContextId);
|
|
409
|
+
return world.executionContextId;
|
|
410
|
+
}
|
|
411
|
+
async evaluateWithGuard(contextId, script, timeout) {
|
|
412
|
+
const evaluationPromise = this.evaluateScript(contextId, script);
|
|
413
|
+
const settledPromise = evaluationPromise.then(
|
|
414
|
+
() => ({ kind: "resolved" }),
|
|
415
|
+
(error) => ({ kind: "rejected", error })
|
|
416
|
+
);
|
|
417
|
+
const timeoutPromise = sleep(
|
|
418
|
+
timeout + FRAME_EVALUATE_GRACE_MS
|
|
419
|
+
).then(() => ({ kind: "timeout" }));
|
|
420
|
+
const result = await Promise.race([
|
|
421
|
+
settledPromise,
|
|
422
|
+
timeoutPromise
|
|
423
|
+
]);
|
|
424
|
+
if (result.kind === "rejected") {
|
|
425
|
+
throw result.error;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
async evaluateScript(contextId, expression) {
|
|
429
|
+
const result = await this.session.send("Runtime.evaluate", {
|
|
430
|
+
contextId,
|
|
431
|
+
expression,
|
|
432
|
+
awaitPromise: true,
|
|
433
|
+
returnByValue: true
|
|
434
|
+
});
|
|
435
|
+
if (result.exceptionDetails) {
|
|
436
|
+
throw new Error(formatCdpException(result.exceptionDetails));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async isFrameOwnerVisible(frameId, parentContextId) {
|
|
440
|
+
const owner = await this.session.send("DOM.getFrameOwner", {
|
|
441
|
+
frameId
|
|
442
|
+
});
|
|
443
|
+
const resolveParams = {
|
|
444
|
+
executionContextId: parentContextId
|
|
445
|
+
};
|
|
446
|
+
if (typeof owner.backendNodeId === "number") {
|
|
447
|
+
resolveParams.backendNodeId = owner.backendNodeId;
|
|
448
|
+
} else if (typeof owner.nodeId === "number") {
|
|
449
|
+
resolveParams.nodeId = owner.nodeId;
|
|
450
|
+
} else {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
const resolved = await this.session.send(
|
|
454
|
+
"DOM.resolveNode",
|
|
455
|
+
resolveParams
|
|
456
|
+
);
|
|
457
|
+
const objectId = resolved.object?.objectId;
|
|
458
|
+
if (!objectId) return false;
|
|
459
|
+
try {
|
|
460
|
+
const callResult = await this.session.send("Runtime.callFunctionOn", {
|
|
461
|
+
objectId,
|
|
462
|
+
functionDeclaration: FRAME_OWNER_VISIBILITY_FUNCTION,
|
|
463
|
+
returnByValue: true
|
|
464
|
+
});
|
|
465
|
+
if (callResult.exceptionDetails) {
|
|
466
|
+
throw new Error(formatCdpException(callResult.exceptionDetails));
|
|
467
|
+
}
|
|
468
|
+
return callResult.result.value === true;
|
|
469
|
+
} finally {
|
|
470
|
+
await this.releaseObject(objectId);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
async releaseObject(objectId) {
|
|
474
|
+
await this.session.send("Runtime.releaseObject", {
|
|
475
|
+
objectId
|
|
476
|
+
}).catch(() => void 0);
|
|
477
|
+
}
|
|
478
|
+
};
|
|
173
479
|
async function waitForVisualStability(page, options = {}) {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
480
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
481
|
+
try {
|
|
482
|
+
await runtime.waitForMainFrameVisualStability(options);
|
|
483
|
+
} finally {
|
|
484
|
+
await runtime.dispose();
|
|
485
|
+
}
|
|
180
486
|
}
|
|
181
487
|
async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
182
488
|
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
183
489
|
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
490
|
+
if (timeout <= 0) return;
|
|
184
491
|
const deadline = Date.now() + timeout;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
492
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
493
|
+
try {
|
|
494
|
+
while (true) {
|
|
495
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
496
|
+
if (remaining === 0) return;
|
|
497
|
+
const frameIds = await runtime.collectVisibleFrameIds();
|
|
498
|
+
if (frameIds.length === 0) return;
|
|
499
|
+
await Promise.all(
|
|
500
|
+
frameIds.map(async (frameId) => {
|
|
501
|
+
try {
|
|
502
|
+
await runtime.waitForFrameVisualStability(
|
|
503
|
+
frameId,
|
|
504
|
+
remaining,
|
|
505
|
+
settleMs
|
|
506
|
+
);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
if (isIgnorableFrameError(error)) return;
|
|
509
|
+
throw error;
|
|
510
|
+
}
|
|
511
|
+
})
|
|
512
|
+
);
|
|
513
|
+
const currentFrameIds = await runtime.collectVisibleFrameIds();
|
|
514
|
+
if (sameFrameIds(frameIds, currentFrameIds)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
205
517
|
}
|
|
518
|
+
} finally {
|
|
519
|
+
await runtime.dispose();
|
|
206
520
|
}
|
|
207
521
|
}
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
522
|
+
function walkFrameTree(node, parentFrameId, records) {
|
|
523
|
+
const frameId = node.frame?.id;
|
|
524
|
+
if (!frameId) return;
|
|
525
|
+
records.push({
|
|
526
|
+
frameId,
|
|
527
|
+
parentFrameId
|
|
528
|
+
});
|
|
529
|
+
for (const child of node.childFrames ?? []) {
|
|
530
|
+
walkFrameTree(child, frameId, records);
|
|
531
|
+
}
|
|
213
532
|
}
|
|
214
|
-
function
|
|
533
|
+
function sameFrameIds(before, after) {
|
|
215
534
|
if (before.length !== after.length) return false;
|
|
216
|
-
for (const
|
|
217
|
-
if (!after.includes(
|
|
535
|
+
for (const frameId of before) {
|
|
536
|
+
if (!after.includes(frameId)) return false;
|
|
218
537
|
}
|
|
219
538
|
return true;
|
|
220
539
|
}
|
|
540
|
+
function formatCdpException(details) {
|
|
541
|
+
return details.exception?.description || details.text || "CDP runtime evaluation failed.";
|
|
542
|
+
}
|
|
543
|
+
function isMissingExecutionContextError(error) {
|
|
544
|
+
if (!(error instanceof Error)) return false;
|
|
545
|
+
const message = error.message;
|
|
546
|
+
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
547
|
+
}
|
|
221
548
|
function isIgnorableFrameError(error) {
|
|
222
549
|
if (!(error instanceof Error)) return false;
|
|
223
550
|
const message = error.message;
|
|
224
|
-
return message.includes("Frame was detached") || message.includes("Execution context was destroyed") || message.includes("Target page, context or browser has been closed");
|
|
551
|
+
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");
|
|
552
|
+
}
|
|
553
|
+
function sleep(ms) {
|
|
554
|
+
return new Promise((resolve) => {
|
|
555
|
+
setTimeout(resolve, ms);
|
|
556
|
+
});
|
|
225
557
|
}
|
|
226
558
|
|
|
227
559
|
// src/storage/registry.ts
|
|
@@ -1114,6 +1446,66 @@ var OS_BOUNDARY_ATTR = "data-os-boundary";
|
|
|
1114
1446
|
var OS_UNAVAILABLE_ATTR = "data-os-unavailable";
|
|
1115
1447
|
var OS_IFRAME_BOUNDARY_TAG = "os-iframe-root";
|
|
1116
1448
|
var OS_SHADOW_BOUNDARY_TAG = "os-shadow-root";
|
|
1449
|
+
function decodeSerializedNodeTableEntry(nodeTable, rawIndex, label) {
|
|
1450
|
+
if (typeof rawIndex !== "number" || !Number.isInteger(rawIndex) || rawIndex < 0 || rawIndex >= nodeTable.length) {
|
|
1451
|
+
throw new Error(
|
|
1452
|
+
`Invalid serialized path node index at "${label}": expected a valid table index.`
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
const node = nodeTable[rawIndex];
|
|
1456
|
+
if (!node || typeof node !== "object") {
|
|
1457
|
+
throw new Error(
|
|
1458
|
+
`Invalid serialized path node at "${label}": table entry is missing.`
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
return node;
|
|
1462
|
+
}
|
|
1463
|
+
function decodeSerializedDomPath(nodeTable, rawPath, label) {
|
|
1464
|
+
if (!Array.isArray(rawPath)) {
|
|
1465
|
+
throw new Error(
|
|
1466
|
+
`Invalid serialized path at "${label}": expected an array of node indexes.`
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
return rawPath.map(
|
|
1470
|
+
(value, index) => decodeSerializedNodeTableEntry(nodeTable, value, `${label}[${index}]`)
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
function decodeSerializedElementPath(nodeTable, rawPath, label) {
|
|
1474
|
+
if (!rawPath || typeof rawPath !== "object") {
|
|
1475
|
+
throw new Error(
|
|
1476
|
+
`Invalid serialized element path at "${label}": expected an object.`
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
if (rawPath.context !== void 0 && !Array.isArray(rawPath.context)) {
|
|
1480
|
+
throw new Error(
|
|
1481
|
+
`Invalid serialized context at "${label}.context": expected an array.`
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
const contextRaw = Array.isArray(rawPath.context) ? rawPath.context : [];
|
|
1485
|
+
const context = contextRaw.map((hop, hopIndex) => {
|
|
1486
|
+
if (!hop || typeof hop !== "object" || hop.kind !== "shadow") {
|
|
1487
|
+
throw new Error(
|
|
1488
|
+
`Invalid serialized context hop at "${label}.context[${hopIndex}]": expected a shadow hop.`
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1491
|
+
return {
|
|
1492
|
+
kind: "shadow",
|
|
1493
|
+
host: decodeSerializedDomPath(
|
|
1494
|
+
nodeTable,
|
|
1495
|
+
hop.host,
|
|
1496
|
+
`${label}.context[${hopIndex}].host`
|
|
1497
|
+
)
|
|
1498
|
+
};
|
|
1499
|
+
});
|
|
1500
|
+
return {
|
|
1501
|
+
context,
|
|
1502
|
+
nodes: decodeSerializedDomPath(
|
|
1503
|
+
nodeTable,
|
|
1504
|
+
rawPath.nodes,
|
|
1505
|
+
`${label}.nodes`
|
|
1506
|
+
)
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1117
1509
|
async function serializePageHTML(page, _options = {}) {
|
|
1118
1510
|
return serializeFrameRecursive(page.mainFrame(), [], "f0");
|
|
1119
1511
|
}
|
|
@@ -1170,6 +1562,8 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
1170
1562
|
(Array.isArray(deferredMatchAttrKeys) ? deferredMatchAttrKeys : []).map((key) => String(key))
|
|
1171
1563
|
);
|
|
1172
1564
|
let counter = 1;
|
|
1565
|
+
const nodeTable = [];
|
|
1566
|
+
const nodeTableIndexByKey = /* @__PURE__ */ new Map();
|
|
1173
1567
|
const entries = [];
|
|
1174
1568
|
const helpers = {
|
|
1175
1569
|
nextToken() {
|
|
@@ -1371,6 +1765,47 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
1371
1765
|
nodes: target
|
|
1372
1766
|
};
|
|
1373
1767
|
},
|
|
1768
|
+
buildPathNodeKey(node) {
|
|
1769
|
+
const attrs = Object.entries(node.attrs || {}).sort(
|
|
1770
|
+
([a], [b]) => a.localeCompare(b)
|
|
1771
|
+
);
|
|
1772
|
+
const match = (node.match || []).map(
|
|
1773
|
+
(clause) => clause.kind === "attr" ? [
|
|
1774
|
+
"attr",
|
|
1775
|
+
clause.key,
|
|
1776
|
+
clause.op || "exact",
|
|
1777
|
+
clause.value ?? null
|
|
1778
|
+
] : ["position", clause.axis]
|
|
1779
|
+
);
|
|
1780
|
+
return JSON.stringify([
|
|
1781
|
+
node.tag,
|
|
1782
|
+
node.position.nthChild,
|
|
1783
|
+
node.position.nthOfType,
|
|
1784
|
+
attrs,
|
|
1785
|
+
match
|
|
1786
|
+
]);
|
|
1787
|
+
},
|
|
1788
|
+
internPathNode(node) {
|
|
1789
|
+
const key = helpers.buildPathNodeKey(node);
|
|
1790
|
+
const existing = nodeTableIndexByKey.get(key);
|
|
1791
|
+
if (existing != null) return existing;
|
|
1792
|
+
const index = nodeTable.length;
|
|
1793
|
+
nodeTable.push(node);
|
|
1794
|
+
nodeTableIndexByKey.set(key, index);
|
|
1795
|
+
return index;
|
|
1796
|
+
},
|
|
1797
|
+
packDomPath(path5) {
|
|
1798
|
+
return path5.map((node) => helpers.internPathNode(node));
|
|
1799
|
+
},
|
|
1800
|
+
packElementPath(path5) {
|
|
1801
|
+
return {
|
|
1802
|
+
context: (path5.context || []).map((hop) => ({
|
|
1803
|
+
kind: "shadow",
|
|
1804
|
+
host: helpers.packDomPath(hop.host)
|
|
1805
|
+
})),
|
|
1806
|
+
nodes: helpers.packDomPath(path5.nodes)
|
|
1807
|
+
};
|
|
1808
|
+
},
|
|
1374
1809
|
ensureNodeId(el) {
|
|
1375
1810
|
const next = `${frameKey2}_${counter++}`;
|
|
1376
1811
|
el.setAttribute(nodeAttr, next);
|
|
@@ -1400,9 +1835,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
1400
1835
|
serializeElement(el) {
|
|
1401
1836
|
const nodeId = helpers.ensureNodeId(el);
|
|
1402
1837
|
const instanceToken = helpers.setInstanceToken(el);
|
|
1838
|
+
const packedPath = helpers.packElementPath(
|
|
1839
|
+
helpers.buildElementPath(el)
|
|
1840
|
+
);
|
|
1403
1841
|
entries.push({
|
|
1404
1842
|
nodeId,
|
|
1405
|
-
path:
|
|
1843
|
+
path: packedPath,
|
|
1406
1844
|
instanceToken
|
|
1407
1845
|
});
|
|
1408
1846
|
const tag = el.tagName.toLowerCase();
|
|
@@ -1430,11 +1868,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
1430
1868
|
win[frameTokenKey] = frameToken;
|
|
1431
1869
|
const root = document.documentElement;
|
|
1432
1870
|
if (!root) {
|
|
1433
|
-
return { html: "", frameToken, entries };
|
|
1871
|
+
return { html: "", frameToken, nodeTable, entries };
|
|
1434
1872
|
}
|
|
1435
1873
|
return {
|
|
1436
1874
|
html: helpers.serializeElement(root),
|
|
1437
1875
|
frameToken,
|
|
1876
|
+
nodeTable,
|
|
1438
1877
|
entries
|
|
1439
1878
|
};
|
|
1440
1879
|
},
|
|
@@ -1452,13 +1891,18 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
1452
1891
|
);
|
|
1453
1892
|
const nodePaths = /* @__PURE__ */ new Map();
|
|
1454
1893
|
const nodeMeta = /* @__PURE__ */ new Map();
|
|
1455
|
-
for (const entry of frameSnapshot.entries) {
|
|
1894
|
+
for (const [index, entry] of frameSnapshot.entries.entries()) {
|
|
1895
|
+
const path5 = decodeSerializedElementPath(
|
|
1896
|
+
frameSnapshot.nodeTable,
|
|
1897
|
+
entry.path,
|
|
1898
|
+
`entries[${index}].path`
|
|
1899
|
+
);
|
|
1456
1900
|
nodePaths.set(entry.nodeId, {
|
|
1457
1901
|
context: [
|
|
1458
1902
|
...baseContext,
|
|
1459
|
-
...
|
|
1903
|
+
...path5.context || []
|
|
1460
1904
|
],
|
|
1461
|
-
nodes:
|
|
1905
|
+
nodes: path5.nodes
|
|
1462
1906
|
});
|
|
1463
1907
|
nodeMeta.set(entry.nodeId, {
|
|
1464
1908
|
frameToken: frameSnapshot.frameToken,
|
|
@@ -3854,7 +4298,7 @@ async function performInput(page, path5, options) {
|
|
|
3854
4298
|
await resolved.element.type(options.text);
|
|
3855
4299
|
}
|
|
3856
4300
|
if (options.pressEnter) {
|
|
3857
|
-
await resolved.element.press("Enter");
|
|
4301
|
+
await resolved.element.press("Enter", { noWaitAfter: true });
|
|
3858
4302
|
}
|
|
3859
4303
|
return {
|
|
3860
4304
|
ok: true,
|
|
@@ -4814,16 +5258,18 @@ var CACHE_IMPORT_BATCH_SIZE = 200;
|
|
|
4814
5258
|
var RemoteSessionClient = class {
|
|
4815
5259
|
baseUrl;
|
|
4816
5260
|
key;
|
|
4817
|
-
|
|
5261
|
+
authScheme;
|
|
5262
|
+
constructor(baseUrl, key, authScheme = "api-key") {
|
|
4818
5263
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
4819
5264
|
this.key = key;
|
|
5265
|
+
this.authScheme = authScheme;
|
|
4820
5266
|
}
|
|
4821
5267
|
async create(request) {
|
|
4822
5268
|
const response = await fetch(`${this.baseUrl}/sessions`, {
|
|
4823
5269
|
method: "POST",
|
|
4824
5270
|
headers: {
|
|
4825
5271
|
"content-type": "application/json",
|
|
4826
|
-
|
|
5272
|
+
...this.authHeaders()
|
|
4827
5273
|
},
|
|
4828
5274
|
body: JSON.stringify(request)
|
|
4829
5275
|
});
|
|
@@ -4836,7 +5282,7 @@ var RemoteSessionClient = class {
|
|
|
4836
5282
|
const response = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
|
|
4837
5283
|
method: "DELETE",
|
|
4838
5284
|
headers: {
|
|
4839
|
-
|
|
5285
|
+
...this.authHeaders()
|
|
4840
5286
|
}
|
|
4841
5287
|
});
|
|
4842
5288
|
if (response.status === 204) {
|
|
@@ -4866,7 +5312,7 @@ var RemoteSessionClient = class {
|
|
|
4866
5312
|
method: "POST",
|
|
4867
5313
|
headers: {
|
|
4868
5314
|
"content-type": "application/json",
|
|
4869
|
-
|
|
5315
|
+
...this.authHeaders()
|
|
4870
5316
|
},
|
|
4871
5317
|
body: JSON.stringify({ entries })
|
|
4872
5318
|
});
|
|
@@ -4875,6 +5321,16 @@ var RemoteSessionClient = class {
|
|
|
4875
5321
|
}
|
|
4876
5322
|
return await response.json();
|
|
4877
5323
|
}
|
|
5324
|
+
authHeaders() {
|
|
5325
|
+
if (this.authScheme === "bearer") {
|
|
5326
|
+
return {
|
|
5327
|
+
authorization: `Bearer ${this.key}`
|
|
5328
|
+
};
|
|
5329
|
+
}
|
|
5330
|
+
return {
|
|
5331
|
+
"x-api-key": this.key
|
|
5332
|
+
};
|
|
5333
|
+
}
|
|
4878
5334
|
};
|
|
4879
5335
|
function normalizeBaseUrl(baseUrl) {
|
|
4880
5336
|
return baseUrl.replace(/\/+$/, "");
|
|
@@ -5496,11 +5952,33 @@ function parseMode(value, source) {
|
|
|
5496
5952
|
`Invalid ${source} value "${value}". Use "local" or "remote".`
|
|
5497
5953
|
);
|
|
5498
5954
|
}
|
|
5955
|
+
function parseAuthScheme(value, source) {
|
|
5956
|
+
if (value == null) return void 0;
|
|
5957
|
+
if (typeof value !== "string") {
|
|
5958
|
+
throw new Error(
|
|
5959
|
+
`Invalid ${source} value "${String(value)}". Use "api-key" or "bearer".`
|
|
5960
|
+
);
|
|
5961
|
+
}
|
|
5962
|
+
const normalized = value.trim().toLowerCase();
|
|
5963
|
+
if (!normalized) return void 0;
|
|
5964
|
+
if (normalized === "api-key" || normalized === "bearer") {
|
|
5965
|
+
return normalized;
|
|
5966
|
+
}
|
|
5967
|
+
throw new Error(
|
|
5968
|
+
`Invalid ${source} value "${value}". Use "api-key" or "bearer".`
|
|
5969
|
+
);
|
|
5970
|
+
}
|
|
5499
5971
|
function resolveOpensteerApiKey() {
|
|
5500
5972
|
const value = process.env.OPENSTEER_API_KEY?.trim();
|
|
5501
5973
|
if (!value) return void 0;
|
|
5502
5974
|
return value;
|
|
5503
5975
|
}
|
|
5976
|
+
function resolveOpensteerAuthScheme() {
|
|
5977
|
+
return parseAuthScheme(
|
|
5978
|
+
process.env.OPENSTEER_AUTH_SCHEME,
|
|
5979
|
+
"OPENSTEER_AUTH_SCHEME"
|
|
5980
|
+
);
|
|
5981
|
+
}
|
|
5504
5982
|
function normalizeRemoteOptions(value) {
|
|
5505
5983
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5506
5984
|
return void 0;
|
|
@@ -5560,7 +6038,12 @@ function resolveConfig(input = {}) {
|
|
|
5560
6038
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
5561
6039
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
5562
6040
|
const envApiKey = resolveOpensteerApiKey();
|
|
6041
|
+
const envAuthScheme = resolveOpensteerAuthScheme();
|
|
5563
6042
|
const inputRemoteOptions = normalizeRemoteOptions(input.remote);
|
|
6043
|
+
const inputAuthScheme = parseAuthScheme(
|
|
6044
|
+
inputRemoteOptions?.authScheme,
|
|
6045
|
+
"remote.authScheme"
|
|
6046
|
+
);
|
|
5564
6047
|
const inputHasRemoteApiKey = Boolean(
|
|
5565
6048
|
inputRemoteOptions && Object.prototype.hasOwnProperty.call(inputRemoteOptions, "apiKey")
|
|
5566
6049
|
);
|
|
@@ -5568,8 +6051,12 @@ function resolveConfig(input = {}) {
|
|
|
5568
6051
|
mode: resolved.mode
|
|
5569
6052
|
});
|
|
5570
6053
|
if (modeSelection.mode === "remote") {
|
|
5571
|
-
const resolvedRemote = normalizeRemoteOptions(resolved.remote);
|
|
5572
|
-
|
|
6054
|
+
const resolvedRemote = normalizeRemoteOptions(resolved.remote) ?? {};
|
|
6055
|
+
const authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedRemote.authScheme, "remote.authScheme") ?? "api-key";
|
|
6056
|
+
resolved.remote = {
|
|
6057
|
+
...resolvedRemote,
|
|
6058
|
+
authScheme
|
|
6059
|
+
};
|
|
5573
6060
|
}
|
|
5574
6061
|
if (envApiKey && modeSelection.mode === "remote" && !inputHasRemoteApiKey) {
|
|
5575
6062
|
resolved.remote = {
|
|
@@ -5648,7 +6135,26 @@ var ACTION_WAIT_PROFILES = {
|
|
|
5648
6135
|
type: ROBUST_PROFILE
|
|
5649
6136
|
};
|
|
5650
6137
|
var NETWORK_POLL_MS = 50;
|
|
5651
|
-
var
|
|
6138
|
+
var NETWORK_RELAX_AFTER_MS = 1800;
|
|
6139
|
+
var RELAXED_ALLOWED_PENDING = 2;
|
|
6140
|
+
var HEAVY_VISUAL_REQUEST_WINDOW_MS = 5e3;
|
|
6141
|
+
var TRACKED_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6142
|
+
"document",
|
|
6143
|
+
"fetch",
|
|
6144
|
+
"xhr",
|
|
6145
|
+
"stylesheet",
|
|
6146
|
+
"image",
|
|
6147
|
+
"font",
|
|
6148
|
+
"media"
|
|
6149
|
+
]);
|
|
6150
|
+
var HEAVY_RESOURCE_TYPES = /* @__PURE__ */ new Set(["document", "fetch", "xhr"]);
|
|
6151
|
+
var HEAVY_VISUAL_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6152
|
+
"stylesheet",
|
|
6153
|
+
"image",
|
|
6154
|
+
"font",
|
|
6155
|
+
"media"
|
|
6156
|
+
]);
|
|
6157
|
+
var IGNORED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["websocket", "eventsource", "manifest"]);
|
|
5652
6158
|
var NOOP_SESSION = {
|
|
5653
6159
|
async wait() {
|
|
5654
6160
|
},
|
|
@@ -5658,7 +6164,7 @@ var NOOP_SESSION = {
|
|
|
5658
6164
|
function createPostActionWaitSession(page, action, override) {
|
|
5659
6165
|
const profile = resolveActionWaitProfile(action, override);
|
|
5660
6166
|
if (!profile.enabled) return NOOP_SESSION;
|
|
5661
|
-
const tracker = profile.includeNetwork ? new
|
|
6167
|
+
const tracker = profile.includeNetwork ? new AdaptiveNetworkTracker(page) : null;
|
|
5662
6168
|
tracker?.start();
|
|
5663
6169
|
let settled = false;
|
|
5664
6170
|
return {
|
|
@@ -5666,19 +6172,32 @@ function createPostActionWaitSession(page, action, override) {
|
|
|
5666
6172
|
if (settled) return;
|
|
5667
6173
|
settled = true;
|
|
5668
6174
|
const deadline = Date.now() + profile.timeout;
|
|
5669
|
-
const
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
6175
|
+
const visualTimeout = profile.includeNetwork ? Math.min(
|
|
6176
|
+
profile.timeout,
|
|
6177
|
+
resolveNetworkBackedVisualTimeout(profile.settleMs)
|
|
6178
|
+
) : profile.timeout;
|
|
5673
6179
|
try {
|
|
5674
|
-
|
|
5675
|
-
waitForVisualStabilityAcrossFrames(page, {
|
|
5676
|
-
timeout:
|
|
6180
|
+
try {
|
|
6181
|
+
await waitForVisualStabilityAcrossFrames(page, {
|
|
6182
|
+
timeout: visualTimeout,
|
|
5677
6183
|
settleMs: profile.settleMs
|
|
5678
|
-
})
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
6184
|
+
});
|
|
6185
|
+
} catch (error) {
|
|
6186
|
+
if (isStealthWaitUnavailableError(error)) {
|
|
6187
|
+
throw error;
|
|
6188
|
+
}
|
|
6189
|
+
} finally {
|
|
6190
|
+
tracker?.freezeCollection();
|
|
6191
|
+
}
|
|
6192
|
+
if (tracker) {
|
|
6193
|
+
try {
|
|
6194
|
+
await tracker.waitForQuiet({
|
|
6195
|
+
deadline,
|
|
6196
|
+
quietMs: profile.networkQuietMs
|
|
6197
|
+
});
|
|
6198
|
+
} catch {
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
5682
6201
|
} finally {
|
|
5683
6202
|
tracker?.stop();
|
|
5684
6203
|
}
|
|
@@ -5718,53 +6237,70 @@ function normalizeMs(value, fallback) {
|
|
|
5718
6237
|
}
|
|
5719
6238
|
return Math.max(0, Math.floor(value));
|
|
5720
6239
|
}
|
|
5721
|
-
|
|
6240
|
+
function resolveNetworkBackedVisualTimeout(settleMs) {
|
|
6241
|
+
const derived = settleMs * 3 + 300;
|
|
6242
|
+
return Math.max(1200, Math.min(2500, derived));
|
|
6243
|
+
}
|
|
6244
|
+
var AdaptiveNetworkTracker = class {
|
|
5722
6245
|
constructor(page) {
|
|
5723
6246
|
this.page = page;
|
|
5724
6247
|
}
|
|
5725
|
-
pending = /* @__PURE__ */ new
|
|
6248
|
+
pending = /* @__PURE__ */ new Map();
|
|
5726
6249
|
started = false;
|
|
6250
|
+
collecting = false;
|
|
6251
|
+
startedAt = 0;
|
|
5727
6252
|
idleSince = Date.now();
|
|
5728
6253
|
start() {
|
|
5729
6254
|
if (this.started) return;
|
|
5730
6255
|
this.started = true;
|
|
6256
|
+
this.collecting = true;
|
|
6257
|
+
this.startedAt = Date.now();
|
|
6258
|
+
this.idleSince = this.startedAt;
|
|
5731
6259
|
this.page.on("request", this.handleRequestStarted);
|
|
5732
6260
|
this.page.on("requestfinished", this.handleRequestFinished);
|
|
5733
6261
|
this.page.on("requestfailed", this.handleRequestFinished);
|
|
5734
6262
|
}
|
|
6263
|
+
freezeCollection() {
|
|
6264
|
+
if (!this.started) return;
|
|
6265
|
+
this.collecting = false;
|
|
6266
|
+
}
|
|
5735
6267
|
stop() {
|
|
5736
6268
|
if (!this.started) return;
|
|
5737
6269
|
this.started = false;
|
|
6270
|
+
this.collecting = false;
|
|
5738
6271
|
this.page.off("request", this.handleRequestStarted);
|
|
5739
6272
|
this.page.off("requestfinished", this.handleRequestFinished);
|
|
5740
6273
|
this.page.off("requestfailed", this.handleRequestFinished);
|
|
5741
6274
|
this.pending.clear();
|
|
6275
|
+
this.startedAt = 0;
|
|
5742
6276
|
this.idleSince = Date.now();
|
|
5743
6277
|
}
|
|
5744
6278
|
async waitForQuiet(options) {
|
|
5745
6279
|
const quietMs = Math.max(0, options.quietMs);
|
|
5746
6280
|
if (quietMs === 0) return;
|
|
5747
6281
|
while (Date.now() < options.deadline) {
|
|
5748
|
-
|
|
6282
|
+
const now = Date.now();
|
|
6283
|
+
const allowedPending = this.resolveAllowedPending(now);
|
|
6284
|
+
if (this.pending.size <= allowedPending) {
|
|
5749
6285
|
if (this.idleSince === 0) {
|
|
5750
|
-
this.idleSince =
|
|
6286
|
+
this.idleSince = now;
|
|
5751
6287
|
}
|
|
5752
|
-
const idleFor =
|
|
6288
|
+
const idleFor = now - this.idleSince;
|
|
5753
6289
|
if (idleFor >= quietMs) {
|
|
5754
6290
|
return;
|
|
5755
6291
|
}
|
|
5756
6292
|
} else {
|
|
5757
6293
|
this.idleSince = 0;
|
|
5758
6294
|
}
|
|
5759
|
-
const remaining = Math.max(1, options.deadline -
|
|
5760
|
-
await
|
|
6295
|
+
const remaining = Math.max(1, options.deadline - now);
|
|
6296
|
+
await sleep2(Math.min(NETWORK_POLL_MS, remaining));
|
|
5761
6297
|
}
|
|
5762
6298
|
}
|
|
5763
6299
|
handleRequestStarted = (request) => {
|
|
5764
|
-
if (!this.started) return;
|
|
5765
|
-
const
|
|
5766
|
-
if (
|
|
5767
|
-
this.pending.
|
|
6300
|
+
if (!this.started || !this.collecting) return;
|
|
6301
|
+
const trackedRequest = this.classifyRequest(request);
|
|
6302
|
+
if (!trackedRequest) return;
|
|
6303
|
+
this.pending.set(request, trackedRequest);
|
|
5768
6304
|
this.idleSince = 0;
|
|
5769
6305
|
};
|
|
5770
6306
|
handleRequestFinished = (request) => {
|
|
@@ -5774,8 +6310,35 @@ var ScopedNetworkTracker = class {
|
|
|
5774
6310
|
this.idleSince = Date.now();
|
|
5775
6311
|
}
|
|
5776
6312
|
};
|
|
6313
|
+
classifyRequest(request) {
|
|
6314
|
+
const resourceType = request.resourceType().toLowerCase();
|
|
6315
|
+
if (IGNORED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6316
|
+
if (!TRACKED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6317
|
+
const frame = request.frame();
|
|
6318
|
+
if (!frame || frame !== this.page.mainFrame()) return null;
|
|
6319
|
+
return {
|
|
6320
|
+
resourceType,
|
|
6321
|
+
startedAt: Date.now()
|
|
6322
|
+
};
|
|
6323
|
+
}
|
|
6324
|
+
resolveAllowedPending(now) {
|
|
6325
|
+
const relaxed = now - this.startedAt >= NETWORK_RELAX_AFTER_MS ? RELAXED_ALLOWED_PENDING : 0;
|
|
6326
|
+
if (this.hasHeavyPending(now)) return 0;
|
|
6327
|
+
return relaxed;
|
|
6328
|
+
}
|
|
6329
|
+
hasHeavyPending(now) {
|
|
6330
|
+
for (const trackedRequest of this.pending.values()) {
|
|
6331
|
+
if (HEAVY_RESOURCE_TYPES.has(trackedRequest.resourceType)) {
|
|
6332
|
+
return true;
|
|
6333
|
+
}
|
|
6334
|
+
if (HEAVY_VISUAL_RESOURCE_TYPES.has(trackedRequest.resourceType) && now - trackedRequest.startedAt < HEAVY_VISUAL_REQUEST_WINDOW_MS) {
|
|
6335
|
+
return true;
|
|
6336
|
+
}
|
|
6337
|
+
}
|
|
6338
|
+
return false;
|
|
6339
|
+
}
|
|
5777
6340
|
};
|
|
5778
|
-
async function
|
|
6341
|
+
async function sleep2(ms) {
|
|
5779
6342
|
await new Promise((resolve) => {
|
|
5780
6343
|
setTimeout(resolve, ms);
|
|
5781
6344
|
});
|
|
@@ -6895,9 +7458,9 @@ function clonePersistedExtractNode(node) {
|
|
|
6895
7458
|
|
|
6896
7459
|
// src/remote/runtime.ts
|
|
6897
7460
|
var DEFAULT_REMOTE_BASE_URL = "https://remote.opensteer.com";
|
|
6898
|
-
function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl()) {
|
|
7461
|
+
function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl(), authScheme = "api-key") {
|
|
6899
7462
|
return {
|
|
6900
|
-
sessionClient: new RemoteSessionClient(baseUrl, key),
|
|
7463
|
+
sessionClient: new RemoteSessionClient(baseUrl, key, authScheme),
|
|
6901
7464
|
cdpClient: new RemoteCdpClient(),
|
|
6902
7465
|
actionClient: null,
|
|
6903
7466
|
sessionId: null
|
|
@@ -6962,7 +7525,8 @@ var Opensteer = class _Opensteer {
|
|
|
6962
7525
|
}
|
|
6963
7526
|
this.remote = createRemoteRuntimeState(
|
|
6964
7527
|
apiKey,
|
|
6965
|
-
remoteConfig?.baseUrl
|
|
7528
|
+
remoteConfig?.baseUrl,
|
|
7529
|
+
remoteConfig?.authScheme
|
|
6966
7530
|
);
|
|
6967
7531
|
} else {
|
|
6968
7532
|
this.remote = null;
|
|
@@ -7418,7 +7982,7 @@ var Opensteer = class _Opensteer {
|
|
|
7418
7982
|
await handle.type(options.text);
|
|
7419
7983
|
}
|
|
7420
7984
|
if (options.pressEnter) {
|
|
7421
|
-
await handle.press("Enter");
|
|
7985
|
+
await handle.press("Enter", { noWaitAfter: true });
|
|
7422
7986
|
}
|
|
7423
7987
|
});
|
|
7424
7988
|
} catch (err) {
|