@opensteer/engine-abp 0.8.2 → 0.8.4

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.js CHANGED
@@ -1252,6 +1252,355 @@ function sleep(ms) {
1252
1252
  return new Promise((resolve) => setTimeout(resolve, ms));
1253
1253
  }
1254
1254
 
1255
+ // ../browser-core/src/post-load-tracker.ts
1256
+ var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
1257
+ var DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = 100;
1258
+ function isRecord(value) {
1259
+ return typeof value === "object" && value !== null;
1260
+ }
1261
+ function readFiniteNumber(value) {
1262
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1263
+ }
1264
+ function readNonNegativeNumber(value) {
1265
+ const parsed = readFiniteNumber(value);
1266
+ return parsed === void 0 || parsed < 0 ? 0 : parsed;
1267
+ }
1268
+ function normalizePostLoadTrackerState(value) {
1269
+ if (!isRecord(value)) {
1270
+ return void 0;
1271
+ }
1272
+ const installedAt = readFiniteNumber(value.installedAt);
1273
+ const lastMutationAt = readFiniteNumber(value.lastMutationAt);
1274
+ const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
1275
+ const lastTrackedNetworkActivityAt = readFiniteNumber(value.lastTrackedNetworkActivityAt);
1276
+ const now = readFiniteNumber(value.now);
1277
+ const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
1278
+ if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || lastTrackedNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
1279
+ return void 0;
1280
+ }
1281
+ return {
1282
+ installedAt,
1283
+ lastMutationAt,
1284
+ lastNetworkActivityAt,
1285
+ lastTrackedNetworkActivityAt,
1286
+ now,
1287
+ pendingFetches: readNonNegativeNumber(value.pendingFetches),
1288
+ pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
1289
+ pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
1290
+ trackedPendingFetches: readNonNegativeNumber(value.trackedPendingFetches),
1291
+ trackedPendingXhrs: readNonNegativeNumber(value.trackedPendingXhrs),
1292
+ collecting: value.collecting === true,
1293
+ readyState
1294
+ };
1295
+ }
1296
+ function buildPostLoadTrackerInstallScript() {
1297
+ return `(() => {
1298
+ const globalObject = globalThis;
1299
+ if (globalObject.__opensteerActionBoundaryTrackerInstalled) {
1300
+ return true;
1301
+ }
1302
+
1303
+ const tracker = {
1304
+ installedAt: performance.now(),
1305
+ lastMutationAt: performance.now(),
1306
+ lastNetworkActivityAt: performance.now(),
1307
+ lastTrackedNetworkActivityAt: performance.now(),
1308
+ pendingFetches: 0,
1309
+ pendingTimeouts: 0,
1310
+ pendingXhrs: 0,
1311
+ trackedPendingFetches: 0,
1312
+ trackedPendingXhrs: 0,
1313
+ collecting: true,
1314
+ readyState: document.readyState,
1315
+ };
1316
+ globalObject.__opensteerActionBoundaryTrackerInstalled = true;
1317
+ globalObject.__opensteerActionBoundaryTracker = tracker;
1318
+
1319
+ const markMutation = () => {
1320
+ tracker.lastMutationAt = performance.now();
1321
+ tracker.readyState = document.readyState;
1322
+ };
1323
+ const markNetwork = () => {
1324
+ tracker.lastNetworkActivityAt = performance.now();
1325
+ tracker.readyState = document.readyState;
1326
+ };
1327
+ const markTrackedNetwork = () => {
1328
+ tracker.lastTrackedNetworkActivityAt = performance.now();
1329
+ markNetwork();
1330
+ };
1331
+ const resetTracking = () => {
1332
+ const now = performance.now();
1333
+ tracker.lastTrackedNetworkActivityAt = now;
1334
+ tracker.trackedPendingFetches = 0;
1335
+ tracker.trackedPendingXhrs = 0;
1336
+ tracker.collecting = true;
1337
+ tracker.readyState = document.readyState;
1338
+ };
1339
+
1340
+ const startObserver = () => {
1341
+ const target = document.documentElement ?? document;
1342
+ if (!(target instanceof Node)) {
1343
+ return;
1344
+ }
1345
+ const observer = new MutationObserver(markMutation);
1346
+ observer.observe(target, {
1347
+ subtree: true,
1348
+ childList: true,
1349
+ characterData: true,
1350
+ attributes: true,
1351
+ });
1352
+ markMutation();
1353
+ };
1354
+
1355
+ if (document.documentElement) {
1356
+ startObserver();
1357
+ } else {
1358
+ document.addEventListener("DOMContentLoaded", startObserver, { once: true });
1359
+ }
1360
+
1361
+ document.addEventListener("readystatechange", markMutation);
1362
+ addEventListener("load", markMutation, { once: true });
1363
+
1364
+ if (typeof globalObject.fetch === "function") {
1365
+ const nativeFetch = globalObject.fetch.bind(globalObject);
1366
+ globalObject.fetch = (...args) => {
1367
+ const tracked = tracker.collecting === true;
1368
+ tracker.pendingFetches += 1;
1369
+ if (tracked) {
1370
+ tracker.trackedPendingFetches += 1;
1371
+ markTrackedNetwork();
1372
+ } else {
1373
+ markNetwork();
1374
+ }
1375
+ return nativeFetch(...args)
1376
+ .finally(() => {
1377
+ tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
1378
+ if (tracked) {
1379
+ tracker.trackedPendingFetches = Math.max(0, tracker.trackedPendingFetches - 1);
1380
+ markTrackedNetwork();
1381
+ } else {
1382
+ markNetwork();
1383
+ }
1384
+ });
1385
+ };
1386
+ }
1387
+
1388
+ if (typeof globalObject.XMLHttpRequest === "function") {
1389
+ const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
1390
+ const nativeSend = NativeXMLHttpRequest.prototype.send;
1391
+ NativeXMLHttpRequest.prototype.send = function(...args) {
1392
+ const tracked = tracker.collecting === true;
1393
+ tracker.pendingXhrs += 1;
1394
+ if (tracked) {
1395
+ tracker.trackedPendingXhrs += 1;
1396
+ markTrackedNetwork();
1397
+ } else {
1398
+ markNetwork();
1399
+ }
1400
+ const finalize = () => {
1401
+ this.removeEventListener("loadend", finalize);
1402
+ tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
1403
+ if (tracked) {
1404
+ tracker.trackedPendingXhrs = Math.max(0, tracker.trackedPendingXhrs - 1);
1405
+ markTrackedNetwork();
1406
+ } else {
1407
+ markNetwork();
1408
+ }
1409
+ };
1410
+ this.addEventListener("loadend", finalize, { once: true });
1411
+ return nativeSend.apply(this, args);
1412
+ };
1413
+ }
1414
+
1415
+ tracker.beginObservation = () => {
1416
+ resetTracking();
1417
+ return true;
1418
+ };
1419
+ tracker.freezeObservation = () => {
1420
+ tracker.collecting = false;
1421
+ tracker.readyState = document.readyState;
1422
+ return true;
1423
+ };
1424
+
1425
+ return true;
1426
+ })()`;
1427
+ }
1428
+ function buildPostLoadTrackerBeginExpression() {
1429
+ return `(() => {
1430
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
1431
+ if (!tracker || typeof tracker.beginObservation !== "function") {
1432
+ return false;
1433
+ }
1434
+ return tracker.beginObservation();
1435
+ })()`;
1436
+ }
1437
+ function buildPostLoadTrackerFreezeExpression() {
1438
+ return `(() => {
1439
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
1440
+ if (!tracker || typeof tracker.freezeObservation !== "function") {
1441
+ return false;
1442
+ }
1443
+ return tracker.freezeObservation();
1444
+ })()`;
1445
+ }
1446
+ function buildPostLoadTrackerReadExpression() {
1447
+ return `(() => {
1448
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
1449
+ if (!tracker) {
1450
+ return null;
1451
+ }
1452
+
1453
+ return {
1454
+ installedAt: Number(tracker.installedAt ?? 0),
1455
+ lastMutationAt: Number(tracker.lastMutationAt ?? 0),
1456
+ lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
1457
+ lastTrackedNetworkActivityAt: Number(tracker.lastTrackedNetworkActivityAt ?? 0),
1458
+ now: Number(performance.now()),
1459
+ pendingFetches: Number(tracker.pendingFetches ?? 0),
1460
+ pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
1461
+ pendingXhrs: Number(tracker.pendingXhrs ?? 0),
1462
+ trackedPendingFetches: Number(tracker.trackedPendingFetches ?? 0),
1463
+ trackedPendingXhrs: Number(tracker.trackedPendingXhrs ?? 0),
1464
+ collecting: tracker.collecting === true,
1465
+ readyState: String(document.readyState),
1466
+ };
1467
+ })()`;
1468
+ }
1469
+ function capturePostLoadTrackerSnapshot(tracker) {
1470
+ return {
1471
+ lastTrackedNetworkActivityAt: tracker.lastTrackedNetworkActivityAt,
1472
+ trackedPendingFetches: tracker.trackedPendingFetches,
1473
+ trackedPendingXhrs: tracker.trackedPendingXhrs
1474
+ };
1475
+ }
1476
+ function postLoadTrackerHasTrackedNetworkActivitySince(snapshot, tracker) {
1477
+ if (!tracker) {
1478
+ return false;
1479
+ }
1480
+ return tracker.trackedPendingFetches > snapshot.trackedPendingFetches || tracker.trackedPendingXhrs > snapshot.trackedPendingXhrs || tracker.lastTrackedNetworkActivityAt > snapshot.lastTrackedNetworkActivityAt;
1481
+ }
1482
+ function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS) {
1483
+ if (!tracker) {
1484
+ return false;
1485
+ }
1486
+ if (tracker.readyState !== "complete") {
1487
+ return false;
1488
+ }
1489
+ if (tracker.trackedPendingFetches > 0 || tracker.trackedPendingXhrs > 0) {
1490
+ return false;
1491
+ }
1492
+ const lastActivityAt = Math.max(
1493
+ tracker.installedAt,
1494
+ tracker.lastMutationAt,
1495
+ tracker.lastTrackedNetworkActivityAt
1496
+ );
1497
+ return tracker.now - lastActivityAt >= quietWindowMs;
1498
+ }
1499
+
1500
+ // ../browser-core/src/action-boundary.ts
1501
+ var CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = 3e4;
1502
+ var CROSS_DOCUMENT_DETECTION_WINDOW_MS = 500;
1503
+ async function waitForActionBoundary(input) {
1504
+ if (input.timeoutMs <= 0) {
1505
+ return {
1506
+ trigger: "dom-action",
1507
+ crossDocument: false,
1508
+ bootstrapSettled: false,
1509
+ timedOutPhase: "bootstrap"
1510
+ };
1511
+ }
1512
+ const deadline = Date.now() + input.timeoutMs;
1513
+ const crossDocumentDetectionDeadline = input.snapshot === void 0 ? void 0 : Math.min(deadline, Date.now() + CROSS_DOCUMENT_DETECTION_WINDOW_MS);
1514
+ const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
1515
+ let trigger = "dom-action";
1516
+ let crossDocument = false;
1517
+ let sameDocumentAsyncActivity = false;
1518
+ while (Date.now() < deadline) {
1519
+ input.throwBackgroundError();
1520
+ if (input.isPageClosed()) {
1521
+ return {
1522
+ trigger,
1523
+ crossDocument,
1524
+ bootstrapSettled: true
1525
+ };
1526
+ }
1527
+ if (input.signal?.aborted) {
1528
+ if (isTimeoutAbort(input.signal.reason) && Date.now() >= deadline) {
1529
+ return {
1530
+ trigger,
1531
+ crossDocument,
1532
+ bootstrapSettled: false,
1533
+ timedOutPhase: "bootstrap"
1534
+ };
1535
+ }
1536
+ throw abortError(input.signal);
1537
+ }
1538
+ const currentDocumentRef = input.getCurrentMainFrameDocumentRef();
1539
+ const currentPageUrl = input.getCurrentPageUrl?.();
1540
+ if (input.snapshot !== void 0 && currentDocumentRef !== void 0 && currentDocumentRef !== input.snapshot.documentRef) {
1541
+ trigger = "navigation";
1542
+ crossDocument = true;
1543
+ }
1544
+ if (!crossDocument && !sameDocumentAsyncActivity && input.snapshot?.tracker !== void 0 && postLoadTrackerHasTrackedNetworkActivitySince(
1545
+ input.snapshot.tracker,
1546
+ await input.readTrackerState()
1547
+ )) {
1548
+ trigger = "navigation";
1549
+ sameDocumentAsyncActivity = true;
1550
+ }
1551
+ if (!crossDocument && input.snapshot?.url !== void 0 && currentPageUrl !== void 0 && currentPageUrl !== input.snapshot.url && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
1552
+ trigger = "navigation";
1553
+ crossDocument = true;
1554
+ }
1555
+ if (!crossDocument && crossDocumentDetectionDeadline !== void 0 && Date.now() >= crossDocumentDetectionDeadline) {
1556
+ return {
1557
+ trigger,
1558
+ crossDocument,
1559
+ bootstrapSettled: true
1560
+ };
1561
+ }
1562
+ if (sameDocumentAsyncActivity) {
1563
+ return {
1564
+ trigger,
1565
+ crossDocument,
1566
+ bootstrapSettled: true
1567
+ };
1568
+ }
1569
+ if (crossDocument && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
1570
+ await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
1571
+ continue;
1572
+ }
1573
+ if (crossDocument) {
1574
+ return {
1575
+ trigger,
1576
+ crossDocument,
1577
+ bootstrapSettled: true
1578
+ };
1579
+ }
1580
+ await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
1581
+ }
1582
+ return {
1583
+ trigger,
1584
+ crossDocument,
1585
+ bootstrapSettled: false,
1586
+ timedOutPhase: "bootstrap"
1587
+ };
1588
+ }
1589
+ function abortError(signal) {
1590
+ return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
1591
+ }
1592
+ async function delay(ms) {
1593
+ if (ms <= 0) {
1594
+ return;
1595
+ }
1596
+ await new Promise((resolve) => {
1597
+ setTimeout(resolve, ms);
1598
+ });
1599
+ }
1600
+ function isTimeoutAbort(reason) {
1601
+ return typeof reason === "object" && reason !== null && "code" in reason && reason.code === "timeout";
1602
+ }
1603
+
1255
1604
  // ../protocol/src/computer-use-bridge.ts
1256
1605
  var OPENSTEER_COMPUTER_USE_BRIDGE_SYMBOL = /* @__PURE__ */ Symbol.for("@opensteer/computer-use-bridge");
1257
1606
 
@@ -1886,7 +2235,7 @@ async function waitForReady(baseUrl) {
1886
2235
  }
1887
2236
  } catch {
1888
2237
  }
1889
- await delay(200);
2238
+ await delay2(200);
1890
2239
  }
1891
2240
  throw createBrowserCoreError("timeout", `ABP did not become ready within 30000ms at ${baseUrl}`);
1892
2241
  }
@@ -1903,19 +2252,19 @@ async function waitForDevToolsPort(userDataDir) {
1903
2252
  }
1904
2253
  } catch {
1905
2254
  }
1906
- await delay(200);
2255
+ await delay2(200);
1907
2256
  }
1908
2257
  throw createBrowserCoreError(
1909
2258
  "timeout",
1910
2259
  `CDP port file was not written to ${userDataDir} within 30000ms`
1911
2260
  );
1912
2261
  }
1913
- function delay(ms) {
2262
+ function delay2(ms) {
1914
2263
  return new Promise((resolve) => setTimeout(resolve, ms));
1915
2264
  }
1916
2265
 
1917
2266
  // src/action-events.ts
1918
- function isRecord(value) {
2267
+ function isRecord2(value) {
1919
2268
  return typeof value === "object" && value !== null;
1920
2269
  }
1921
2270
  function readBoolean(value) {
@@ -1928,7 +2277,7 @@ function readString(value) {
1928
2277
  return typeof value === "string" ? value : void 0;
1929
2278
  }
1930
2279
  function parseSelectPopupItem(value) {
1931
- if (!isRecord(value)) {
2280
+ if (!isRecord2(value)) {
1932
2281
  return void 0;
1933
2282
  }
1934
2283
  const index = readInteger(value.index);
@@ -1987,225 +2336,22 @@ function normalizeSelectChooserEventData(data) {
1987
2336
  }
1988
2337
 
1989
2338
  // src/action-settle.ts
1990
- var DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS = 5e3;
1991
- var POST_ACTION_SETTLE_QUIET_WINDOW_MS = 400;
1992
- var POST_ACTION_SETTLE_POLL_INTERVAL_MS = 100;
2339
+ var DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
2340
+ var DEFAULT_ABP_POST_LOAD_CAPTURE_WINDOW_MS = 1e3;
1993
2341
  function clampAbpActionSettleTimeout(timeoutMs) {
1994
2342
  if (timeoutMs === void 0) {
1995
2343
  return DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS;
1996
2344
  }
1997
2345
  return Math.max(0, Math.min(DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS, timeoutMs));
1998
2346
  }
1999
- function isRecord2(value) {
2000
- return typeof value === "object" && value !== null;
2001
- }
2002
- function readFiniteNumber(value) {
2003
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2004
- }
2005
- function readNonNegativeNumber(value) {
2006
- const parsed = readFiniteNumber(value);
2007
- return parsed === void 0 || parsed < 0 ? 0 : parsed;
2008
- }
2009
- function normalizeAbpSettleTrackerState(value) {
2010
- if (!isRecord2(value)) {
2011
- return void 0;
2012
- }
2013
- const installedAt = readFiniteNumber(value.installedAt);
2014
- const lastMutationAt = readFiniteNumber(value.lastMutationAt);
2015
- const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
2016
- const now = readFiniteNumber(value.now);
2017
- const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
2018
- if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
2019
- return void 0;
2020
- }
2021
- return {
2022
- installedAt,
2023
- lastMutationAt,
2024
- lastNetworkActivityAt,
2025
- now,
2026
- pendingFetches: readNonNegativeNumber(value.pendingFetches),
2027
- pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
2028
- pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
2029
- readyState
2030
- };
2031
- }
2032
- function buildAbpSettleTrackerInstallScript() {
2033
- return `(() => {
2034
- const globalObject = globalThis;
2035
- if (globalObject.__opensteerAbpSettleTrackerInstalled) {
2036
- return true;
2037
- }
2038
-
2039
- const tracker = {
2040
- installedAt: performance.now(),
2041
- lastMutationAt: performance.now(),
2042
- lastNetworkActivityAt: performance.now(),
2043
- pendingFetches: 0,
2044
- pendingTimeouts: 0,
2045
- pendingXhrs: 0,
2046
- readyState: document.readyState,
2047
- timeoutIds: new Set(),
2048
- };
2049
- globalObject.__opensteerAbpSettleTrackerInstalled = true;
2050
- globalObject.__opensteerAbpSettleTracker = tracker;
2051
-
2052
- const markMutation = () => {
2053
- tracker.lastMutationAt = performance.now();
2054
- tracker.readyState = document.readyState;
2055
- };
2056
- const markNetwork = () => {
2057
- tracker.lastNetworkActivityAt = performance.now();
2058
- tracker.readyState = document.readyState;
2059
- };
2060
-
2061
- const startObserver = () => {
2062
- const target = document.documentElement ?? document;
2063
- if (!(target instanceof Node)) {
2064
- return;
2065
- }
2066
- const observer = new MutationObserver(markMutation);
2067
- observer.observe(target, {
2068
- subtree: true,
2069
- childList: true,
2070
- characterData: true,
2071
- attributes: true,
2072
- });
2073
- markMutation();
2074
- };
2075
-
2076
- if (document.documentElement) {
2077
- startObserver();
2078
- } else {
2079
- document.addEventListener("DOMContentLoaded", startObserver, { once: true });
2080
- }
2081
-
2082
- document.addEventListener("readystatechange", markMutation);
2083
- addEventListener("load", markMutation, { once: true });
2084
-
2085
- const nativeSetTimeout = globalObject.setTimeout.bind(globalObject);
2086
- const nativeClearTimeout = globalObject.clearTimeout.bind(globalObject);
2087
- globalObject.setTimeout = function(callback, delay, ...args) {
2088
- tracker.pendingTimeouts += 1;
2089
- markNetwork();
2090
- let handle;
2091
- const wrapped =
2092
- typeof callback === "function"
2093
- ? (...callbackArgs) => {
2094
- if (tracker.timeoutIds.delete(handle)) {
2095
- tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
2096
- }
2097
- try {
2098
- return callback(...callbackArgs);
2099
- } finally {
2100
- markMutation();
2101
- }
2102
- }
2103
- : callback;
2104
- handle = nativeSetTimeout(wrapped, delay, ...args);
2105
- tracker.timeoutIds.add(handle);
2106
- return handle;
2107
- };
2108
- globalObject.clearTimeout = function(handle) {
2109
- if (tracker.timeoutIds.delete(handle)) {
2110
- tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
2111
- }
2112
- return nativeClearTimeout(handle);
2113
- };
2114
-
2115
- if (typeof globalObject.fetch === "function") {
2116
- const nativeFetch = globalObject.fetch.bind(globalObject);
2117
- globalObject.fetch = (...args) => {
2118
- tracker.pendingFetches += 1;
2119
- markNetwork();
2120
- return nativeFetch(...args)
2121
- .finally(() => {
2122
- tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
2123
- markNetwork();
2124
- });
2125
- };
2126
- }
2127
-
2128
- if (typeof globalObject.XMLHttpRequest === "function") {
2129
- const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
2130
- const nativeSend = NativeXMLHttpRequest.prototype.send;
2131
- NativeXMLHttpRequest.prototype.send = function(...args) {
2132
- tracker.pendingXhrs += 1;
2133
- markNetwork();
2134
- const finalize = () => {
2135
- this.removeEventListener("loadend", finalize);
2136
- tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
2137
- markNetwork();
2138
- };
2139
- this.addEventListener("loadend", finalize, { once: true });
2140
- return nativeSend.apply(this, args);
2141
- };
2142
- }
2143
-
2144
- return true;
2145
- })()`;
2146
- }
2147
- function buildAbpSettleTrackerReadExpression() {
2148
- return `(() => {
2149
- const tracker = globalThis.__opensteerAbpSettleTracker;
2150
- if (!tracker) {
2151
- return null;
2152
- }
2153
-
2154
- return {
2155
- installedAt: Number(tracker.installedAt ?? 0),
2156
- lastMutationAt: Number(tracker.lastMutationAt ?? 0),
2157
- lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
2158
- now: Number(performance.now()),
2159
- pendingFetches: Number(tracker.pendingFetches ?? 0),
2160
- pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
2161
- pendingXhrs: Number(tracker.pendingXhrs ?? 0),
2162
- readyState: String(document.readyState),
2163
- };
2164
- })()`;
2165
- }
2166
- function trackerStateIsSettled(tracker) {
2167
- if (!tracker) {
2168
- return false;
2169
- }
2170
- if (tracker.readyState !== "complete") {
2171
- return false;
2172
- }
2173
- if (tracker.pendingFetches > 0 || tracker.pendingTimeouts > 0 || tracker.pendingXhrs > 0) {
2174
- return false;
2175
- }
2176
- const lastActivityAt = Math.max(
2177
- tracker.installedAt,
2178
- tracker.lastMutationAt,
2179
- tracker.lastNetworkActivityAt
2180
- );
2181
- return tracker.now - lastActivityAt >= POST_ACTION_SETTLE_QUIET_WINDOW_MS;
2182
- }
2183
- function abortError(signal) {
2347
+ function abortError2(signal) {
2184
2348
  return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
2185
2349
  }
2186
- async function delay2(ms, signal) {
2187
- if (ms <= 0) {
2188
- return;
2189
- }
2190
- if (signal?.aborted) {
2191
- throw abortError(signal);
2192
- }
2193
- await new Promise((resolve, reject) => {
2194
- const timeoutId = setTimeout(() => {
2195
- signal?.removeEventListener("abort", onAbort);
2196
- resolve();
2197
- }, ms);
2198
- const onAbort = () => {
2199
- clearTimeout(timeoutId);
2200
- signal?.removeEventListener("abort", onAbort);
2201
- reject(abortError(signal));
2202
- };
2203
- signal?.addEventListener("abort", onAbort, { once: true });
2204
- });
2205
- }
2206
2350
  function createAbpActionSettler(context) {
2207
- const installScript = buildAbpSettleTrackerInstallScript();
2208
- const readExpression = buildAbpSettleTrackerReadExpression();
2351
+ const installScript = buildPostLoadTrackerInstallScript();
2352
+ const beginExpression = buildPostLoadTrackerBeginExpression();
2353
+ const freezeExpression = buildPostLoadTrackerFreezeExpression();
2354
+ const readExpression = buildPostLoadTrackerReadExpression();
2209
2355
  async function installTracker(controller) {
2210
2356
  if (!controller.settleTrackerRegistered) {
2211
2357
  await controller.cdp.send("Page.addScriptToEvaluateOnNewDocument", {
@@ -2220,47 +2366,130 @@ function createAbpActionSettler(context) {
2220
2366
  });
2221
2367
  }
2222
2368
  async function readTrackerState(controller) {
2223
- const evaluated = await controller.cdp.send("Runtime.evaluate", {
2224
- expression: readExpression,
2369
+ try {
2370
+ const evaluated = await controller.cdp.send("Runtime.evaluate", {
2371
+ expression: readExpression,
2372
+ returnByValue: true,
2373
+ awaitPromise: true
2374
+ });
2375
+ return normalizePostLoadTrackerState(evaluated.result?.value);
2376
+ } catch (error) {
2377
+ if (context.isPageClosedError(error)) {
2378
+ return void 0;
2379
+ }
2380
+ throw error;
2381
+ }
2382
+ }
2383
+ async function beginTrackerObservation(controller) {
2384
+ await installTracker(controller);
2385
+ await controller.cdp.send("Runtime.evaluate", {
2386
+ expression: beginExpression,
2225
2387
  returnByValue: true,
2226
2388
  awaitPromise: true
2227
2389
  });
2228
- return normalizeAbpSettleTrackerState(evaluated.result?.value);
2229
2390
  }
2230
- async function settle(options) {
2231
- const { controller, timeoutMs, signal, policySettle } = options;
2391
+ async function freezeTrackerObservation(controller) {
2392
+ await controller.cdp.send("Runtime.evaluate", {
2393
+ expression: freezeExpression,
2394
+ returnByValue: true,
2395
+ awaitPromise: true
2396
+ });
2397
+ }
2398
+ async function captureSnapshot(controller) {
2399
+ const documentRef = context.getMainFrameDocumentRef(controller);
2400
+ if (documentRef === void 0) {
2401
+ throw new Error(`page ${controller.pageRef} does not expose a main frame`);
2402
+ }
2403
+ await beginTrackerObservation(controller);
2404
+ const tracker = await readTrackerState(controller);
2405
+ return {
2406
+ pageRef: controller.pageRef,
2407
+ documentRef,
2408
+ ...controller.mainFrameRef === void 0 ? {} : {
2409
+ url: controller.framesByCdpId.get(controller.mainFrameRef)?.currentDocument.url
2410
+ },
2411
+ ...tracker === void 0 ? {} : { tracker: capturePostLoadTrackerSnapshot(tracker) }
2412
+ };
2413
+ }
2414
+ async function waitForPostLoadQuiet(input) {
2415
+ const { controller, timeoutMs, signal } = input;
2232
2416
  if (timeoutMs <= 0) {
2233
2417
  return;
2234
2418
  }
2419
+ const quietMs = input.quietMs ?? DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS;
2420
+ const captureWindowMs = Math.max(
2421
+ 0,
2422
+ Math.min(input.captureWindowMs ?? DEFAULT_ABP_POST_LOAD_CAPTURE_WINDOW_MS, timeoutMs)
2423
+ );
2235
2424
  const deadline = Date.now() + timeoutMs;
2425
+ await installTracker(controller);
2426
+ if (captureWindowMs > 0) {
2427
+ await delayWithSignal(captureWindowMs, signal, deadline);
2428
+ }
2429
+ await freezeTrackerObservation(controller);
2430
+ while (Date.now() < deadline) {
2431
+ if (signal?.aborted) {
2432
+ throw abortError2(signal);
2433
+ }
2434
+ context.throwBackgroundError(controller);
2435
+ if (controller.lifecycleState === "closed") {
2436
+ return;
2437
+ }
2438
+ if (postLoadTrackerIsSettled(await readTrackerState(controller), quietMs)) {
2439
+ return;
2440
+ }
2441
+ await delayWithSignal(100, signal, deadline);
2442
+ }
2443
+ }
2444
+ async function settle(options) {
2445
+ const { controller, timeoutMs, signal, snapshot, policySettle } = options;
2446
+ if (timeoutMs <= 0) {
2447
+ return {
2448
+ trigger: "dom-action",
2449
+ crossDocument: false,
2450
+ bootstrapSettled: false,
2451
+ timedOutPhase: "bootstrap"
2452
+ };
2453
+ }
2236
2454
  const wasPaused = await context.syncExecutionPaused(controller);
2455
+ let boundary = {
2456
+ trigger: "dom-action",
2457
+ crossDocument: false,
2458
+ bootstrapSettled: false,
2459
+ timedOutPhase: "bootstrap"
2460
+ };
2237
2461
  if (wasPaused) {
2238
2462
  await context.setExecutionPaused(controller, false);
2239
2463
  }
2240
2464
  try {
2241
- await installTracker(controller);
2242
- if (policySettle) {
2243
- if (signal?.aborted) {
2244
- throw abortError(signal);
2245
- }
2246
- await policySettle(controller.pageRef, signal);
2247
- }
2248
- while (Date.now() < deadline) {
2249
- context.throwBackgroundError(controller);
2250
- if (controller.lifecycleState === "closed") {
2251
- return;
2252
- }
2253
- if (signal?.aborted) {
2254
- throw abortError(signal);
2465
+ if (snapshot === void 0) {
2466
+ if (policySettle) {
2467
+ if (signal?.aborted) {
2468
+ throw abortError2(signal);
2469
+ }
2470
+ await policySettle(controller.pageRef, "dom-action");
2255
2471
  }
2256
- const tracker = await readTrackerState(controller).catch(() => void 0);
2257
- if (trackerStateIsSettled(tracker)) {
2258
- break;
2472
+ boundary = {
2473
+ trigger: "dom-action",
2474
+ crossDocument: false,
2475
+ bootstrapSettled: true
2476
+ };
2477
+ } else {
2478
+ await installTracker(controller);
2479
+ boundary = await waitForActionBoundary({
2480
+ timeoutMs,
2481
+ ...signal === void 0 ? {} : { signal },
2482
+ snapshot,
2483
+ getCurrentMainFrameDocumentRef: () => context.getMainFrameDocumentRef(controller),
2484
+ getCurrentPageUrl: () => controller.mainFrameRef === void 0 ? void 0 : controller.framesByCdpId.get(controller.mainFrameRef)?.currentDocument.url,
2485
+ isCurrentMainFrameBootstrapSettled: () => context.isCurrentMainFrameBootstrapSettled(controller),
2486
+ readTrackerState: () => readTrackerState(controller),
2487
+ throwBackgroundError: () => context.throwBackgroundError(controller),
2488
+ isPageClosed: () => controller.lifecycleState === "closed"
2489
+ });
2490
+ if (policySettle) {
2491
+ await policySettle(controller.pageRef, boundary.trigger);
2259
2492
  }
2260
- await delay2(
2261
- Math.min(POST_ACTION_SETTLE_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())),
2262
- signal
2263
- );
2264
2493
  }
2265
2494
  } finally {
2266
2495
  if (wasPaused && controller.lifecycleState !== "closed") {
@@ -2270,7 +2499,6 @@ function createAbpActionSettler(context) {
2270
2499
  if (!context.isPageClosedError(error)) {
2271
2500
  throw error;
2272
2501
  }
2273
- return;
2274
2502
  }
2275
2503
  }
2276
2504
  if (controller.lifecycleState !== "closed") {
@@ -2283,12 +2511,36 @@ function createAbpActionSettler(context) {
2283
2511
  }
2284
2512
  }
2285
2513
  }
2514
+ return boundary;
2286
2515
  }
2287
2516
  return {
2517
+ captureSnapshot,
2288
2518
  installTracker,
2519
+ waitForPostLoadQuiet,
2289
2520
  settle
2290
2521
  };
2291
2522
  }
2523
+ async function delayWithSignal(delayMs, signal, deadline) {
2524
+ const effectiveDelay = Math.max(0, Math.min(delayMs, Math.max(0, deadline - Date.now())));
2525
+ if (effectiveDelay <= 0) {
2526
+ return;
2527
+ }
2528
+ if (signal?.aborted) {
2529
+ throw abortError2(signal);
2530
+ }
2531
+ await new Promise((resolve, reject) => {
2532
+ const timer = setTimeout(() => {
2533
+ signal?.removeEventListener("abort", onAbort);
2534
+ resolve();
2535
+ }, effectiveDelay);
2536
+ const onAbort = () => {
2537
+ clearTimeout(timer);
2538
+ signal?.removeEventListener("abort", onAbort);
2539
+ reject(abortError2(signal));
2540
+ };
2541
+ signal?.addEventListener("abort", onAbort, { once: true });
2542
+ });
2543
+ }
2292
2544
 
2293
2545
  // src/rest-client.ts
2294
2546
  function isRecord3(value) {
@@ -2709,6 +2961,7 @@ function createAbpComputerUseBridge(context) {
2709
2961
  });
2710
2962
  let response;
2711
2963
  let dialogEvents = [];
2964
+ let boundary;
2712
2965
  switch (action.type) {
2713
2966
  case "click": {
2714
2967
  const executed = await context.executeInputAction(
@@ -2839,8 +3092,9 @@ function createAbpComputerUseBridge(context) {
2839
3092
  const resultController = context.resolveController(resultPageRef);
2840
3093
  let displayResponse = response;
2841
3094
  if (action.type !== "screenshot") {
2842
- await context.settleActionBoundary(resultController, {
3095
+ boundary = await context.settleActionBoundary(resultController, {
2843
3096
  timeoutMs: clampAbpActionSettleTimeout(remainingMs),
3097
+ ...resultController.pageRef === controller.pageRef && input.snapshot !== void 0 ? { snapshot: input.snapshot } : {},
2844
3098
  signal: input.signal,
2845
3099
  policySettle: input.policySettle
2846
3100
  });
@@ -2871,7 +3125,8 @@ function createAbpComputerUseBridge(context) {
2871
3125
  ...dialogEvents,
2872
3126
  ...popupQueuedEvents
2873
3127
  ],
2874
- timing: timingFromResponse(response, Date.now() - startedAt)
3128
+ timing: timingFromResponse(response, Date.now() - startedAt),
3129
+ ...boundary === void 0 ? {} : { boundary }
2875
3130
  };
2876
3131
  }
2877
3132
  };
@@ -3547,8 +3802,9 @@ function createAbpDomActionBridge(context) {
3547
3802
  },
3548
3803
  async finalizeDomAction(pageRef, options) {
3549
3804
  const controller = context.resolveController(pageRef);
3550
- await context.settleActionBoundary(controller, {
3805
+ const boundary = await context.settleActionBoundary(controller, {
3551
3806
  timeoutMs: clampAbpActionSettleTimeout(options.remainingMs()),
3807
+ ...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
3552
3808
  signal: options.signal,
3553
3809
  policySettle: options.policySettle
3554
3810
  });
@@ -3558,6 +3814,7 @@ function createAbpDomActionBridge(context) {
3558
3814
  details: { pageRef }
3559
3815
  });
3560
3816
  }
3817
+ return boundary;
3561
3818
  }
3562
3819
  };
3563
3820
  }
@@ -4197,6 +4454,8 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
4197
4454
  syncExecutionPaused: (controller) => this.syncControllerExecutionPaused(controller),
4198
4455
  setExecutionPaused: (controller, paused) => this.setControllerExecutionPaused(controller, paused),
4199
4456
  flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
4457
+ getMainFrameDocumentRef: (controller) => controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef)?.currentDocument.documentRef,
4458
+ isCurrentMainFrameBootstrapSettled: () => true,
4200
4459
  throwBackgroundError: (controller) => this.throwBackgroundError(controller),
4201
4460
  isPageClosedError: isAbpPageClosedError
4202
4461
  });
@@ -4959,6 +5218,9 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
4959
5218
  )
4960
5219
  );
4961
5220
  }
5221
+ async drainEvents(input) {
5222
+ return this.drainQueuedEvents(input.pageRef);
5223
+ }
4962
5224
  async listFrames(input) {
4963
5225
  const controller = this.requirePage(input.pageRef);
4964
5226
  await this.flushDomUpdateTask(controller);
@@ -5010,6 +5272,11 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
5010
5272
  (contentDocumentIndex) => resolveCapturedContentDocumentRef(controller.framesByCdpId, captured, contentDocumentIndex)
5011
5273
  );
5012
5274
  }
5275
+ async getActionBoundarySnapshot(input) {
5276
+ const controller = this.requirePage(input.pageRef);
5277
+ await this.flushDomUpdateTask(controller);
5278
+ return this.actionSettler.captureSnapshot(controller);
5279
+ }
5013
5280
  async waitForVisualStability(input) {
5014
5281
  const controller = this.requirePage(input.pageRef);
5015
5282
  await this.flushDomUpdateTask(controller);
@@ -5020,6 +5287,20 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
5020
5287
  });
5021
5288
  await this.flushDomUpdateTask(controller);
5022
5289
  }
5290
+ async waitForPostLoadQuiet(input) {
5291
+ const controller = this.requirePage(input.pageRef);
5292
+ await this.flushDomUpdateTask(controller);
5293
+ await this.actionSettler.waitForPostLoadQuiet({
5294
+ controller,
5295
+ timeoutMs: clampAbpActionSettleTimeout(input.timeoutMs),
5296
+ ...input.quietMs === void 0 ? {} : { quietMs: input.quietMs },
5297
+ ...input.captureWindowMs === void 0 ? {} : { captureWindowMs: input.captureWindowMs },
5298
+ ...input.signal === void 0 ? {} : { signal: input.signal }
5299
+ });
5300
+ if (controller.lifecycleState !== "closed") {
5301
+ await this.flushDomUpdateTask(controller);
5302
+ }
5303
+ }
5023
5304
  async readText(input) {
5024
5305
  const document = this.requireDocument(input.documentRef);
5025
5306
  const controller = this.requirePage(document.pageRef);