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