@opensteer/engine-playwright 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +433 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +433 -7
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -753,6 +753,19 @@ interface BrowserInstrumentation {
|
|
|
753
753
|
interface BrowserCoreEngine extends BrowserExecutor, BrowserInspector, SessionTransportExecutor, BrowserInstrumentation {
|
|
754
754
|
}
|
|
755
755
|
|
|
756
|
+
interface ActionBoundarySnapshot {
|
|
757
|
+
readonly pageRef: PageRef;
|
|
758
|
+
readonly documentRef: DocumentRef;
|
|
759
|
+
}
|
|
760
|
+
type ActionBoundarySettleTrigger = "dom-action" | "navigation";
|
|
761
|
+
type ActionBoundaryTimedOutPhase = "bootstrap";
|
|
762
|
+
interface ActionBoundaryOutcome {
|
|
763
|
+
readonly trigger: ActionBoundarySettleTrigger;
|
|
764
|
+
readonly crossDocument: boolean;
|
|
765
|
+
readonly bootstrapSettled: boolean;
|
|
766
|
+
readonly timedOutPhase?: ActionBoundaryTimedOutPhase;
|
|
767
|
+
}
|
|
768
|
+
|
|
756
769
|
declare const opensteerComputerAnnotationNames: readonly ["clickable", "typeable", "scrollable", "grid", "selected"];
|
|
757
770
|
type OpensteerComputerAnnotation = (typeof opensteerComputerAnnotationNames)[number];
|
|
758
771
|
type OpensteerComputerMouseButton = "left" | "middle" | "right";
|
|
@@ -814,11 +827,12 @@ interface NormalizedComputerScreenshotOptions {
|
|
|
814
827
|
}
|
|
815
828
|
interface ComputerUseBridgeInput {
|
|
816
829
|
readonly pageRef: PageRef;
|
|
830
|
+
readonly snapshot?: ActionBoundarySnapshot;
|
|
817
831
|
readonly action: OpensteerComputerAction;
|
|
818
832
|
readonly screenshot: NormalizedComputerScreenshotOptions;
|
|
819
833
|
readonly signal: AbortSignal;
|
|
820
834
|
remainingMs(): number | undefined;
|
|
821
|
-
policySettle(pageRef: PageRef): Promise<void>;
|
|
835
|
+
policySettle(pageRef: PageRef, trigger: ActionBoundarySettleTrigger): Promise<void>;
|
|
822
836
|
}
|
|
823
837
|
interface ComputerUseBridgeOutput {
|
|
824
838
|
readonly pageRef: PageRef;
|
|
@@ -826,6 +840,7 @@ interface ComputerUseBridgeOutput {
|
|
|
826
840
|
readonly viewport: ViewportMetrics;
|
|
827
841
|
readonly events: readonly StepEvent[];
|
|
828
842
|
readonly timing: OpensteerComputerExecuteTiming;
|
|
843
|
+
readonly boundary?: ActionBoundaryOutcome;
|
|
829
844
|
}
|
|
830
845
|
interface ComputerUseBridge {
|
|
831
846
|
execute(input: ComputerUseBridgeInput): Promise<ComputerUseBridgeOutput>;
|
|
@@ -886,9 +901,10 @@ interface DomActionKeyPressInput {
|
|
|
886
901
|
}
|
|
887
902
|
interface DomActionSettleOptions {
|
|
888
903
|
readonly operation: "dom.click" | "dom.hover" | "dom.input" | "dom.scroll";
|
|
904
|
+
readonly snapshot?: ActionBoundarySnapshot;
|
|
889
905
|
readonly signal: AbortSignal;
|
|
890
906
|
remainingMs(): number | undefined;
|
|
891
|
-
policySettle(pageRef: PageRef): Promise<void>;
|
|
907
|
+
policySettle(pageRef: PageRef, trigger: ActionBoundarySettleTrigger): Promise<void>;
|
|
892
908
|
}
|
|
893
909
|
type DomPointerHitRelation = "self" | "descendant" | "ancestor" | "same-owner" | "outside" | "unknown";
|
|
894
910
|
interface DomPointerHitAssessment {
|
|
@@ -910,7 +926,7 @@ interface DomActionBridge {
|
|
|
910
926
|
scrollNodeIntoView(locator: NodeLocator, options?: DomActionScrollOptions): Promise<void>;
|
|
911
927
|
focusNode(locator: NodeLocator): Promise<void>;
|
|
912
928
|
pressKey(locator: NodeLocator, input: DomActionKeyPressInput): Promise<void>;
|
|
913
|
-
finalizeDomAction(pageRef: PageRef, options: DomActionSettleOptions): Promise<
|
|
929
|
+
finalizeDomAction(pageRef: PageRef, options: DomActionSettleOptions): Promise<ActionBoundaryOutcome>;
|
|
914
930
|
}
|
|
915
931
|
|
|
916
932
|
interface PlaywrightChromiumLaunchOptions {
|
|
@@ -978,6 +994,7 @@ declare class PlaywrightBrowserCoreEngine implements BrowserCoreEngine {
|
|
|
978
994
|
private readonly pageByPlaywrightPage;
|
|
979
995
|
private readonly pendingPopupOpeners;
|
|
980
996
|
private readonly preassignedPopupPageRefs;
|
|
997
|
+
private readonly actionSettler;
|
|
981
998
|
private pageCounter;
|
|
982
999
|
private frameCounter;
|
|
983
1000
|
private documentCounter;
|
package/dist/index.d.ts
CHANGED
|
@@ -753,6 +753,19 @@ interface BrowserInstrumentation {
|
|
|
753
753
|
interface BrowserCoreEngine extends BrowserExecutor, BrowserInspector, SessionTransportExecutor, BrowserInstrumentation {
|
|
754
754
|
}
|
|
755
755
|
|
|
756
|
+
interface ActionBoundarySnapshot {
|
|
757
|
+
readonly pageRef: PageRef;
|
|
758
|
+
readonly documentRef: DocumentRef;
|
|
759
|
+
}
|
|
760
|
+
type ActionBoundarySettleTrigger = "dom-action" | "navigation";
|
|
761
|
+
type ActionBoundaryTimedOutPhase = "bootstrap";
|
|
762
|
+
interface ActionBoundaryOutcome {
|
|
763
|
+
readonly trigger: ActionBoundarySettleTrigger;
|
|
764
|
+
readonly crossDocument: boolean;
|
|
765
|
+
readonly bootstrapSettled: boolean;
|
|
766
|
+
readonly timedOutPhase?: ActionBoundaryTimedOutPhase;
|
|
767
|
+
}
|
|
768
|
+
|
|
756
769
|
declare const opensteerComputerAnnotationNames: readonly ["clickable", "typeable", "scrollable", "grid", "selected"];
|
|
757
770
|
type OpensteerComputerAnnotation = (typeof opensteerComputerAnnotationNames)[number];
|
|
758
771
|
type OpensteerComputerMouseButton = "left" | "middle" | "right";
|
|
@@ -814,11 +827,12 @@ interface NormalizedComputerScreenshotOptions {
|
|
|
814
827
|
}
|
|
815
828
|
interface ComputerUseBridgeInput {
|
|
816
829
|
readonly pageRef: PageRef;
|
|
830
|
+
readonly snapshot?: ActionBoundarySnapshot;
|
|
817
831
|
readonly action: OpensteerComputerAction;
|
|
818
832
|
readonly screenshot: NormalizedComputerScreenshotOptions;
|
|
819
833
|
readonly signal: AbortSignal;
|
|
820
834
|
remainingMs(): number | undefined;
|
|
821
|
-
policySettle(pageRef: PageRef): Promise<void>;
|
|
835
|
+
policySettle(pageRef: PageRef, trigger: ActionBoundarySettleTrigger): Promise<void>;
|
|
822
836
|
}
|
|
823
837
|
interface ComputerUseBridgeOutput {
|
|
824
838
|
readonly pageRef: PageRef;
|
|
@@ -826,6 +840,7 @@ interface ComputerUseBridgeOutput {
|
|
|
826
840
|
readonly viewport: ViewportMetrics;
|
|
827
841
|
readonly events: readonly StepEvent[];
|
|
828
842
|
readonly timing: OpensteerComputerExecuteTiming;
|
|
843
|
+
readonly boundary?: ActionBoundaryOutcome;
|
|
829
844
|
}
|
|
830
845
|
interface ComputerUseBridge {
|
|
831
846
|
execute(input: ComputerUseBridgeInput): Promise<ComputerUseBridgeOutput>;
|
|
@@ -886,9 +901,10 @@ interface DomActionKeyPressInput {
|
|
|
886
901
|
}
|
|
887
902
|
interface DomActionSettleOptions {
|
|
888
903
|
readonly operation: "dom.click" | "dom.hover" | "dom.input" | "dom.scroll";
|
|
904
|
+
readonly snapshot?: ActionBoundarySnapshot;
|
|
889
905
|
readonly signal: AbortSignal;
|
|
890
906
|
remainingMs(): number | undefined;
|
|
891
|
-
policySettle(pageRef: PageRef): Promise<void>;
|
|
907
|
+
policySettle(pageRef: PageRef, trigger: ActionBoundarySettleTrigger): Promise<void>;
|
|
892
908
|
}
|
|
893
909
|
type DomPointerHitRelation = "self" | "descendant" | "ancestor" | "same-owner" | "outside" | "unknown";
|
|
894
910
|
interface DomPointerHitAssessment {
|
|
@@ -910,7 +926,7 @@ interface DomActionBridge {
|
|
|
910
926
|
scrollNodeIntoView(locator: NodeLocator, options?: DomActionScrollOptions): Promise<void>;
|
|
911
927
|
focusNode(locator: NodeLocator): Promise<void>;
|
|
912
928
|
pressKey(locator: NodeLocator, input: DomActionKeyPressInput): Promise<void>;
|
|
913
|
-
finalizeDomAction(pageRef: PageRef, options: DomActionSettleOptions): Promise<
|
|
929
|
+
finalizeDomAction(pageRef: PageRef, options: DomActionSettleOptions): Promise<ActionBoundaryOutcome>;
|
|
914
930
|
}
|
|
915
931
|
|
|
916
932
|
interface PlaywrightChromiumLaunchOptions {
|
|
@@ -978,6 +994,7 @@ declare class PlaywrightBrowserCoreEngine implements BrowserCoreEngine {
|
|
|
978
994
|
private readonly pageByPlaywrightPage;
|
|
979
995
|
private readonly pendingPopupOpeners;
|
|
980
996
|
private readonly preassignedPopupPageRefs;
|
|
997
|
+
private readonly actionSettler;
|
|
981
998
|
private pageCounter;
|
|
982
999
|
private frameCounter;
|
|
983
1000
|
private documentCounter;
|
package/dist/index.js
CHANGED
|
@@ -1257,6 +1257,282 @@ function sleep(ms) {
|
|
|
1257
1257
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1258
1258
|
}
|
|
1259
1259
|
|
|
1260
|
+
// ../browser-core/src/post-load-tracker.ts
|
|
1261
|
+
var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
|
|
1262
|
+
var DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = 100;
|
|
1263
|
+
function isRecord(value) {
|
|
1264
|
+
return typeof value === "object" && value !== null;
|
|
1265
|
+
}
|
|
1266
|
+
function readFiniteNumber(value) {
|
|
1267
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1268
|
+
}
|
|
1269
|
+
function readNonNegativeNumber(value) {
|
|
1270
|
+
const parsed = readFiniteNumber(value);
|
|
1271
|
+
return parsed === void 0 || parsed < 0 ? 0 : parsed;
|
|
1272
|
+
}
|
|
1273
|
+
function normalizePostLoadTrackerState(value) {
|
|
1274
|
+
if (!isRecord(value)) {
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
const installedAt = readFiniteNumber(value.installedAt);
|
|
1278
|
+
const lastMutationAt = readFiniteNumber(value.lastMutationAt);
|
|
1279
|
+
const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
|
|
1280
|
+
const now = readFiniteNumber(value.now);
|
|
1281
|
+
const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
|
|
1282
|
+
if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
|
|
1283
|
+
return void 0;
|
|
1284
|
+
}
|
|
1285
|
+
return {
|
|
1286
|
+
installedAt,
|
|
1287
|
+
lastMutationAt,
|
|
1288
|
+
lastNetworkActivityAt,
|
|
1289
|
+
now,
|
|
1290
|
+
pendingFetches: readNonNegativeNumber(value.pendingFetches),
|
|
1291
|
+
pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
|
|
1292
|
+
pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
|
|
1293
|
+
readyState
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
function buildPostLoadTrackerInstallScript() {
|
|
1297
|
+
return `(() => {
|
|
1298
|
+
const globalObject = globalThis;
|
|
1299
|
+
if (globalObject.__opensteerActionBoundaryTrackerInstalled) {
|
|
1300
|
+
return true;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
const tracker = {
|
|
1304
|
+
installedAt: performance.now(),
|
|
1305
|
+
lastMutationAt: performance.now(),
|
|
1306
|
+
lastNetworkActivityAt: performance.now(),
|
|
1307
|
+
pendingFetches: 0,
|
|
1308
|
+
pendingTimeouts: 0,
|
|
1309
|
+
pendingXhrs: 0,
|
|
1310
|
+
readyState: document.readyState,
|
|
1311
|
+
timeoutIds: new Set(),
|
|
1312
|
+
};
|
|
1313
|
+
globalObject.__opensteerActionBoundaryTrackerInstalled = true;
|
|
1314
|
+
globalObject.__opensteerActionBoundaryTracker = tracker;
|
|
1315
|
+
|
|
1316
|
+
const markMutation = () => {
|
|
1317
|
+
tracker.lastMutationAt = performance.now();
|
|
1318
|
+
tracker.readyState = document.readyState;
|
|
1319
|
+
};
|
|
1320
|
+
const markNetwork = () => {
|
|
1321
|
+
tracker.lastNetworkActivityAt = performance.now();
|
|
1322
|
+
tracker.readyState = document.readyState;
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
const startObserver = () => {
|
|
1326
|
+
const target = document.documentElement ?? document;
|
|
1327
|
+
if (!(target instanceof Node)) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
const observer = new MutationObserver(markMutation);
|
|
1331
|
+
observer.observe(target, {
|
|
1332
|
+
subtree: true,
|
|
1333
|
+
childList: true,
|
|
1334
|
+
characterData: true,
|
|
1335
|
+
attributes: true,
|
|
1336
|
+
});
|
|
1337
|
+
markMutation();
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1340
|
+
if (document.documentElement) {
|
|
1341
|
+
startObserver();
|
|
1342
|
+
} else {
|
|
1343
|
+
document.addEventListener("DOMContentLoaded", startObserver, { once: true });
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
document.addEventListener("readystatechange", markMutation);
|
|
1347
|
+
addEventListener("load", markMutation, { once: true });
|
|
1348
|
+
|
|
1349
|
+
const nativeSetTimeout = globalObject.setTimeout.bind(globalObject);
|
|
1350
|
+
const nativeClearTimeout = globalObject.clearTimeout.bind(globalObject);
|
|
1351
|
+
globalObject.setTimeout = function(callback, delay, ...args) {
|
|
1352
|
+
tracker.pendingTimeouts += 1;
|
|
1353
|
+
markNetwork();
|
|
1354
|
+
let handle;
|
|
1355
|
+
const wrapped =
|
|
1356
|
+
typeof callback === "function"
|
|
1357
|
+
? (...callbackArgs) => {
|
|
1358
|
+
if (tracker.timeoutIds.delete(handle)) {
|
|
1359
|
+
tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
|
|
1360
|
+
}
|
|
1361
|
+
try {
|
|
1362
|
+
return callback(...callbackArgs);
|
|
1363
|
+
} finally {
|
|
1364
|
+
markMutation();
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
: callback;
|
|
1368
|
+
handle = nativeSetTimeout(wrapped, delay, ...args);
|
|
1369
|
+
tracker.timeoutIds.add(handle);
|
|
1370
|
+
return handle;
|
|
1371
|
+
};
|
|
1372
|
+
globalObject.clearTimeout = function(handle) {
|
|
1373
|
+
if (tracker.timeoutIds.delete(handle)) {
|
|
1374
|
+
tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
|
|
1375
|
+
}
|
|
1376
|
+
return nativeClearTimeout(handle);
|
|
1377
|
+
};
|
|
1378
|
+
|
|
1379
|
+
if (typeof globalObject.fetch === "function") {
|
|
1380
|
+
const nativeFetch = globalObject.fetch.bind(globalObject);
|
|
1381
|
+
globalObject.fetch = (...args) => {
|
|
1382
|
+
tracker.pendingFetches += 1;
|
|
1383
|
+
markNetwork();
|
|
1384
|
+
return nativeFetch(...args)
|
|
1385
|
+
.finally(() => {
|
|
1386
|
+
tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
|
|
1387
|
+
markNetwork();
|
|
1388
|
+
});
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (typeof globalObject.XMLHttpRequest === "function") {
|
|
1393
|
+
const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
|
|
1394
|
+
const nativeSend = NativeXMLHttpRequest.prototype.send;
|
|
1395
|
+
NativeXMLHttpRequest.prototype.send = function(...args) {
|
|
1396
|
+
tracker.pendingXhrs += 1;
|
|
1397
|
+
markNetwork();
|
|
1398
|
+
const finalize = () => {
|
|
1399
|
+
this.removeEventListener("loadend", finalize);
|
|
1400
|
+
tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
|
|
1401
|
+
markNetwork();
|
|
1402
|
+
};
|
|
1403
|
+
this.addEventListener("loadend", finalize, { once: true });
|
|
1404
|
+
return nativeSend.apply(this, args);
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
return true;
|
|
1409
|
+
})()`;
|
|
1410
|
+
}
|
|
1411
|
+
function buildPostLoadTrackerReadExpression() {
|
|
1412
|
+
return `(() => {
|
|
1413
|
+
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
1414
|
+
if (!tracker) {
|
|
1415
|
+
return null;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
return {
|
|
1419
|
+
installedAt: Number(tracker.installedAt ?? 0),
|
|
1420
|
+
lastMutationAt: Number(tracker.lastMutationAt ?? 0),
|
|
1421
|
+
lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
|
|
1422
|
+
now: Number(performance.now()),
|
|
1423
|
+
pendingFetches: Number(tracker.pendingFetches ?? 0),
|
|
1424
|
+
pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
|
|
1425
|
+
pendingXhrs: Number(tracker.pendingXhrs ?? 0),
|
|
1426
|
+
readyState: String(document.readyState),
|
|
1427
|
+
};
|
|
1428
|
+
})()`;
|
|
1429
|
+
}
|
|
1430
|
+
function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS) {
|
|
1431
|
+
if (!tracker) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
if (tracker.readyState !== "complete") {
|
|
1435
|
+
return false;
|
|
1436
|
+
}
|
|
1437
|
+
if (tracker.pendingFetches > 0 || tracker.pendingTimeouts > 0 || tracker.pendingXhrs > 0) {
|
|
1438
|
+
return false;
|
|
1439
|
+
}
|
|
1440
|
+
const lastActivityAt = Math.max(
|
|
1441
|
+
tracker.installedAt,
|
|
1442
|
+
tracker.lastMutationAt,
|
|
1443
|
+
tracker.lastNetworkActivityAt
|
|
1444
|
+
);
|
|
1445
|
+
return tracker.now - lastActivityAt >= quietWindowMs;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// ../browser-core/src/action-boundary.ts
|
|
1449
|
+
var CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = 3e4;
|
|
1450
|
+
var CROSS_DOCUMENT_DETECTION_WINDOW_MS = 500;
|
|
1451
|
+
async function waitForActionBoundary(input) {
|
|
1452
|
+
if (input.timeoutMs <= 0) {
|
|
1453
|
+
return {
|
|
1454
|
+
trigger: "dom-action",
|
|
1455
|
+
crossDocument: false,
|
|
1456
|
+
bootstrapSettled: false,
|
|
1457
|
+
timedOutPhase: "bootstrap"
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
const deadline = Date.now() + input.timeoutMs;
|
|
1461
|
+
const crossDocumentDetectionDeadline = input.snapshot === void 0 ? void 0 : Math.min(deadline, Date.now() + CROSS_DOCUMENT_DETECTION_WINDOW_MS);
|
|
1462
|
+
const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
|
|
1463
|
+
let trigger = "dom-action";
|
|
1464
|
+
let crossDocument = false;
|
|
1465
|
+
let waitedForNavigationContentLoaded = false;
|
|
1466
|
+
while (Date.now() < deadline) {
|
|
1467
|
+
input.throwBackgroundError();
|
|
1468
|
+
if (input.isPageClosed()) {
|
|
1469
|
+
return {
|
|
1470
|
+
trigger,
|
|
1471
|
+
crossDocument,
|
|
1472
|
+
bootstrapSettled: true
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
if (input.signal?.aborted) {
|
|
1476
|
+
if (isTimeoutAbort(input.signal.reason) && Date.now() >= deadline) {
|
|
1477
|
+
return {
|
|
1478
|
+
trigger,
|
|
1479
|
+
crossDocument,
|
|
1480
|
+
bootstrapSettled: false,
|
|
1481
|
+
timedOutPhase: "bootstrap"
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
throw abortError(input.signal);
|
|
1485
|
+
}
|
|
1486
|
+
const currentDocumentRef = input.getCurrentMainFrameDocumentRef();
|
|
1487
|
+
if (input.snapshot !== void 0 && currentDocumentRef !== void 0 && currentDocumentRef !== input.snapshot.documentRef) {
|
|
1488
|
+
trigger = "navigation";
|
|
1489
|
+
crossDocument = true;
|
|
1490
|
+
if (!waitedForNavigationContentLoaded) {
|
|
1491
|
+
waitedForNavigationContentLoaded = true;
|
|
1492
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
1493
|
+
if (remaining > 0) {
|
|
1494
|
+
await input.waitForNavigationContentLoaded(remaining);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
if (!crossDocument && crossDocumentDetectionDeadline !== void 0 && Date.now() >= crossDocumentDetectionDeadline) {
|
|
1499
|
+
return {
|
|
1500
|
+
trigger,
|
|
1501
|
+
crossDocument,
|
|
1502
|
+
bootstrapSettled: true
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
if (crossDocument && postLoadTrackerIsSettled(await input.readTrackerState())) {
|
|
1506
|
+
return {
|
|
1507
|
+
trigger,
|
|
1508
|
+
crossDocument,
|
|
1509
|
+
bootstrapSettled: true
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
|
|
1513
|
+
}
|
|
1514
|
+
return {
|
|
1515
|
+
trigger,
|
|
1516
|
+
crossDocument,
|
|
1517
|
+
bootstrapSettled: false,
|
|
1518
|
+
timedOutPhase: "bootstrap"
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
function abortError(signal) {
|
|
1522
|
+
return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
1523
|
+
}
|
|
1524
|
+
async function delay(ms) {
|
|
1525
|
+
if (ms <= 0) {
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
await new Promise((resolve) => {
|
|
1529
|
+
setTimeout(resolve, ms);
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
function isTimeoutAbort(reason) {
|
|
1533
|
+
return typeof reason === "object" && reason !== null && "code" in reason && reason.code === "timeout";
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1260
1536
|
// ../protocol/src/computer-use-bridge.ts
|
|
1261
1537
|
var OPENSTEER_COMPUTER_USE_BRIDGE_SYMBOL = /* @__PURE__ */ Symbol.for("@opensteer/computer-use-bridge");
|
|
1262
1538
|
|
|
@@ -1741,6 +2017,7 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1741
2017
|
const startedAt = Date.now();
|
|
1742
2018
|
const actionController = context.resolveController(input.pageRef);
|
|
1743
2019
|
const action = input.action;
|
|
2020
|
+
let boundary;
|
|
1744
2021
|
let actionMs = 0;
|
|
1745
2022
|
let waitMs = 0;
|
|
1746
2023
|
const actionStartedAt = Date.now();
|
|
@@ -1806,7 +2083,12 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1806
2083
|
await context.flushPendingPageTasks(actionController.sessionRef);
|
|
1807
2084
|
if (action.type !== "screenshot" && action.type !== "wait") {
|
|
1808
2085
|
const waitStartedAt = Date.now();
|
|
1809
|
-
await
|
|
2086
|
+
boundary = await context.settleActionBoundary(actionController, {
|
|
2087
|
+
signal: input.signal,
|
|
2088
|
+
...input.snapshot === void 0 ? {} : { snapshot: input.snapshot },
|
|
2089
|
+
remainingMs: input.remainingMs,
|
|
2090
|
+
policySettle: input.policySettle
|
|
2091
|
+
});
|
|
1810
2092
|
waitMs = Date.now() - waitStartedAt;
|
|
1811
2093
|
} else if (action.type === "wait") {
|
|
1812
2094
|
waitMs = actionMs;
|
|
@@ -1818,7 +2100,11 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1818
2100
|
let resultController = context.resolveController(resultPageRef);
|
|
1819
2101
|
if (action.type !== "screenshot" && action.type !== "wait" && resultController.pageRef !== actionController.pageRef) {
|
|
1820
2102
|
const popupWaitStartedAt = Date.now();
|
|
1821
|
-
await
|
|
2103
|
+
await context.settleActionBoundary(resultController, {
|
|
2104
|
+
signal: input.signal,
|
|
2105
|
+
remainingMs: input.remainingMs,
|
|
2106
|
+
policySettle: input.policySettle
|
|
2107
|
+
});
|
|
1822
2108
|
waitMs += Date.now() - popupWaitStartedAt;
|
|
1823
2109
|
await context.flushPendingPageTasks(actionController.sessionRef);
|
|
1824
2110
|
resultController = context.resolveController(resultController.pageRef);
|
|
@@ -1842,7 +2128,8 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1842
2128
|
actionMs,
|
|
1843
2129
|
waitMs,
|
|
1844
2130
|
totalMs: Date.now() - startedAt
|
|
1845
|
-
}
|
|
2131
|
+
},
|
|
2132
|
+
...boundary === void 0 ? {} : { boundary }
|
|
1846
2133
|
};
|
|
1847
2134
|
}
|
|
1848
2135
|
};
|
|
@@ -2875,10 +3162,12 @@ function createPlaywrightDomActionBridge(context) {
|
|
|
2875
3162
|
},
|
|
2876
3163
|
async finalizeDomAction(pageRef, options) {
|
|
2877
3164
|
const controller = context.resolveController(pageRef);
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
3165
|
+
return context.settleActionBoundary(controller, {
|
|
3166
|
+
signal: options.signal,
|
|
3167
|
+
...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
|
|
3168
|
+
remainingMs: options.remainingMs,
|
|
3169
|
+
policySettle: options.policySettle
|
|
3170
|
+
});
|
|
2882
3171
|
}
|
|
2883
3172
|
};
|
|
2884
3173
|
}
|
|
@@ -3146,6 +3435,121 @@ async function releaseObject(controller, objectId) {
|
|
|
3146
3435
|
await controller.cdp.send("Runtime.releaseObject", { objectId }).catch(() => void 0);
|
|
3147
3436
|
}
|
|
3148
3437
|
|
|
3438
|
+
// src/action-settle.ts
|
|
3439
|
+
var DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
|
|
3440
|
+
function clampPlaywrightActionSettleTimeout(timeoutMs) {
|
|
3441
|
+
if (timeoutMs === void 0) {
|
|
3442
|
+
return DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS;
|
|
3443
|
+
}
|
|
3444
|
+
return Math.max(0, Math.min(DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS, timeoutMs));
|
|
3445
|
+
}
|
|
3446
|
+
function createPlaywrightActionSettler(context) {
|
|
3447
|
+
const installScript = buildPostLoadTrackerInstallScript();
|
|
3448
|
+
const readExpression = buildPostLoadTrackerReadExpression();
|
|
3449
|
+
async function installTracker(controller) {
|
|
3450
|
+
if (!controller.settleTrackerRegistered) {
|
|
3451
|
+
await controller.page.addInitScript(installScript);
|
|
3452
|
+
controller.settleTrackerRegistered = true;
|
|
3453
|
+
}
|
|
3454
|
+
try {
|
|
3455
|
+
await controller.cdp.send("Runtime.evaluate", {
|
|
3456
|
+
expression: installScript,
|
|
3457
|
+
returnByValue: true,
|
|
3458
|
+
awaitPromise: true
|
|
3459
|
+
});
|
|
3460
|
+
} catch (error) {
|
|
3461
|
+
if (controller.lifecycleState === "closed" || isContextClosedError(error)) {
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3464
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
async function readTrackerState(controller) {
|
|
3468
|
+
try {
|
|
3469
|
+
const evaluated = await controller.cdp.send("Runtime.evaluate", {
|
|
3470
|
+
expression: readExpression,
|
|
3471
|
+
returnByValue: true,
|
|
3472
|
+
awaitPromise: true
|
|
3473
|
+
});
|
|
3474
|
+
return normalizePostLoadTrackerState(evaluated.result?.value);
|
|
3475
|
+
} catch (error) {
|
|
3476
|
+
if (isIgnorableTrackerReadError(error)) {
|
|
3477
|
+
return void 0;
|
|
3478
|
+
}
|
|
3479
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
async function settle(options) {
|
|
3483
|
+
const { controller, timeoutMs, signal, snapshot, policySettle } = options;
|
|
3484
|
+
if (timeoutMs <= 0) {
|
|
3485
|
+
return {
|
|
3486
|
+
trigger: "dom-action",
|
|
3487
|
+
crossDocument: false,
|
|
3488
|
+
bootstrapSettled: false,
|
|
3489
|
+
timedOutPhase: "bootstrap"
|
|
3490
|
+
};
|
|
3491
|
+
}
|
|
3492
|
+
await context.flushPendingPageTasks(controller.sessionRef);
|
|
3493
|
+
let boundary;
|
|
3494
|
+
if (snapshot === void 0) {
|
|
3495
|
+
if (policySettle) {
|
|
3496
|
+
if (signal?.aborted) {
|
|
3497
|
+
throw signal.reason ?? abortError2();
|
|
3498
|
+
}
|
|
3499
|
+
await policySettle(controller.pageRef, "dom-action");
|
|
3500
|
+
}
|
|
3501
|
+
boundary = {
|
|
3502
|
+
trigger: "dom-action",
|
|
3503
|
+
crossDocument: false,
|
|
3504
|
+
bootstrapSettled: true
|
|
3505
|
+
};
|
|
3506
|
+
} else {
|
|
3507
|
+
await installTracker(controller);
|
|
3508
|
+
boundary = await waitForActionBoundary({
|
|
3509
|
+
timeoutMs,
|
|
3510
|
+
...signal === void 0 ? {} : { signal },
|
|
3511
|
+
snapshot,
|
|
3512
|
+
getCurrentMainFrameDocumentRef: () => context.getMainFrameDocumentRef(controller),
|
|
3513
|
+
waitForNavigationContentLoaded: async (remainingMs) => {
|
|
3514
|
+
try {
|
|
3515
|
+
await controller.page.waitForLoadState("domcontentloaded", {
|
|
3516
|
+
timeout: remainingMs
|
|
3517
|
+
});
|
|
3518
|
+
} catch (error) {
|
|
3519
|
+
if (controller.lifecycleState === "closed" || isContextClosedError(error)) {
|
|
3520
|
+
return;
|
|
3521
|
+
}
|
|
3522
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3523
|
+
}
|
|
3524
|
+
},
|
|
3525
|
+
readTrackerState: () => readTrackerState(controller),
|
|
3526
|
+
throwBackgroundError: () => context.throwBackgroundError(controller),
|
|
3527
|
+
isPageClosed: () => controller.lifecycleState === "closed"
|
|
3528
|
+
});
|
|
3529
|
+
if (policySettle) {
|
|
3530
|
+
await policySettle(controller.pageRef, boundary.trigger);
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
await context.flushPendingPageTasks(controller.sessionRef);
|
|
3534
|
+
if (controller.lifecycleState !== "closed") {
|
|
3535
|
+
await context.flushDomUpdateTask(controller);
|
|
3536
|
+
}
|
|
3537
|
+
return boundary;
|
|
3538
|
+
}
|
|
3539
|
+
return {
|
|
3540
|
+
installTracker,
|
|
3541
|
+
settle
|
|
3542
|
+
};
|
|
3543
|
+
}
|
|
3544
|
+
function abortError2() {
|
|
3545
|
+
return new DOMException("The operation was aborted", "AbortError");
|
|
3546
|
+
}
|
|
3547
|
+
function isIgnorableTrackerReadError(error) {
|
|
3548
|
+
return isContextClosedError(error) || error instanceof Error && /Execution context was destroyed|Cannot find context|Inspected target navigated or closed/i.test(
|
|
3549
|
+
error.message
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3149
3553
|
// src/storage-capture.ts
|
|
3150
3554
|
var ACTIVATION_PATH = "/__opensteer_storage_capture__";
|
|
3151
3555
|
var ACTIVATION_TIMEOUT_MS = 15e3;
|
|
@@ -3352,6 +3756,12 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3352
3756
|
pageByPlaywrightPage = /* @__PURE__ */ new WeakMap();
|
|
3353
3757
|
pendingPopupOpeners = /* @__PURE__ */ new WeakMap();
|
|
3354
3758
|
preassignedPopupPageRefs = /* @__PURE__ */ new WeakMap();
|
|
3759
|
+
actionSettler = createPlaywrightActionSettler({
|
|
3760
|
+
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3761
|
+
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
3762
|
+
getMainFrameDocumentRef: (controller) => controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef)?.currentDocument.documentRef,
|
|
3763
|
+
throwBackgroundError: (controller) => this.throwBackgroundError(controller)
|
|
3764
|
+
});
|
|
3355
3765
|
pageCounter = 0;
|
|
3356
3766
|
frameCounter = 0;
|
|
3357
3767
|
documentCounter = 0;
|
|
@@ -3407,6 +3817,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3407
3817
|
resolveController: (pageRef) => this.requirePage(pageRef),
|
|
3408
3818
|
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3409
3819
|
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
3820
|
+
settleActionBoundary: (controller, options) => this.actionSettler.settle({
|
|
3821
|
+
controller,
|
|
3822
|
+
timeoutMs: clampPlaywrightActionSettleTimeout(options.remainingMs()),
|
|
3823
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
3824
|
+
...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
|
|
3825
|
+
...options.policySettle === void 0 ? {} : { policySettle: options.policySettle }
|
|
3826
|
+
}),
|
|
3410
3827
|
requireMainFrame: (controller) => this.requireMainFrame(controller),
|
|
3411
3828
|
drainQueuedEvents: (pageRef) => this.drainQueuedEvents(pageRef),
|
|
3412
3829
|
withModifiers: (page, modifiers, action) => this.withModifiers(page, modifiers, action)
|
|
@@ -3418,6 +3835,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3418
3835
|
resolveController: (pageRef) => this.requirePage(pageRef),
|
|
3419
3836
|
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3420
3837
|
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
3838
|
+
settleActionBoundary: (controller, options) => this.actionSettler.settle({
|
|
3839
|
+
controller,
|
|
3840
|
+
timeoutMs: clampPlaywrightActionSettleTimeout(options.remainingMs()),
|
|
3841
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
3842
|
+
...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
|
|
3843
|
+
...options.policySettle === void 0 ? {} : { policySettle: options.policySettle }
|
|
3844
|
+
}),
|
|
3421
3845
|
locateBackendNode: (document, backendNodeId) => createNodeLocator(
|
|
3422
3846
|
document.documentRef,
|
|
3423
3847
|
document.documentEpoch,
|
|
@@ -4512,6 +4936,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4512
4936
|
backgroundTasks: /* @__PURE__ */ new Set(),
|
|
4513
4937
|
domUpdateTask: void 0,
|
|
4514
4938
|
backgroundError: void 0,
|
|
4939
|
+
settleTrackerRegistered: false,
|
|
4515
4940
|
openerPageRef: void 0,
|
|
4516
4941
|
mainFrameRef: void 0,
|
|
4517
4942
|
lifecycleState: "open",
|
|
@@ -4528,6 +4953,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4528
4953
|
await cdp.send("DOM.enable", { includeWhitespace: "none" });
|
|
4529
4954
|
await cdp.send("DOMStorage.enable");
|
|
4530
4955
|
await cdp.send("DOM.getDocument", { depth: 0 });
|
|
4956
|
+
await this.actionSettler.installTracker(controller);
|
|
4531
4957
|
cdp.on(
|
|
4532
4958
|
"Page.frameAttached",
|
|
4533
4959
|
(payload) => this.runControllerEvent(
|