@opensteer/engine-playwright 0.8.1 → 0.8.3
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 +883 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -5
- package/dist/index.d.ts +59 -5
- package/dist/index.js +883 -29
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1259,6 +1259,355 @@ function sleep(ms) {
|
|
|
1259
1259
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1260
1260
|
}
|
|
1261
1261
|
|
|
1262
|
+
// ../browser-core/src/post-load-tracker.ts
|
|
1263
|
+
var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
|
|
1264
|
+
var DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = 100;
|
|
1265
|
+
function isRecord(value) {
|
|
1266
|
+
return typeof value === "object" && value !== null;
|
|
1267
|
+
}
|
|
1268
|
+
function readFiniteNumber(value) {
|
|
1269
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1270
|
+
}
|
|
1271
|
+
function readNonNegativeNumber(value) {
|
|
1272
|
+
const parsed = readFiniteNumber(value);
|
|
1273
|
+
return parsed === void 0 || parsed < 0 ? 0 : parsed;
|
|
1274
|
+
}
|
|
1275
|
+
function normalizePostLoadTrackerState(value) {
|
|
1276
|
+
if (!isRecord(value)) {
|
|
1277
|
+
return void 0;
|
|
1278
|
+
}
|
|
1279
|
+
const installedAt = readFiniteNumber(value.installedAt);
|
|
1280
|
+
const lastMutationAt = readFiniteNumber(value.lastMutationAt);
|
|
1281
|
+
const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
|
|
1282
|
+
const lastTrackedNetworkActivityAt = readFiniteNumber(value.lastTrackedNetworkActivityAt);
|
|
1283
|
+
const now = readFiniteNumber(value.now);
|
|
1284
|
+
const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
|
|
1285
|
+
if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || lastTrackedNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
|
|
1286
|
+
return void 0;
|
|
1287
|
+
}
|
|
1288
|
+
return {
|
|
1289
|
+
installedAt,
|
|
1290
|
+
lastMutationAt,
|
|
1291
|
+
lastNetworkActivityAt,
|
|
1292
|
+
lastTrackedNetworkActivityAt,
|
|
1293
|
+
now,
|
|
1294
|
+
pendingFetches: readNonNegativeNumber(value.pendingFetches),
|
|
1295
|
+
pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
|
|
1296
|
+
pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
|
|
1297
|
+
trackedPendingFetches: readNonNegativeNumber(value.trackedPendingFetches),
|
|
1298
|
+
trackedPendingXhrs: readNonNegativeNumber(value.trackedPendingXhrs),
|
|
1299
|
+
collecting: value.collecting === true,
|
|
1300
|
+
readyState
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
function buildPostLoadTrackerInstallScript() {
|
|
1304
|
+
return `(() => {
|
|
1305
|
+
const globalObject = globalThis;
|
|
1306
|
+
if (globalObject.__opensteerActionBoundaryTrackerInstalled) {
|
|
1307
|
+
return true;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
const tracker = {
|
|
1311
|
+
installedAt: performance.now(),
|
|
1312
|
+
lastMutationAt: performance.now(),
|
|
1313
|
+
lastNetworkActivityAt: performance.now(),
|
|
1314
|
+
lastTrackedNetworkActivityAt: performance.now(),
|
|
1315
|
+
pendingFetches: 0,
|
|
1316
|
+
pendingTimeouts: 0,
|
|
1317
|
+
pendingXhrs: 0,
|
|
1318
|
+
trackedPendingFetches: 0,
|
|
1319
|
+
trackedPendingXhrs: 0,
|
|
1320
|
+
collecting: true,
|
|
1321
|
+
readyState: document.readyState,
|
|
1322
|
+
};
|
|
1323
|
+
globalObject.__opensteerActionBoundaryTrackerInstalled = true;
|
|
1324
|
+
globalObject.__opensteerActionBoundaryTracker = tracker;
|
|
1325
|
+
|
|
1326
|
+
const markMutation = () => {
|
|
1327
|
+
tracker.lastMutationAt = performance.now();
|
|
1328
|
+
tracker.readyState = document.readyState;
|
|
1329
|
+
};
|
|
1330
|
+
const markNetwork = () => {
|
|
1331
|
+
tracker.lastNetworkActivityAt = performance.now();
|
|
1332
|
+
tracker.readyState = document.readyState;
|
|
1333
|
+
};
|
|
1334
|
+
const markTrackedNetwork = () => {
|
|
1335
|
+
tracker.lastTrackedNetworkActivityAt = performance.now();
|
|
1336
|
+
markNetwork();
|
|
1337
|
+
};
|
|
1338
|
+
const resetTracking = () => {
|
|
1339
|
+
const now = performance.now();
|
|
1340
|
+
tracker.lastTrackedNetworkActivityAt = now;
|
|
1341
|
+
tracker.trackedPendingFetches = 0;
|
|
1342
|
+
tracker.trackedPendingXhrs = 0;
|
|
1343
|
+
tracker.collecting = true;
|
|
1344
|
+
tracker.readyState = document.readyState;
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
const startObserver = () => {
|
|
1348
|
+
const target = document.documentElement ?? document;
|
|
1349
|
+
if (!(target instanceof Node)) {
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
const observer = new MutationObserver(markMutation);
|
|
1353
|
+
observer.observe(target, {
|
|
1354
|
+
subtree: true,
|
|
1355
|
+
childList: true,
|
|
1356
|
+
characterData: true,
|
|
1357
|
+
attributes: true,
|
|
1358
|
+
});
|
|
1359
|
+
markMutation();
|
|
1360
|
+
};
|
|
1361
|
+
|
|
1362
|
+
if (document.documentElement) {
|
|
1363
|
+
startObserver();
|
|
1364
|
+
} else {
|
|
1365
|
+
document.addEventListener("DOMContentLoaded", startObserver, { once: true });
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
document.addEventListener("readystatechange", markMutation);
|
|
1369
|
+
addEventListener("load", markMutation, { once: true });
|
|
1370
|
+
|
|
1371
|
+
if (typeof globalObject.fetch === "function") {
|
|
1372
|
+
const nativeFetch = globalObject.fetch.bind(globalObject);
|
|
1373
|
+
globalObject.fetch = (...args) => {
|
|
1374
|
+
const tracked = tracker.collecting === true;
|
|
1375
|
+
tracker.pendingFetches += 1;
|
|
1376
|
+
if (tracked) {
|
|
1377
|
+
tracker.trackedPendingFetches += 1;
|
|
1378
|
+
markTrackedNetwork();
|
|
1379
|
+
} else {
|
|
1380
|
+
markNetwork();
|
|
1381
|
+
}
|
|
1382
|
+
return nativeFetch(...args)
|
|
1383
|
+
.finally(() => {
|
|
1384
|
+
tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
|
|
1385
|
+
if (tracked) {
|
|
1386
|
+
tracker.trackedPendingFetches = Math.max(0, tracker.trackedPendingFetches - 1);
|
|
1387
|
+
markTrackedNetwork();
|
|
1388
|
+
} else {
|
|
1389
|
+
markNetwork();
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
if (typeof globalObject.XMLHttpRequest === "function") {
|
|
1396
|
+
const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
|
|
1397
|
+
const nativeSend = NativeXMLHttpRequest.prototype.send;
|
|
1398
|
+
NativeXMLHttpRequest.prototype.send = function(...args) {
|
|
1399
|
+
const tracked = tracker.collecting === true;
|
|
1400
|
+
tracker.pendingXhrs += 1;
|
|
1401
|
+
if (tracked) {
|
|
1402
|
+
tracker.trackedPendingXhrs += 1;
|
|
1403
|
+
markTrackedNetwork();
|
|
1404
|
+
} else {
|
|
1405
|
+
markNetwork();
|
|
1406
|
+
}
|
|
1407
|
+
const finalize = () => {
|
|
1408
|
+
this.removeEventListener("loadend", finalize);
|
|
1409
|
+
tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
|
|
1410
|
+
if (tracked) {
|
|
1411
|
+
tracker.trackedPendingXhrs = Math.max(0, tracker.trackedPendingXhrs - 1);
|
|
1412
|
+
markTrackedNetwork();
|
|
1413
|
+
} else {
|
|
1414
|
+
markNetwork();
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
this.addEventListener("loadend", finalize, { once: true });
|
|
1418
|
+
return nativeSend.apply(this, args);
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
tracker.beginObservation = () => {
|
|
1423
|
+
resetTracking();
|
|
1424
|
+
return true;
|
|
1425
|
+
};
|
|
1426
|
+
tracker.freezeObservation = () => {
|
|
1427
|
+
tracker.collecting = false;
|
|
1428
|
+
tracker.readyState = document.readyState;
|
|
1429
|
+
return true;
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
return true;
|
|
1433
|
+
})()`;
|
|
1434
|
+
}
|
|
1435
|
+
function buildPostLoadTrackerBeginExpression() {
|
|
1436
|
+
return `(() => {
|
|
1437
|
+
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
1438
|
+
if (!tracker || typeof tracker.beginObservation !== "function") {
|
|
1439
|
+
return false;
|
|
1440
|
+
}
|
|
1441
|
+
return tracker.beginObservation();
|
|
1442
|
+
})()`;
|
|
1443
|
+
}
|
|
1444
|
+
function buildPostLoadTrackerFreezeExpression() {
|
|
1445
|
+
return `(() => {
|
|
1446
|
+
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
1447
|
+
if (!tracker || typeof tracker.freezeObservation !== "function") {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
return tracker.freezeObservation();
|
|
1451
|
+
})()`;
|
|
1452
|
+
}
|
|
1453
|
+
function buildPostLoadTrackerReadExpression() {
|
|
1454
|
+
return `(() => {
|
|
1455
|
+
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
1456
|
+
if (!tracker) {
|
|
1457
|
+
return null;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
return {
|
|
1461
|
+
installedAt: Number(tracker.installedAt ?? 0),
|
|
1462
|
+
lastMutationAt: Number(tracker.lastMutationAt ?? 0),
|
|
1463
|
+
lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
|
|
1464
|
+
lastTrackedNetworkActivityAt: Number(tracker.lastTrackedNetworkActivityAt ?? 0),
|
|
1465
|
+
now: Number(performance.now()),
|
|
1466
|
+
pendingFetches: Number(tracker.pendingFetches ?? 0),
|
|
1467
|
+
pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
|
|
1468
|
+
pendingXhrs: Number(tracker.pendingXhrs ?? 0),
|
|
1469
|
+
trackedPendingFetches: Number(tracker.trackedPendingFetches ?? 0),
|
|
1470
|
+
trackedPendingXhrs: Number(tracker.trackedPendingXhrs ?? 0),
|
|
1471
|
+
collecting: tracker.collecting === true,
|
|
1472
|
+
readyState: String(document.readyState),
|
|
1473
|
+
};
|
|
1474
|
+
})()`;
|
|
1475
|
+
}
|
|
1476
|
+
function capturePostLoadTrackerSnapshot(tracker) {
|
|
1477
|
+
return {
|
|
1478
|
+
lastTrackedNetworkActivityAt: tracker.lastTrackedNetworkActivityAt,
|
|
1479
|
+
trackedPendingFetches: tracker.trackedPendingFetches,
|
|
1480
|
+
trackedPendingXhrs: tracker.trackedPendingXhrs
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function postLoadTrackerHasTrackedNetworkActivitySince(snapshot, tracker) {
|
|
1484
|
+
if (!tracker) {
|
|
1485
|
+
return false;
|
|
1486
|
+
}
|
|
1487
|
+
return tracker.trackedPendingFetches > snapshot.trackedPendingFetches || tracker.trackedPendingXhrs > snapshot.trackedPendingXhrs || tracker.lastTrackedNetworkActivityAt > snapshot.lastTrackedNetworkActivityAt;
|
|
1488
|
+
}
|
|
1489
|
+
function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS) {
|
|
1490
|
+
if (!tracker) {
|
|
1491
|
+
return false;
|
|
1492
|
+
}
|
|
1493
|
+
if (tracker.readyState !== "complete") {
|
|
1494
|
+
return false;
|
|
1495
|
+
}
|
|
1496
|
+
if (tracker.trackedPendingFetches > 0 || tracker.trackedPendingXhrs > 0) {
|
|
1497
|
+
return false;
|
|
1498
|
+
}
|
|
1499
|
+
const lastActivityAt = Math.max(
|
|
1500
|
+
tracker.installedAt,
|
|
1501
|
+
tracker.lastMutationAt,
|
|
1502
|
+
tracker.lastTrackedNetworkActivityAt
|
|
1503
|
+
);
|
|
1504
|
+
return tracker.now - lastActivityAt >= quietWindowMs;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// ../browser-core/src/action-boundary.ts
|
|
1508
|
+
var CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = 3e4;
|
|
1509
|
+
var CROSS_DOCUMENT_DETECTION_WINDOW_MS = 500;
|
|
1510
|
+
async function waitForActionBoundary(input) {
|
|
1511
|
+
if (input.timeoutMs <= 0) {
|
|
1512
|
+
return {
|
|
1513
|
+
trigger: "dom-action",
|
|
1514
|
+
crossDocument: false,
|
|
1515
|
+
bootstrapSettled: false,
|
|
1516
|
+
timedOutPhase: "bootstrap"
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
const deadline = Date.now() + input.timeoutMs;
|
|
1520
|
+
const crossDocumentDetectionDeadline = input.snapshot === void 0 ? void 0 : Math.min(deadline, Date.now() + CROSS_DOCUMENT_DETECTION_WINDOW_MS);
|
|
1521
|
+
const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
|
|
1522
|
+
let trigger = "dom-action";
|
|
1523
|
+
let crossDocument = false;
|
|
1524
|
+
let sameDocumentAsyncActivity = false;
|
|
1525
|
+
while (Date.now() < deadline) {
|
|
1526
|
+
input.throwBackgroundError();
|
|
1527
|
+
if (input.isPageClosed()) {
|
|
1528
|
+
return {
|
|
1529
|
+
trigger,
|
|
1530
|
+
crossDocument,
|
|
1531
|
+
bootstrapSettled: true
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
if (input.signal?.aborted) {
|
|
1535
|
+
if (isTimeoutAbort(input.signal.reason) && Date.now() >= deadline) {
|
|
1536
|
+
return {
|
|
1537
|
+
trigger,
|
|
1538
|
+
crossDocument,
|
|
1539
|
+
bootstrapSettled: false,
|
|
1540
|
+
timedOutPhase: "bootstrap"
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
throw abortError(input.signal);
|
|
1544
|
+
}
|
|
1545
|
+
const currentDocumentRef = input.getCurrentMainFrameDocumentRef();
|
|
1546
|
+
const currentPageUrl = input.getCurrentPageUrl?.();
|
|
1547
|
+
if (input.snapshot !== void 0 && currentDocumentRef !== void 0 && currentDocumentRef !== input.snapshot.documentRef) {
|
|
1548
|
+
trigger = "navigation";
|
|
1549
|
+
crossDocument = true;
|
|
1550
|
+
}
|
|
1551
|
+
if (!crossDocument && !sameDocumentAsyncActivity && input.snapshot?.tracker !== void 0 && postLoadTrackerHasTrackedNetworkActivitySince(
|
|
1552
|
+
input.snapshot.tracker,
|
|
1553
|
+
await input.readTrackerState()
|
|
1554
|
+
)) {
|
|
1555
|
+
trigger = "navigation";
|
|
1556
|
+
sameDocumentAsyncActivity = true;
|
|
1557
|
+
}
|
|
1558
|
+
if (!crossDocument && input.snapshot?.url !== void 0 && currentPageUrl !== void 0 && currentPageUrl !== input.snapshot.url && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
|
|
1559
|
+
trigger = "navigation";
|
|
1560
|
+
crossDocument = true;
|
|
1561
|
+
}
|
|
1562
|
+
if (!crossDocument && crossDocumentDetectionDeadline !== void 0 && Date.now() >= crossDocumentDetectionDeadline) {
|
|
1563
|
+
return {
|
|
1564
|
+
trigger,
|
|
1565
|
+
crossDocument,
|
|
1566
|
+
bootstrapSettled: true
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
if (sameDocumentAsyncActivity) {
|
|
1570
|
+
return {
|
|
1571
|
+
trigger,
|
|
1572
|
+
crossDocument,
|
|
1573
|
+
bootstrapSettled: true
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
if (crossDocument && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
|
|
1577
|
+
await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
if (crossDocument) {
|
|
1581
|
+
return {
|
|
1582
|
+
trigger,
|
|
1583
|
+
crossDocument,
|
|
1584
|
+
bootstrapSettled: true
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
|
|
1588
|
+
}
|
|
1589
|
+
return {
|
|
1590
|
+
trigger,
|
|
1591
|
+
crossDocument,
|
|
1592
|
+
bootstrapSettled: false,
|
|
1593
|
+
timedOutPhase: "bootstrap"
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
function abortError(signal) {
|
|
1597
|
+
return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
1598
|
+
}
|
|
1599
|
+
async function delay(ms) {
|
|
1600
|
+
if (ms <= 0) {
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
await new Promise((resolve) => {
|
|
1604
|
+
setTimeout(resolve, ms);
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
function isTimeoutAbort(reason) {
|
|
1608
|
+
return typeof reason === "object" && reason !== null && "code" in reason && reason.code === "timeout";
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1262
1611
|
// ../protocol/src/computer-use-bridge.ts
|
|
1263
1612
|
var OPENSTEER_COMPUTER_USE_BRIDGE_SYMBOL = /* @__PURE__ */ Symbol.for("@opensteer/computer-use-bridge");
|
|
1264
1613
|
|
|
@@ -1743,6 +2092,7 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1743
2092
|
const startedAt = Date.now();
|
|
1744
2093
|
const actionController = context.resolveController(input.pageRef);
|
|
1745
2094
|
const action = input.action;
|
|
2095
|
+
let boundary;
|
|
1746
2096
|
let actionMs = 0;
|
|
1747
2097
|
let waitMs = 0;
|
|
1748
2098
|
const actionStartedAt = Date.now();
|
|
@@ -1808,7 +2158,12 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1808
2158
|
await context.flushPendingPageTasks(actionController.sessionRef);
|
|
1809
2159
|
if (action.type !== "screenshot" && action.type !== "wait") {
|
|
1810
2160
|
const waitStartedAt = Date.now();
|
|
1811
|
-
await
|
|
2161
|
+
boundary = await context.settleActionBoundary(actionController, {
|
|
2162
|
+
signal: input.signal,
|
|
2163
|
+
...input.snapshot === void 0 ? {} : { snapshot: input.snapshot },
|
|
2164
|
+
remainingMs: input.remainingMs,
|
|
2165
|
+
policySettle: input.policySettle
|
|
2166
|
+
});
|
|
1812
2167
|
waitMs = Date.now() - waitStartedAt;
|
|
1813
2168
|
} else if (action.type === "wait") {
|
|
1814
2169
|
waitMs = actionMs;
|
|
@@ -1820,7 +2175,11 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1820
2175
|
let resultController = context.resolveController(resultPageRef);
|
|
1821
2176
|
if (action.type !== "screenshot" && action.type !== "wait" && resultController.pageRef !== actionController.pageRef) {
|
|
1822
2177
|
const popupWaitStartedAt = Date.now();
|
|
1823
|
-
await
|
|
2178
|
+
await context.settleActionBoundary(resultController, {
|
|
2179
|
+
signal: input.signal,
|
|
2180
|
+
remainingMs: input.remainingMs,
|
|
2181
|
+
policySettle: input.policySettle
|
|
2182
|
+
});
|
|
1824
2183
|
waitMs += Date.now() - popupWaitStartedAt;
|
|
1825
2184
|
await context.flushPendingPageTasks(actionController.sessionRef);
|
|
1826
2185
|
resultController = context.resolveController(resultController.pageRef);
|
|
@@ -1844,7 +2203,8 @@ function createPlaywrightComputerUseBridge(context) {
|
|
|
1844
2203
|
actionMs,
|
|
1845
2204
|
waitMs,
|
|
1846
2205
|
totalMs: Date.now() - startedAt
|
|
1847
|
-
}
|
|
2206
|
+
},
|
|
2207
|
+
...boundary === void 0 ? {} : { boundary }
|
|
1848
2208
|
};
|
|
1849
2209
|
}
|
|
1850
2210
|
};
|
|
@@ -2877,10 +3237,12 @@ function createPlaywrightDomActionBridge(context) {
|
|
|
2877
3237
|
},
|
|
2878
3238
|
async finalizeDomAction(pageRef, options) {
|
|
2879
3239
|
const controller = context.resolveController(pageRef);
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
3240
|
+
return context.settleActionBoundary(controller, {
|
|
3241
|
+
signal: options.signal,
|
|
3242
|
+
...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
|
|
3243
|
+
remainingMs: options.remainingMs,
|
|
3244
|
+
policySettle: options.policySettle
|
|
3245
|
+
});
|
|
2884
3246
|
}
|
|
2885
3247
|
};
|
|
2886
3248
|
}
|
|
@@ -3148,6 +3510,210 @@ async function releaseObject(controller, objectId) {
|
|
|
3148
3510
|
await controller.cdp.send("Runtime.releaseObject", { objectId }).catch(() => void 0);
|
|
3149
3511
|
}
|
|
3150
3512
|
|
|
3513
|
+
// src/action-settle.ts
|
|
3514
|
+
var DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
|
|
3515
|
+
var DEFAULT_PLAYWRIGHT_POST_LOAD_CAPTURE_WINDOW_MS = 1e3;
|
|
3516
|
+
function clampPlaywrightActionSettleTimeout(timeoutMs) {
|
|
3517
|
+
if (timeoutMs === void 0) {
|
|
3518
|
+
return DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS;
|
|
3519
|
+
}
|
|
3520
|
+
return Math.max(0, Math.min(DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS, timeoutMs));
|
|
3521
|
+
}
|
|
3522
|
+
function createPlaywrightActionSettler(context) {
|
|
3523
|
+
const installScript = buildPostLoadTrackerInstallScript();
|
|
3524
|
+
const beginExpression = buildPostLoadTrackerBeginExpression();
|
|
3525
|
+
const freezeExpression = buildPostLoadTrackerFreezeExpression();
|
|
3526
|
+
const readExpression = buildPostLoadTrackerReadExpression();
|
|
3527
|
+
async function installTracker(controller) {
|
|
3528
|
+
if (!controller.settleTrackerRegistered) {
|
|
3529
|
+
await controller.page.addInitScript(installScript);
|
|
3530
|
+
controller.settleTrackerRegistered = true;
|
|
3531
|
+
}
|
|
3532
|
+
try {
|
|
3533
|
+
await controller.cdp.send("Runtime.evaluate", {
|
|
3534
|
+
expression: installScript,
|
|
3535
|
+
returnByValue: true,
|
|
3536
|
+
awaitPromise: true
|
|
3537
|
+
});
|
|
3538
|
+
} catch (error) {
|
|
3539
|
+
if (controller.lifecycleState === "closed" || isContextClosedError(error)) {
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
async function readTrackerState(controller) {
|
|
3546
|
+
try {
|
|
3547
|
+
const evaluated = await controller.cdp.send("Runtime.evaluate", {
|
|
3548
|
+
expression: readExpression,
|
|
3549
|
+
returnByValue: true,
|
|
3550
|
+
awaitPromise: true
|
|
3551
|
+
});
|
|
3552
|
+
return normalizePostLoadTrackerState(evaluated.result?.value);
|
|
3553
|
+
} catch (error) {
|
|
3554
|
+
if (isIgnorableTrackerReadError(error)) {
|
|
3555
|
+
return void 0;
|
|
3556
|
+
}
|
|
3557
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
async function beginTrackerObservation(controller) {
|
|
3561
|
+
await installTracker(controller);
|
|
3562
|
+
try {
|
|
3563
|
+
await controller.cdp.send("Runtime.evaluate", {
|
|
3564
|
+
expression: beginExpression,
|
|
3565
|
+
returnByValue: true,
|
|
3566
|
+
awaitPromise: true
|
|
3567
|
+
});
|
|
3568
|
+
} catch (error) {
|
|
3569
|
+
if (isIgnorableTrackerReadError(error)) {
|
|
3570
|
+
return;
|
|
3571
|
+
}
|
|
3572
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
async function freezeTrackerObservation(controller) {
|
|
3576
|
+
try {
|
|
3577
|
+
await controller.cdp.send("Runtime.evaluate", {
|
|
3578
|
+
expression: freezeExpression,
|
|
3579
|
+
returnByValue: true,
|
|
3580
|
+
awaitPromise: true
|
|
3581
|
+
});
|
|
3582
|
+
} catch (error) {
|
|
3583
|
+
if (isIgnorableTrackerReadError(error)) {
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3586
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
async function captureSnapshot(controller) {
|
|
3590
|
+
const documentRef = context.getMainFrameDocumentRef(controller);
|
|
3591
|
+
if (documentRef === void 0) {
|
|
3592
|
+
throw new Error(`page ${controller.pageRef} does not expose a main frame`);
|
|
3593
|
+
}
|
|
3594
|
+
await beginTrackerObservation(controller);
|
|
3595
|
+
const tracker = await readTrackerState(controller);
|
|
3596
|
+
return {
|
|
3597
|
+
pageRef: controller.pageRef,
|
|
3598
|
+
documentRef,
|
|
3599
|
+
url: controller.page.url(),
|
|
3600
|
+
...tracker === void 0 ? {} : { tracker: capturePostLoadTrackerSnapshot(tracker) }
|
|
3601
|
+
};
|
|
3602
|
+
}
|
|
3603
|
+
async function waitForPostLoadQuiet(input) {
|
|
3604
|
+
const { controller, timeoutMs, signal } = input;
|
|
3605
|
+
if (timeoutMs <= 0) {
|
|
3606
|
+
return;
|
|
3607
|
+
}
|
|
3608
|
+
const quietMs = input.quietMs ?? DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS;
|
|
3609
|
+
const captureWindowMs = Math.max(
|
|
3610
|
+
0,
|
|
3611
|
+
Math.min(input.captureWindowMs ?? DEFAULT_PLAYWRIGHT_POST_LOAD_CAPTURE_WINDOW_MS, timeoutMs)
|
|
3612
|
+
);
|
|
3613
|
+
const deadline = Date.now() + timeoutMs;
|
|
3614
|
+
await installTracker(controller);
|
|
3615
|
+
if (captureWindowMs > 0) {
|
|
3616
|
+
await delayWithSignal2(captureWindowMs, signal, deadline);
|
|
3617
|
+
}
|
|
3618
|
+
await freezeTrackerObservation(controller);
|
|
3619
|
+
while (Date.now() < deadline) {
|
|
3620
|
+
if (signal?.aborted) {
|
|
3621
|
+
throw signal.reason ?? abortError2();
|
|
3622
|
+
}
|
|
3623
|
+
context.throwBackgroundError(controller);
|
|
3624
|
+
if (controller.lifecycleState === "closed") {
|
|
3625
|
+
return;
|
|
3626
|
+
}
|
|
3627
|
+
if (postLoadTrackerIsSettled(await readTrackerState(controller), quietMs)) {
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
await delayWithSignal2(100, signal, deadline);
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
async function settle(options) {
|
|
3634
|
+
const { controller, timeoutMs, signal, snapshot, policySettle } = options;
|
|
3635
|
+
if (timeoutMs <= 0) {
|
|
3636
|
+
return {
|
|
3637
|
+
trigger: "dom-action",
|
|
3638
|
+
crossDocument: false,
|
|
3639
|
+
bootstrapSettled: false,
|
|
3640
|
+
timedOutPhase: "bootstrap"
|
|
3641
|
+
};
|
|
3642
|
+
}
|
|
3643
|
+
await context.flushPendingPageTasks(controller.sessionRef);
|
|
3644
|
+
let boundary;
|
|
3645
|
+
if (snapshot === void 0) {
|
|
3646
|
+
if (policySettle) {
|
|
3647
|
+
if (signal?.aborted) {
|
|
3648
|
+
throw signal.reason ?? abortError2();
|
|
3649
|
+
}
|
|
3650
|
+
await policySettle(controller.pageRef, "dom-action");
|
|
3651
|
+
}
|
|
3652
|
+
boundary = {
|
|
3653
|
+
trigger: "dom-action",
|
|
3654
|
+
crossDocument: false,
|
|
3655
|
+
bootstrapSettled: true
|
|
3656
|
+
};
|
|
3657
|
+
} else {
|
|
3658
|
+
await installTracker(controller);
|
|
3659
|
+
boundary = await waitForActionBoundary({
|
|
3660
|
+
timeoutMs,
|
|
3661
|
+
...signal === void 0 ? {} : { signal },
|
|
3662
|
+
snapshot,
|
|
3663
|
+
getCurrentMainFrameDocumentRef: () => context.getMainFrameDocumentRef(controller),
|
|
3664
|
+
getCurrentPageUrl: () => controller.page.url(),
|
|
3665
|
+
isCurrentMainFrameBootstrapSettled: () => context.isCurrentMainFrameBootstrapSettled(controller),
|
|
3666
|
+
readTrackerState: () => readTrackerState(controller),
|
|
3667
|
+
throwBackgroundError: () => context.throwBackgroundError(controller),
|
|
3668
|
+
isPageClosed: () => controller.lifecycleState === "closed"
|
|
3669
|
+
});
|
|
3670
|
+
if (policySettle) {
|
|
3671
|
+
await policySettle(controller.pageRef, boundary.trigger);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
await context.flushPendingPageTasks(controller.sessionRef);
|
|
3675
|
+
if (controller.lifecycleState !== "closed") {
|
|
3676
|
+
await context.flushDomUpdateTask(controller);
|
|
3677
|
+
}
|
|
3678
|
+
return boundary;
|
|
3679
|
+
}
|
|
3680
|
+
return {
|
|
3681
|
+
captureSnapshot,
|
|
3682
|
+
installTracker,
|
|
3683
|
+
waitForPostLoadQuiet,
|
|
3684
|
+
settle
|
|
3685
|
+
};
|
|
3686
|
+
}
|
|
3687
|
+
function abortError2() {
|
|
3688
|
+
return new DOMException("The operation was aborted", "AbortError");
|
|
3689
|
+
}
|
|
3690
|
+
async function delayWithSignal2(delayMs, signal, deadline) {
|
|
3691
|
+
const effectiveDelay = Math.max(0, Math.min(delayMs, Math.max(0, deadline - Date.now())));
|
|
3692
|
+
if (effectiveDelay <= 0) {
|
|
3693
|
+
return;
|
|
3694
|
+
}
|
|
3695
|
+
if (signal?.aborted) {
|
|
3696
|
+
throw signal.reason ?? abortError2();
|
|
3697
|
+
}
|
|
3698
|
+
await new Promise((resolve, reject) => {
|
|
3699
|
+
const timer = setTimeout(() => {
|
|
3700
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3701
|
+
resolve();
|
|
3702
|
+
}, effectiveDelay);
|
|
3703
|
+
const onAbort = () => {
|
|
3704
|
+
clearTimeout(timer);
|
|
3705
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3706
|
+
reject(signal?.reason ?? abortError2());
|
|
3707
|
+
};
|
|
3708
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
function isIgnorableTrackerReadError(error) {
|
|
3712
|
+
return isContextClosedError(error) || error instanceof Error && /Execution context was destroyed|Cannot find context|Inspected target navigated or closed/i.test(
|
|
3713
|
+
error.message
|
|
3714
|
+
);
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3151
3717
|
// src/storage-capture.ts
|
|
3152
3718
|
var ACTIVATION_PATH = "/__opensteer_storage_capture__";
|
|
3153
3719
|
var ACTIVATION_TIMEOUT_MS = 15e3;
|
|
@@ -3339,6 +3905,71 @@ function cloneKeyPath(keyPath) {
|
|
|
3339
3905
|
}
|
|
3340
3906
|
|
|
3341
3907
|
// src/engine.ts
|
|
3908
|
+
var PLAYWRIGHT_RUNTIME_EVENT_RECORDER_SOURCE = String.raw`(() => {
|
|
3909
|
+
const key = "__opensteerRuntimeEventRecorder";
|
|
3910
|
+
const globalScope = globalThis;
|
|
3911
|
+
if (globalScope[key]?.installed === true) {
|
|
3912
|
+
return;
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3915
|
+
const queue = [];
|
|
3916
|
+
const limit = 500;
|
|
3917
|
+
const asString = (value) => {
|
|
3918
|
+
if (typeof value === "string") {
|
|
3919
|
+
return value;
|
|
3920
|
+
}
|
|
3921
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
3922
|
+
return String(value);
|
|
3923
|
+
}
|
|
3924
|
+
if (value === undefined) {
|
|
3925
|
+
return "undefined";
|
|
3926
|
+
}
|
|
3927
|
+
try {
|
|
3928
|
+
return JSON.stringify(value);
|
|
3929
|
+
} catch {
|
|
3930
|
+
return String(value);
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
const enqueue = (entry) => {
|
|
3934
|
+
queue.push({
|
|
3935
|
+
...entry,
|
|
3936
|
+
timestamp: Date.now(),
|
|
3937
|
+
});
|
|
3938
|
+
if (queue.length > limit) {
|
|
3939
|
+
queue.splice(0, queue.length - limit);
|
|
3940
|
+
}
|
|
3941
|
+
};
|
|
3942
|
+
|
|
3943
|
+
globalScope.addEventListener("error", (event) => {
|
|
3944
|
+
enqueue({
|
|
3945
|
+
kind: "page-error",
|
|
3946
|
+
message:
|
|
3947
|
+
typeof event.message === "string" && event.message.length > 0
|
|
3948
|
+
? event.message
|
|
3949
|
+
: event.error?.message || "Uncaught exception",
|
|
3950
|
+
stack: typeof event.error?.stack === "string" ? event.error.stack : undefined,
|
|
3951
|
+
});
|
|
3952
|
+
});
|
|
3953
|
+
|
|
3954
|
+
globalScope.addEventListener("unhandledrejection", (event) => {
|
|
3955
|
+
const reason = event.reason;
|
|
3956
|
+
enqueue({
|
|
3957
|
+
kind: "page-error",
|
|
3958
|
+
message:
|
|
3959
|
+
typeof reason?.message === "string" && reason.message.length > 0
|
|
3960
|
+
? reason.message
|
|
3961
|
+
: asString(reason),
|
|
3962
|
+
stack: typeof reason?.stack === "string" ? reason.stack : undefined,
|
|
3963
|
+
});
|
|
3964
|
+
});
|
|
3965
|
+
|
|
3966
|
+
globalScope[key] = {
|
|
3967
|
+
installed: true,
|
|
3968
|
+
drain() {
|
|
3969
|
+
return queue.splice(0, queue.length);
|
|
3970
|
+
},
|
|
3971
|
+
};
|
|
3972
|
+
})();`;
|
|
3342
3973
|
var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
3343
3974
|
capabilities = PLAYWRIGHT_BROWSER_CORE_CAPABILITIES;
|
|
3344
3975
|
browser;
|
|
@@ -3354,6 +3985,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3354
3985
|
pageByPlaywrightPage = /* @__PURE__ */ new WeakMap();
|
|
3355
3986
|
pendingPopupOpeners = /* @__PURE__ */ new WeakMap();
|
|
3356
3987
|
preassignedPopupPageRefs = /* @__PURE__ */ new WeakMap();
|
|
3988
|
+
actionSettler = createPlaywrightActionSettler({
|
|
3989
|
+
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3990
|
+
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
3991
|
+
getMainFrameDocumentRef: (controller) => controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef)?.currentDocument.documentRef,
|
|
3992
|
+
isCurrentMainFrameBootstrapSettled: (controller) => controller.mainFrameRef !== void 0 && this.frames.get(controller.mainFrameRef)?.currentDocument.domContentLoadedAt !== void 0,
|
|
3993
|
+
throwBackgroundError: (controller) => this.throwBackgroundError(controller)
|
|
3994
|
+
});
|
|
3357
3995
|
pageCounter = 0;
|
|
3358
3996
|
frameCounter = 0;
|
|
3359
3997
|
documentCounter = 0;
|
|
@@ -3409,6 +4047,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3409
4047
|
resolveController: (pageRef) => this.requirePage(pageRef),
|
|
3410
4048
|
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3411
4049
|
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
4050
|
+
settleActionBoundary: (controller, options) => this.actionSettler.settle({
|
|
4051
|
+
controller,
|
|
4052
|
+
timeoutMs: clampPlaywrightActionSettleTimeout(options.remainingMs()),
|
|
4053
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
4054
|
+
...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
|
|
4055
|
+
...options.policySettle === void 0 ? {} : { policySettle: options.policySettle }
|
|
4056
|
+
}),
|
|
3412
4057
|
requireMainFrame: (controller) => this.requireMainFrame(controller),
|
|
3413
4058
|
drainQueuedEvents: (pageRef) => this.drainQueuedEvents(pageRef),
|
|
3414
4059
|
withModifiers: (page, modifiers, action) => this.withModifiers(page, modifiers, action)
|
|
@@ -3420,6 +4065,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3420
4065
|
resolveController: (pageRef) => this.requirePage(pageRef),
|
|
3421
4066
|
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3422
4067
|
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
4068
|
+
settleActionBoundary: (controller, options) => this.actionSettler.settle({
|
|
4069
|
+
controller,
|
|
4070
|
+
timeoutMs: clampPlaywrightActionSettleTimeout(options.remainingMs()),
|
|
4071
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
4072
|
+
...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
|
|
4073
|
+
...options.policySettle === void 0 ? {} : { policySettle: options.policySettle }
|
|
4074
|
+
}),
|
|
3423
4075
|
locateBackendNode: (document, backendNodeId) => createNodeLocator(
|
|
3424
4076
|
document.documentRef,
|
|
3425
4077
|
document.documentEpoch,
|
|
@@ -3750,11 +4402,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3750
4402
|
});
|
|
3751
4403
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
3752
4404
|
const mainFrame = this.requireMainFrame(controller);
|
|
4405
|
+
const events = mergeDistinctStepEvents([
|
|
4406
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4407
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4408
|
+
]);
|
|
3753
4409
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
3754
4410
|
frameRef: mainFrame.frameRef,
|
|
3755
4411
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
3756
4412
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
3757
|
-
events
|
|
4413
|
+
events,
|
|
3758
4414
|
data: hit
|
|
3759
4415
|
});
|
|
3760
4416
|
}
|
|
@@ -3774,11 +4430,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3774
4430
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
3775
4431
|
await this.flushDomUpdateTask(controller);
|
|
3776
4432
|
const mainFrame = this.requireMainFrame(controller);
|
|
4433
|
+
const events = mergeDistinctStepEvents([
|
|
4434
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4435
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4436
|
+
]);
|
|
3777
4437
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
3778
4438
|
frameRef: mainFrame.frameRef,
|
|
3779
4439
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
3780
4440
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
3781
|
-
events
|
|
4441
|
+
events,
|
|
3782
4442
|
data: void 0
|
|
3783
4443
|
});
|
|
3784
4444
|
}
|
|
@@ -3790,11 +4450,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3790
4450
|
});
|
|
3791
4451
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
3792
4452
|
const mainFrame = this.requireMainFrame(controller);
|
|
4453
|
+
const events = mergeDistinctStepEvents([
|
|
4454
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4455
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4456
|
+
]);
|
|
3793
4457
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
3794
4458
|
frameRef: mainFrame.frameRef,
|
|
3795
4459
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
3796
4460
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
3797
|
-
events
|
|
4461
|
+
events,
|
|
3798
4462
|
data: void 0
|
|
3799
4463
|
});
|
|
3800
4464
|
}
|
|
@@ -3804,11 +4468,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3804
4468
|
await controller.page.keyboard.type(input.text);
|
|
3805
4469
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
3806
4470
|
const mainFrame = this.requireMainFrame(controller);
|
|
4471
|
+
const events = mergeDistinctStepEvents([
|
|
4472
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4473
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4474
|
+
]);
|
|
3807
4475
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
3808
4476
|
frameRef: mainFrame.frameRef,
|
|
3809
4477
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
3810
4478
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
3811
|
-
events
|
|
4479
|
+
events,
|
|
3812
4480
|
data: void 0
|
|
3813
4481
|
});
|
|
3814
4482
|
}
|
|
@@ -3946,6 +4614,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3946
4614
|
}
|
|
3947
4615
|
return infos;
|
|
3948
4616
|
}
|
|
4617
|
+
async drainEvents(input) {
|
|
4618
|
+
const controller = this.requirePage(input.pageRef);
|
|
4619
|
+
return mergeDistinctStepEvents([
|
|
4620
|
+
...this.drainQueuedEvents(input.pageRef),
|
|
4621
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4622
|
+
]);
|
|
4623
|
+
}
|
|
3949
4624
|
async listFrames(input) {
|
|
3950
4625
|
const controller = this.requirePage(input.pageRef);
|
|
3951
4626
|
await this.flushDomUpdateTask(controller);
|
|
@@ -3997,6 +4672,12 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3997
4672
|
(contentDocIndex) => resolveCapturedContentDocumentRef(controller.framesByCdpId, captured, contentDocIndex)
|
|
3998
4673
|
);
|
|
3999
4674
|
}
|
|
4675
|
+
async getActionBoundarySnapshot(input) {
|
|
4676
|
+
const controller = this.requirePage(input.pageRef);
|
|
4677
|
+
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4678
|
+
await this.flushDomUpdateTask(controller);
|
|
4679
|
+
return this.actionSettler.captureSnapshot(controller);
|
|
4680
|
+
}
|
|
4000
4681
|
async waitForVisualStability(input) {
|
|
4001
4682
|
const controller = this.requirePage(input.pageRef);
|
|
4002
4683
|
await this.flushDomUpdateTask(controller);
|
|
@@ -4007,6 +4688,21 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4007
4688
|
});
|
|
4008
4689
|
await this.flushDomUpdateTask(controller);
|
|
4009
4690
|
}
|
|
4691
|
+
async waitForPostLoadQuiet(input) {
|
|
4692
|
+
const controller = this.requirePage(input.pageRef);
|
|
4693
|
+
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4694
|
+
await this.actionSettler.waitForPostLoadQuiet({
|
|
4695
|
+
controller,
|
|
4696
|
+
timeoutMs: clampPlaywrightActionSettleTimeout(input.timeoutMs),
|
|
4697
|
+
...input.quietMs === void 0 ? {} : { quietMs: input.quietMs },
|
|
4698
|
+
...input.captureWindowMs === void 0 ? {} : { captureWindowMs: input.captureWindowMs },
|
|
4699
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
4700
|
+
});
|
|
4701
|
+
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4702
|
+
if (controller.lifecycleState !== "closed") {
|
|
4703
|
+
await this.flushDomUpdateTask(controller);
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4010
4706
|
async readText(input) {
|
|
4011
4707
|
const document = this.requireDocument(input.documentRef);
|
|
4012
4708
|
const controller = this.requirePage(document.pageRef);
|
|
@@ -4514,6 +5210,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4514
5210
|
backgroundTasks: /* @__PURE__ */ new Set(),
|
|
4515
5211
|
domUpdateTask: void 0,
|
|
4516
5212
|
backgroundError: void 0,
|
|
5213
|
+
settleTrackerRegistered: false,
|
|
4517
5214
|
openerPageRef: void 0,
|
|
4518
5215
|
mainFrameRef: void 0,
|
|
4519
5216
|
lifecycleState: "open",
|
|
@@ -4527,9 +5224,12 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4527
5224
|
session.activePageRef = pageRef;
|
|
4528
5225
|
await cdp.send("Page.enable", { enableFileChooserOpenedEvent: true });
|
|
4529
5226
|
await cdp.send("Network.enable");
|
|
5227
|
+
await cdp.send("Runtime.enable");
|
|
4530
5228
|
await cdp.send("DOM.enable", { includeWhitespace: "none" });
|
|
4531
5229
|
await cdp.send("DOMStorage.enable");
|
|
4532
5230
|
await cdp.send("DOM.getDocument", { depth: 0 });
|
|
5231
|
+
await this.installRuntimeEventRecorder(page);
|
|
5232
|
+
await this.actionSettler.installTracker(controller);
|
|
4533
5233
|
cdp.on(
|
|
4534
5234
|
"Page.frameAttached",
|
|
4535
5235
|
(payload) => this.runControllerEvent(
|
|
@@ -4604,9 +5304,19 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4604
5304
|
"DOM.documentUpdated",
|
|
4605
5305
|
() => this.runControllerEvent(controller, () => this.handleDocumentUpdated(controller))
|
|
4606
5306
|
);
|
|
4607
|
-
|
|
4608
|
-
"
|
|
4609
|
-
(
|
|
5307
|
+
cdp.on(
|
|
5308
|
+
"Runtime.consoleAPICalled",
|
|
5309
|
+
(payload) => this.runControllerEvent(
|
|
5310
|
+
controller,
|
|
5311
|
+
() => this.handleRuntimeConsole(controller, payload)
|
|
5312
|
+
)
|
|
5313
|
+
);
|
|
5314
|
+
cdp.on(
|
|
5315
|
+
"Runtime.exceptionThrown",
|
|
5316
|
+
(payload) => this.runControllerEvent(
|
|
5317
|
+
controller,
|
|
5318
|
+
() => this.handleRuntimeException(controller, payload)
|
|
5319
|
+
)
|
|
4610
5320
|
);
|
|
4611
5321
|
page.on(
|
|
4612
5322
|
"popup",
|
|
@@ -4633,10 +5343,6 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4633
5343
|
"download",
|
|
4634
5344
|
(download) => this.runControllerEvent(controller, () => this.handleDownload(controller, download))
|
|
4635
5345
|
);
|
|
4636
|
-
page.on(
|
|
4637
|
-
"pageerror",
|
|
4638
|
-
(error) => this.runControllerEvent(controller, () => this.handlePageError(controller, error))
|
|
4639
|
-
);
|
|
4640
5346
|
page.on(
|
|
4641
5347
|
"request",
|
|
4642
5348
|
(request) => this.runControllerEvent(controller, () => this.handlePlaywrightRequest(controller, request))
|
|
@@ -4648,6 +5354,10 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4648
5354
|
() => this.handlePlaywrightResponse(controller, response)
|
|
4649
5355
|
)
|
|
4650
5356
|
);
|
|
5357
|
+
page.on(
|
|
5358
|
+
"domcontentloaded",
|
|
5359
|
+
() => this.runControllerEvent(controller, () => this.handlePageDomContentLoaded(controller))
|
|
5360
|
+
);
|
|
4651
5361
|
page.on("close", () => this.handleUnexpectedPageClose(controller));
|
|
4652
5362
|
const frameTree = await cdp.send("Page.getFrameTree");
|
|
4653
5363
|
this.syncFrameTree(controller, frameTree.frameTree);
|
|
@@ -4700,6 +5410,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4700
5410
|
documentRef,
|
|
4701
5411
|
documentEpoch: createDocumentEpoch(0),
|
|
4702
5412
|
url: "about:blank",
|
|
5413
|
+
domContentLoadedAt: void 0,
|
|
4703
5414
|
parentDocumentRef: parent?.currentDocument.documentRef,
|
|
4704
5415
|
nodeRefsByBackendNodeId: /* @__PURE__ */ new Map(),
|
|
4705
5416
|
backendNodeIdsByNodeRef: /* @__PURE__ */ new Map(),
|
|
@@ -4758,6 +5469,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4758
5469
|
documentRef: nextDocumentRef,
|
|
4759
5470
|
documentEpoch: createDocumentEpoch(0),
|
|
4760
5471
|
url: combineFrameUrl(frame.url, frame.urlFragment),
|
|
5472
|
+
domContentLoadedAt: void 0,
|
|
4761
5473
|
parentDocumentRef: parent?.currentDocument.documentRef,
|
|
4762
5474
|
nodeRefsByBackendNodeId: /* @__PURE__ */ new Map(),
|
|
4763
5475
|
backendNodeIdsByNodeRef: /* @__PURE__ */ new Map(),
|
|
@@ -4787,6 +5499,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4787
5499
|
handleDocumentUpdated(controller) {
|
|
4788
5500
|
this.queueDocumentReconciliation(controller);
|
|
4789
5501
|
}
|
|
5502
|
+
handlePageDomContentLoaded(controller) {
|
|
5503
|
+
const mainFrame = controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef);
|
|
5504
|
+
if (mainFrame === void 0) {
|
|
5505
|
+
return;
|
|
5506
|
+
}
|
|
5507
|
+
mainFrame.currentDocument.domContentLoadedAt = Date.now();
|
|
5508
|
+
}
|
|
4790
5509
|
syncFrameTree(controller, tree) {
|
|
4791
5510
|
const visit = (node, parentFrameRef) => {
|
|
4792
5511
|
const existing = controller.framesByCdpId.get(node.frame.id);
|
|
@@ -4800,6 +5519,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4800
5519
|
documentRef,
|
|
4801
5520
|
documentEpoch: createDocumentEpoch(0),
|
|
4802
5521
|
url: combineFrameUrl(node.frame.url, node.frame.urlFragment),
|
|
5522
|
+
domContentLoadedAt: void 0,
|
|
4803
5523
|
parentDocumentRef: parentFrameRef === void 0 ? void 0 : this.requireFrame(parentFrameRef).currentDocument.documentRef,
|
|
4804
5524
|
nodeRefsByBackendNodeId: /* @__PURE__ */ new Map(),
|
|
4805
5525
|
backendNodeIdsByNodeRef: /* @__PURE__ */ new Map(),
|
|
@@ -4858,19 +5578,20 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4858
5578
|
}
|
|
4859
5579
|
}
|
|
4860
5580
|
}
|
|
4861
|
-
|
|
5581
|
+
handleRuntimeConsole(controller, payload) {
|
|
5582
|
+
const callFrame = payload.stackTrace?.callFrames?.[0];
|
|
4862
5583
|
this.queueEvent(
|
|
4863
5584
|
controller.pageRef,
|
|
4864
5585
|
this.createEvent({
|
|
4865
5586
|
kind: "console",
|
|
4866
5587
|
sessionRef: controller.sessionRef,
|
|
4867
5588
|
pageRef: controller.pageRef,
|
|
4868
|
-
level:
|
|
4869
|
-
text:
|
|
5589
|
+
level: normalizeRuntimeConsoleLevel(payload.type),
|
|
5590
|
+
text: formatRuntimeConsoleText(payload),
|
|
4870
5591
|
location: {
|
|
4871
|
-
url:
|
|
4872
|
-
lineNumber:
|
|
4873
|
-
columnNumber:
|
|
5592
|
+
url: callFrame?.url ?? "",
|
|
5593
|
+
lineNumber: callFrame?.lineNumber ?? 0,
|
|
5594
|
+
columnNumber: callFrame?.columnNumber ?? 0
|
|
4874
5595
|
}
|
|
4875
5596
|
})
|
|
4876
5597
|
);
|
|
@@ -4951,15 +5672,18 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4951
5672
|
})
|
|
4952
5673
|
);
|
|
4953
5674
|
}
|
|
4954
|
-
|
|
5675
|
+
handleRuntimeException(controller, payload) {
|
|
5676
|
+
const details = payload.exceptionDetails;
|
|
5677
|
+
const message = formatRuntimeExceptionMessage(details);
|
|
5678
|
+
const stack = formatRuntimeExceptionStack(details);
|
|
4955
5679
|
this.queueEvent(
|
|
4956
5680
|
controller.pageRef,
|
|
4957
5681
|
this.createEvent({
|
|
4958
5682
|
kind: "page-error",
|
|
4959
5683
|
sessionRef: controller.sessionRef,
|
|
4960
5684
|
pageRef: controller.pageRef,
|
|
4961
|
-
message
|
|
4962
|
-
...
|
|
5685
|
+
message,
|
|
5686
|
+
...stack === void 0 ? {} : { stack }
|
|
4963
5687
|
})
|
|
4964
5688
|
);
|
|
4965
5689
|
}
|
|
@@ -5681,10 +6405,11 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5681
6405
|
}
|
|
5682
6406
|
}
|
|
5683
6407
|
createEvent(value) {
|
|
6408
|
+
const { timestamp, ...event } = value;
|
|
5684
6409
|
return {
|
|
5685
|
-
...
|
|
6410
|
+
...event,
|
|
5686
6411
|
eventId: `event:${++this.eventCounter}`,
|
|
5687
|
-
timestamp: Date.now()
|
|
6412
|
+
timestamp: timestamp ?? Date.now()
|
|
5688
6413
|
};
|
|
5689
6414
|
}
|
|
5690
6415
|
queueEvent(pageRef, event) {
|
|
@@ -5694,6 +6419,37 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5694
6419
|
}
|
|
5695
6420
|
controller.queuedEvents.push(event);
|
|
5696
6421
|
}
|
|
6422
|
+
async installRuntimeEventRecorder(page) {
|
|
6423
|
+
await page.addInitScript({
|
|
6424
|
+
content: PLAYWRIGHT_RUNTIME_EVENT_RECORDER_SOURCE
|
|
6425
|
+
});
|
|
6426
|
+
await page.evaluate(PLAYWRIGHT_RUNTIME_EVENT_RECORDER_SOURCE).catch(() => void 0);
|
|
6427
|
+
}
|
|
6428
|
+
async drainInstrumentedRuntimeEvents(controller) {
|
|
6429
|
+
const recorded = await Promise.all(
|
|
6430
|
+
controller.page.frames().map(async (frame) => {
|
|
6431
|
+
const events = await frame.evaluate(() => {
|
|
6432
|
+
const recorder = globalThis.__opensteerRuntimeEventRecorder;
|
|
6433
|
+
return recorder?.drain?.() ?? [];
|
|
6434
|
+
}).catch(() => []);
|
|
6435
|
+
return events;
|
|
6436
|
+
})
|
|
6437
|
+
);
|
|
6438
|
+
return mergeDistinctStepEvents(
|
|
6439
|
+
recorded.flatMap(
|
|
6440
|
+
(events) => events.map(
|
|
6441
|
+
(event) => this.createEvent({
|
|
6442
|
+
kind: "page-error",
|
|
6443
|
+
sessionRef: controller.sessionRef,
|
|
6444
|
+
pageRef: controller.pageRef,
|
|
6445
|
+
message: event.message ?? "Uncaught exception",
|
|
6446
|
+
...event.stack === void 0 ? {} : { stack: event.stack },
|
|
6447
|
+
timestamp: event.timestamp
|
|
6448
|
+
})
|
|
6449
|
+
)
|
|
6450
|
+
)
|
|
6451
|
+
);
|
|
6452
|
+
}
|
|
5697
6453
|
drainQueuedEvents(pageRef) {
|
|
5698
6454
|
const controller = this.requirePage(pageRef);
|
|
5699
6455
|
const events = controller.queuedEvents.splice(0, controller.queuedEvents.length);
|
|
@@ -5940,6 +6696,104 @@ function withTimeout(promise, timeoutMs) {
|
|
|
5940
6696
|
})
|
|
5941
6697
|
]);
|
|
5942
6698
|
}
|
|
6699
|
+
function formatRuntimeConsoleText(payload) {
|
|
6700
|
+
const parts = (payload.args ?? []).map((arg) => formatRuntimeRemoteObject(arg)).filter((value) => value.length > 0);
|
|
6701
|
+
if (parts.length > 0) {
|
|
6702
|
+
return parts.join(" ");
|
|
6703
|
+
}
|
|
6704
|
+
return payload.type?.trim() || "console";
|
|
6705
|
+
}
|
|
6706
|
+
function normalizeRuntimeConsoleLevel(value) {
|
|
6707
|
+
switch (value) {
|
|
6708
|
+
case "warning":
|
|
6709
|
+
case "debug":
|
|
6710
|
+
case "info":
|
|
6711
|
+
case "error":
|
|
6712
|
+
case "trace":
|
|
6713
|
+
return normalizeConsoleLevel(value);
|
|
6714
|
+
default:
|
|
6715
|
+
return "log";
|
|
6716
|
+
}
|
|
6717
|
+
}
|
|
6718
|
+
function formatRuntimeExceptionMessage(details) {
|
|
6719
|
+
const description = details?.exception?.description?.trim();
|
|
6720
|
+
if (description) {
|
|
6721
|
+
const firstLine = description.split("\n")[0]?.trim() ?? "";
|
|
6722
|
+
if (firstLine.startsWith("Error: ")) {
|
|
6723
|
+
return firstLine.slice("Error: ".length);
|
|
6724
|
+
}
|
|
6725
|
+
return firstLine || description;
|
|
6726
|
+
}
|
|
6727
|
+
const value = details?.exception?.value;
|
|
6728
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
6729
|
+
return value.trim();
|
|
6730
|
+
}
|
|
6731
|
+
return details?.text?.trim() || "Uncaught exception";
|
|
6732
|
+
}
|
|
6733
|
+
function formatRuntimeExceptionStack(details) {
|
|
6734
|
+
const description = details?.exception?.description?.trim();
|
|
6735
|
+
if (description && description.includes("\n")) {
|
|
6736
|
+
return description;
|
|
6737
|
+
}
|
|
6738
|
+
const frames = details?.stackTrace?.callFrames;
|
|
6739
|
+
if (!frames || frames.length === 0) {
|
|
6740
|
+
return void 0;
|
|
6741
|
+
}
|
|
6742
|
+
return frames.map((frame) => {
|
|
6743
|
+
const url = frame.url ?? "<anonymous>";
|
|
6744
|
+
const lineNumber = frame.lineNumber ?? 0;
|
|
6745
|
+
const columnNumber = frame.columnNumber ?? 0;
|
|
6746
|
+
return ` at ${url}:${lineNumber}:${columnNumber}`;
|
|
6747
|
+
}).join("\n");
|
|
6748
|
+
}
|
|
6749
|
+
function formatRuntimeRemoteObject(object) {
|
|
6750
|
+
if (object.unserializableValue !== void 0) {
|
|
6751
|
+
return object.unserializableValue;
|
|
6752
|
+
}
|
|
6753
|
+
if (object.value !== void 0) {
|
|
6754
|
+
return typeof object.value === "string" ? object.value : JSON.stringify(object.value);
|
|
6755
|
+
}
|
|
6756
|
+
if (object.description !== void 0 && object.description.length > 0) {
|
|
6757
|
+
return object.description;
|
|
6758
|
+
}
|
|
6759
|
+
const previewParts = object.preview?.properties?.map((property) => {
|
|
6760
|
+
if (!property.name) {
|
|
6761
|
+
return "";
|
|
6762
|
+
}
|
|
6763
|
+
return property.value === void 0 ? property.name : `${property.name}: ${property.value}`;
|
|
6764
|
+
}).filter((value) => value.length > 0) ?? [];
|
|
6765
|
+
return previewParts.join(", ");
|
|
6766
|
+
}
|
|
6767
|
+
function mergeDistinctStepEvents(events) {
|
|
6768
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6769
|
+
const merged = [];
|
|
6770
|
+
for (const event of events) {
|
|
6771
|
+
const fingerprint = stepEventFingerprint(event);
|
|
6772
|
+
if (seen.has(fingerprint)) {
|
|
6773
|
+
continue;
|
|
6774
|
+
}
|
|
6775
|
+
seen.add(fingerprint);
|
|
6776
|
+
merged.push(event);
|
|
6777
|
+
}
|
|
6778
|
+
return merged;
|
|
6779
|
+
}
|
|
6780
|
+
function stepEventFingerprint(event) {
|
|
6781
|
+
switch (event.kind) {
|
|
6782
|
+
case "console":
|
|
6783
|
+
return [
|
|
6784
|
+
event.kind,
|
|
6785
|
+
event.level,
|
|
6786
|
+
event.text,
|
|
6787
|
+
event.location?.url ?? "",
|
|
6788
|
+
event.location?.lineNumber ?? "",
|
|
6789
|
+
event.location?.columnNumber ?? ""
|
|
6790
|
+
].join("|");
|
|
6791
|
+
case "page-error":
|
|
6792
|
+
return [event.kind, event.message, event.stack ?? ""].join("|");
|
|
6793
|
+
default:
|
|
6794
|
+
return event.eventId;
|
|
6795
|
+
}
|
|
6796
|
+
}
|
|
5943
6797
|
|
|
5944
6798
|
exports.PlaywrightBrowserCoreEngine = PlaywrightBrowserCoreEngine;
|
|
5945
6799
|
exports.capturePlaywrightStorageOrigins = capturePlaywrightStorageOrigins;
|