@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.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
 
@@ -1893,7 +2242,7 @@ async function waitForReady(baseUrl) {
1893
2242
  }
1894
2243
  } catch {
1895
2244
  }
1896
- await delay(200);
2245
+ await delay2(200);
1897
2246
  }
1898
2247
  throw createBrowserCoreError("timeout", `ABP did not become ready within 30000ms at ${baseUrl}`);
1899
2248
  }
@@ -1910,19 +2259,19 @@ async function waitForDevToolsPort(userDataDir) {
1910
2259
  }
1911
2260
  } catch {
1912
2261
  }
1913
- await delay(200);
2262
+ await delay2(200);
1914
2263
  }
1915
2264
  throw createBrowserCoreError(
1916
2265
  "timeout",
1917
2266
  `CDP port file was not written to ${userDataDir} within 30000ms`
1918
2267
  );
1919
2268
  }
1920
- function delay(ms) {
2269
+ function delay2(ms) {
1921
2270
  return new Promise((resolve) => setTimeout(resolve, ms));
1922
2271
  }
1923
2272
 
1924
2273
  // src/action-events.ts
1925
- function isRecord(value) {
2274
+ function isRecord2(value) {
1926
2275
  return typeof value === "object" && value !== null;
1927
2276
  }
1928
2277
  function readBoolean(value) {
@@ -1935,7 +2284,7 @@ function readString(value) {
1935
2284
  return typeof value === "string" ? value : void 0;
1936
2285
  }
1937
2286
  function parseSelectPopupItem(value) {
1938
- if (!isRecord(value)) {
2287
+ if (!isRecord2(value)) {
1939
2288
  return void 0;
1940
2289
  }
1941
2290
  const index = readInteger(value.index);
@@ -1994,225 +2343,22 @@ function normalizeSelectChooserEventData(data) {
1994
2343
  }
1995
2344
 
1996
2345
  // src/action-settle.ts
1997
- var DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS = 5e3;
1998
- var POST_ACTION_SETTLE_QUIET_WINDOW_MS = 400;
1999
- var POST_ACTION_SETTLE_POLL_INTERVAL_MS = 100;
2346
+ var DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
2347
+ var DEFAULT_ABP_POST_LOAD_CAPTURE_WINDOW_MS = 1e3;
2000
2348
  function clampAbpActionSettleTimeout(timeoutMs) {
2001
2349
  if (timeoutMs === void 0) {
2002
2350
  return DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS;
2003
2351
  }
2004
2352
  return Math.max(0, Math.min(DEFAULT_ABP_ACTION_SETTLE_TIMEOUT_MS, timeoutMs));
2005
2353
  }
2006
- function isRecord2(value) {
2007
- return typeof value === "object" && value !== null;
2008
- }
2009
- function readFiniteNumber(value) {
2010
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2011
- }
2012
- function readNonNegativeNumber(value) {
2013
- const parsed = readFiniteNumber(value);
2014
- return parsed === void 0 || parsed < 0 ? 0 : parsed;
2015
- }
2016
- function normalizeAbpSettleTrackerState(value) {
2017
- if (!isRecord2(value)) {
2018
- return void 0;
2019
- }
2020
- const installedAt = readFiniteNumber(value.installedAt);
2021
- const lastMutationAt = readFiniteNumber(value.lastMutationAt);
2022
- const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
2023
- const now = readFiniteNumber(value.now);
2024
- const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
2025
- if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
2026
- return void 0;
2027
- }
2028
- return {
2029
- installedAt,
2030
- lastMutationAt,
2031
- lastNetworkActivityAt,
2032
- now,
2033
- pendingFetches: readNonNegativeNumber(value.pendingFetches),
2034
- pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
2035
- pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
2036
- readyState
2037
- };
2038
- }
2039
- function buildAbpSettleTrackerInstallScript() {
2040
- return `(() => {
2041
- const globalObject = globalThis;
2042
- if (globalObject.__opensteerAbpSettleTrackerInstalled) {
2043
- return true;
2044
- }
2045
-
2046
- const tracker = {
2047
- installedAt: performance.now(),
2048
- lastMutationAt: performance.now(),
2049
- lastNetworkActivityAt: performance.now(),
2050
- pendingFetches: 0,
2051
- pendingTimeouts: 0,
2052
- pendingXhrs: 0,
2053
- readyState: document.readyState,
2054
- timeoutIds: new Set(),
2055
- };
2056
- globalObject.__opensteerAbpSettleTrackerInstalled = true;
2057
- globalObject.__opensteerAbpSettleTracker = tracker;
2058
-
2059
- const markMutation = () => {
2060
- tracker.lastMutationAt = performance.now();
2061
- tracker.readyState = document.readyState;
2062
- };
2063
- const markNetwork = () => {
2064
- tracker.lastNetworkActivityAt = performance.now();
2065
- tracker.readyState = document.readyState;
2066
- };
2067
-
2068
- const startObserver = () => {
2069
- const target = document.documentElement ?? document;
2070
- if (!(target instanceof Node)) {
2071
- return;
2072
- }
2073
- const observer = new MutationObserver(markMutation);
2074
- observer.observe(target, {
2075
- subtree: true,
2076
- childList: true,
2077
- characterData: true,
2078
- attributes: true,
2079
- });
2080
- markMutation();
2081
- };
2082
-
2083
- if (document.documentElement) {
2084
- startObserver();
2085
- } else {
2086
- document.addEventListener("DOMContentLoaded", startObserver, { once: true });
2087
- }
2088
-
2089
- document.addEventListener("readystatechange", markMutation);
2090
- addEventListener("load", markMutation, { once: true });
2091
-
2092
- const nativeSetTimeout = globalObject.setTimeout.bind(globalObject);
2093
- const nativeClearTimeout = globalObject.clearTimeout.bind(globalObject);
2094
- globalObject.setTimeout = function(callback, delay, ...args) {
2095
- tracker.pendingTimeouts += 1;
2096
- markNetwork();
2097
- let handle;
2098
- const wrapped =
2099
- typeof callback === "function"
2100
- ? (...callbackArgs) => {
2101
- if (tracker.timeoutIds.delete(handle)) {
2102
- tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
2103
- }
2104
- try {
2105
- return callback(...callbackArgs);
2106
- } finally {
2107
- markMutation();
2108
- }
2109
- }
2110
- : callback;
2111
- handle = nativeSetTimeout(wrapped, delay, ...args);
2112
- tracker.timeoutIds.add(handle);
2113
- return handle;
2114
- };
2115
- globalObject.clearTimeout = function(handle) {
2116
- if (tracker.timeoutIds.delete(handle)) {
2117
- tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
2118
- }
2119
- return nativeClearTimeout(handle);
2120
- };
2121
-
2122
- if (typeof globalObject.fetch === "function") {
2123
- const nativeFetch = globalObject.fetch.bind(globalObject);
2124
- globalObject.fetch = (...args) => {
2125
- tracker.pendingFetches += 1;
2126
- markNetwork();
2127
- return nativeFetch(...args)
2128
- .finally(() => {
2129
- tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
2130
- markNetwork();
2131
- });
2132
- };
2133
- }
2134
-
2135
- if (typeof globalObject.XMLHttpRequest === "function") {
2136
- const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
2137
- const nativeSend = NativeXMLHttpRequest.prototype.send;
2138
- NativeXMLHttpRequest.prototype.send = function(...args) {
2139
- tracker.pendingXhrs += 1;
2140
- markNetwork();
2141
- const finalize = () => {
2142
- this.removeEventListener("loadend", finalize);
2143
- tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
2144
- markNetwork();
2145
- };
2146
- this.addEventListener("loadend", finalize, { once: true });
2147
- return nativeSend.apply(this, args);
2148
- };
2149
- }
2150
-
2151
- return true;
2152
- })()`;
2153
- }
2154
- function buildAbpSettleTrackerReadExpression() {
2155
- return `(() => {
2156
- const tracker = globalThis.__opensteerAbpSettleTracker;
2157
- if (!tracker) {
2158
- return null;
2159
- }
2160
-
2161
- return {
2162
- installedAt: Number(tracker.installedAt ?? 0),
2163
- lastMutationAt: Number(tracker.lastMutationAt ?? 0),
2164
- lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
2165
- now: Number(performance.now()),
2166
- pendingFetches: Number(tracker.pendingFetches ?? 0),
2167
- pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
2168
- pendingXhrs: Number(tracker.pendingXhrs ?? 0),
2169
- readyState: String(document.readyState),
2170
- };
2171
- })()`;
2172
- }
2173
- function trackerStateIsSettled(tracker) {
2174
- if (!tracker) {
2175
- return false;
2176
- }
2177
- if (tracker.readyState !== "complete") {
2178
- return false;
2179
- }
2180
- if (tracker.pendingFetches > 0 || tracker.pendingTimeouts > 0 || tracker.pendingXhrs > 0) {
2181
- return false;
2182
- }
2183
- const lastActivityAt = Math.max(
2184
- tracker.installedAt,
2185
- tracker.lastMutationAt,
2186
- tracker.lastNetworkActivityAt
2187
- );
2188
- return tracker.now - lastActivityAt >= POST_ACTION_SETTLE_QUIET_WINDOW_MS;
2189
- }
2190
- function abortError(signal) {
2354
+ function abortError2(signal) {
2191
2355
  return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
2192
2356
  }
2193
- async function delay2(ms, signal) {
2194
- if (ms <= 0) {
2195
- return;
2196
- }
2197
- if (signal?.aborted) {
2198
- throw abortError(signal);
2199
- }
2200
- await new Promise((resolve, reject) => {
2201
- const timeoutId = setTimeout(() => {
2202
- signal?.removeEventListener("abort", onAbort);
2203
- resolve();
2204
- }, ms);
2205
- const onAbort = () => {
2206
- clearTimeout(timeoutId);
2207
- signal?.removeEventListener("abort", onAbort);
2208
- reject(abortError(signal));
2209
- };
2210
- signal?.addEventListener("abort", onAbort, { once: true });
2211
- });
2212
- }
2213
2357
  function createAbpActionSettler(context) {
2214
- const installScript = buildAbpSettleTrackerInstallScript();
2215
- const readExpression = buildAbpSettleTrackerReadExpression();
2358
+ const installScript = buildPostLoadTrackerInstallScript();
2359
+ const beginExpression = buildPostLoadTrackerBeginExpression();
2360
+ const freezeExpression = buildPostLoadTrackerFreezeExpression();
2361
+ const readExpression = buildPostLoadTrackerReadExpression();
2216
2362
  async function installTracker(controller) {
2217
2363
  if (!controller.settleTrackerRegistered) {
2218
2364
  await controller.cdp.send("Page.addScriptToEvaluateOnNewDocument", {
@@ -2227,47 +2373,130 @@ function createAbpActionSettler(context) {
2227
2373
  });
2228
2374
  }
2229
2375
  async function readTrackerState(controller) {
2230
- const evaluated = await controller.cdp.send("Runtime.evaluate", {
2231
- expression: readExpression,
2376
+ try {
2377
+ const evaluated = await controller.cdp.send("Runtime.evaluate", {
2378
+ expression: readExpression,
2379
+ returnByValue: true,
2380
+ awaitPromise: true
2381
+ });
2382
+ return normalizePostLoadTrackerState(evaluated.result?.value);
2383
+ } catch (error) {
2384
+ if (context.isPageClosedError(error)) {
2385
+ return void 0;
2386
+ }
2387
+ throw error;
2388
+ }
2389
+ }
2390
+ async function beginTrackerObservation(controller) {
2391
+ await installTracker(controller);
2392
+ await controller.cdp.send("Runtime.evaluate", {
2393
+ expression: beginExpression,
2232
2394
  returnByValue: true,
2233
2395
  awaitPromise: true
2234
2396
  });
2235
- return normalizeAbpSettleTrackerState(evaluated.result?.value);
2236
2397
  }
2237
- async function settle(options) {
2238
- const { controller, timeoutMs, signal, policySettle } = options;
2398
+ async function freezeTrackerObservation(controller) {
2399
+ await controller.cdp.send("Runtime.evaluate", {
2400
+ expression: freezeExpression,
2401
+ returnByValue: true,
2402
+ awaitPromise: true
2403
+ });
2404
+ }
2405
+ async function captureSnapshot(controller) {
2406
+ const documentRef = context.getMainFrameDocumentRef(controller);
2407
+ if (documentRef === void 0) {
2408
+ throw new Error(`page ${controller.pageRef} does not expose a main frame`);
2409
+ }
2410
+ await beginTrackerObservation(controller);
2411
+ const tracker = await readTrackerState(controller);
2412
+ return {
2413
+ pageRef: controller.pageRef,
2414
+ documentRef,
2415
+ ...controller.mainFrameRef === void 0 ? {} : {
2416
+ url: controller.framesByCdpId.get(controller.mainFrameRef)?.currentDocument.url
2417
+ },
2418
+ ...tracker === void 0 ? {} : { tracker: capturePostLoadTrackerSnapshot(tracker) }
2419
+ };
2420
+ }
2421
+ async function waitForPostLoadQuiet(input) {
2422
+ const { controller, timeoutMs, signal } = input;
2239
2423
  if (timeoutMs <= 0) {
2240
2424
  return;
2241
2425
  }
2426
+ const quietMs = input.quietMs ?? DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS;
2427
+ const captureWindowMs = Math.max(
2428
+ 0,
2429
+ Math.min(input.captureWindowMs ?? DEFAULT_ABP_POST_LOAD_CAPTURE_WINDOW_MS, timeoutMs)
2430
+ );
2242
2431
  const deadline = Date.now() + timeoutMs;
2432
+ await installTracker(controller);
2433
+ if (captureWindowMs > 0) {
2434
+ await delayWithSignal(captureWindowMs, signal, deadline);
2435
+ }
2436
+ await freezeTrackerObservation(controller);
2437
+ while (Date.now() < deadline) {
2438
+ if (signal?.aborted) {
2439
+ throw abortError2(signal);
2440
+ }
2441
+ context.throwBackgroundError(controller);
2442
+ if (controller.lifecycleState === "closed") {
2443
+ return;
2444
+ }
2445
+ if (postLoadTrackerIsSettled(await readTrackerState(controller), quietMs)) {
2446
+ return;
2447
+ }
2448
+ await delayWithSignal(100, signal, deadline);
2449
+ }
2450
+ }
2451
+ async function settle(options) {
2452
+ const { controller, timeoutMs, signal, snapshot, policySettle } = options;
2453
+ if (timeoutMs <= 0) {
2454
+ return {
2455
+ trigger: "dom-action",
2456
+ crossDocument: false,
2457
+ bootstrapSettled: false,
2458
+ timedOutPhase: "bootstrap"
2459
+ };
2460
+ }
2243
2461
  const wasPaused = await context.syncExecutionPaused(controller);
2462
+ let boundary = {
2463
+ trigger: "dom-action",
2464
+ crossDocument: false,
2465
+ bootstrapSettled: false,
2466
+ timedOutPhase: "bootstrap"
2467
+ };
2244
2468
  if (wasPaused) {
2245
2469
  await context.setExecutionPaused(controller, false);
2246
2470
  }
2247
2471
  try {
2248
- await installTracker(controller);
2249
- if (policySettle) {
2250
- if (signal?.aborted) {
2251
- throw abortError(signal);
2252
- }
2253
- await policySettle(controller.pageRef, signal);
2254
- }
2255
- while (Date.now() < deadline) {
2256
- context.throwBackgroundError(controller);
2257
- if (controller.lifecycleState === "closed") {
2258
- return;
2259
- }
2260
- if (signal?.aborted) {
2261
- throw abortError(signal);
2472
+ if (snapshot === void 0) {
2473
+ if (policySettle) {
2474
+ if (signal?.aborted) {
2475
+ throw abortError2(signal);
2476
+ }
2477
+ await policySettle(controller.pageRef, "dom-action");
2262
2478
  }
2263
- const tracker = await readTrackerState(controller).catch(() => void 0);
2264
- if (trackerStateIsSettled(tracker)) {
2265
- break;
2479
+ boundary = {
2480
+ trigger: "dom-action",
2481
+ crossDocument: false,
2482
+ bootstrapSettled: true
2483
+ };
2484
+ } else {
2485
+ await installTracker(controller);
2486
+ boundary = await waitForActionBoundary({
2487
+ timeoutMs,
2488
+ ...signal === void 0 ? {} : { signal },
2489
+ snapshot,
2490
+ getCurrentMainFrameDocumentRef: () => context.getMainFrameDocumentRef(controller),
2491
+ getCurrentPageUrl: () => controller.mainFrameRef === void 0 ? void 0 : controller.framesByCdpId.get(controller.mainFrameRef)?.currentDocument.url,
2492
+ isCurrentMainFrameBootstrapSettled: () => context.isCurrentMainFrameBootstrapSettled(controller),
2493
+ readTrackerState: () => readTrackerState(controller),
2494
+ throwBackgroundError: () => context.throwBackgroundError(controller),
2495
+ isPageClosed: () => controller.lifecycleState === "closed"
2496
+ });
2497
+ if (policySettle) {
2498
+ await policySettle(controller.pageRef, boundary.trigger);
2266
2499
  }
2267
- await delay2(
2268
- Math.min(POST_ACTION_SETTLE_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())),
2269
- signal
2270
- );
2271
2500
  }
2272
2501
  } finally {
2273
2502
  if (wasPaused && controller.lifecycleState !== "closed") {
@@ -2277,7 +2506,6 @@ function createAbpActionSettler(context) {
2277
2506
  if (!context.isPageClosedError(error)) {
2278
2507
  throw error;
2279
2508
  }
2280
- return;
2281
2509
  }
2282
2510
  }
2283
2511
  if (controller.lifecycleState !== "closed") {
@@ -2290,12 +2518,36 @@ function createAbpActionSettler(context) {
2290
2518
  }
2291
2519
  }
2292
2520
  }
2521
+ return boundary;
2293
2522
  }
2294
2523
  return {
2524
+ captureSnapshot,
2295
2525
  installTracker,
2526
+ waitForPostLoadQuiet,
2296
2527
  settle
2297
2528
  };
2298
2529
  }
2530
+ async function delayWithSignal(delayMs, signal, deadline) {
2531
+ const effectiveDelay = Math.max(0, Math.min(delayMs, Math.max(0, deadline - Date.now())));
2532
+ if (effectiveDelay <= 0) {
2533
+ return;
2534
+ }
2535
+ if (signal?.aborted) {
2536
+ throw abortError2(signal);
2537
+ }
2538
+ await new Promise((resolve, reject) => {
2539
+ const timer = setTimeout(() => {
2540
+ signal?.removeEventListener("abort", onAbort);
2541
+ resolve();
2542
+ }, effectiveDelay);
2543
+ const onAbort = () => {
2544
+ clearTimeout(timer);
2545
+ signal?.removeEventListener("abort", onAbort);
2546
+ reject(abortError2(signal));
2547
+ };
2548
+ signal?.addEventListener("abort", onAbort, { once: true });
2549
+ });
2550
+ }
2299
2551
 
2300
2552
  // src/rest-client.ts
2301
2553
  function isRecord3(value) {
@@ -2716,6 +2968,7 @@ function createAbpComputerUseBridge(context) {
2716
2968
  });
2717
2969
  let response;
2718
2970
  let dialogEvents = [];
2971
+ let boundary;
2719
2972
  switch (action.type) {
2720
2973
  case "click": {
2721
2974
  const executed = await context.executeInputAction(
@@ -2846,8 +3099,9 @@ function createAbpComputerUseBridge(context) {
2846
3099
  const resultController = context.resolveController(resultPageRef);
2847
3100
  let displayResponse = response;
2848
3101
  if (action.type !== "screenshot") {
2849
- await context.settleActionBoundary(resultController, {
3102
+ boundary = await context.settleActionBoundary(resultController, {
2850
3103
  timeoutMs: clampAbpActionSettleTimeout(remainingMs),
3104
+ ...resultController.pageRef === controller.pageRef && input.snapshot !== void 0 ? { snapshot: input.snapshot } : {},
2851
3105
  signal: input.signal,
2852
3106
  policySettle: input.policySettle
2853
3107
  });
@@ -2878,7 +3132,8 @@ function createAbpComputerUseBridge(context) {
2878
3132
  ...dialogEvents,
2879
3133
  ...popupQueuedEvents
2880
3134
  ],
2881
- timing: timingFromResponse(response, Date.now() - startedAt)
3135
+ timing: timingFromResponse(response, Date.now() - startedAt),
3136
+ ...boundary === void 0 ? {} : { boundary }
2882
3137
  };
2883
3138
  }
2884
3139
  };
@@ -3554,8 +3809,9 @@ function createAbpDomActionBridge(context) {
3554
3809
  },
3555
3810
  async finalizeDomAction(pageRef, options) {
3556
3811
  const controller = context.resolveController(pageRef);
3557
- await context.settleActionBoundary(controller, {
3812
+ const boundary = await context.settleActionBoundary(controller, {
3558
3813
  timeoutMs: clampAbpActionSettleTimeout(options.remainingMs()),
3814
+ ...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
3559
3815
  signal: options.signal,
3560
3816
  policySettle: options.policySettle
3561
3817
  });
@@ -3565,6 +3821,7 @@ function createAbpDomActionBridge(context) {
3565
3821
  details: { pageRef }
3566
3822
  });
3567
3823
  }
3824
+ return boundary;
3568
3825
  }
3569
3826
  };
3570
3827
  }
@@ -4204,6 +4461,8 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
4204
4461
  syncExecutionPaused: (controller) => this.syncControllerExecutionPaused(controller),
4205
4462
  setExecutionPaused: (controller, paused) => this.setControllerExecutionPaused(controller, paused),
4206
4463
  flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
4464
+ getMainFrameDocumentRef: (controller) => controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef)?.currentDocument.documentRef,
4465
+ isCurrentMainFrameBootstrapSettled: () => true,
4207
4466
  throwBackgroundError: (controller) => this.throwBackgroundError(controller),
4208
4467
  isPageClosedError: isAbpPageClosedError
4209
4468
  });
@@ -4966,6 +5225,9 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
4966
5225
  )
4967
5226
  );
4968
5227
  }
5228
+ async drainEvents(input) {
5229
+ return this.drainQueuedEvents(input.pageRef);
5230
+ }
4969
5231
  async listFrames(input) {
4970
5232
  const controller = this.requirePage(input.pageRef);
4971
5233
  await this.flushDomUpdateTask(controller);
@@ -5017,6 +5279,11 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
5017
5279
  (contentDocumentIndex) => resolveCapturedContentDocumentRef(controller.framesByCdpId, captured, contentDocumentIndex)
5018
5280
  );
5019
5281
  }
5282
+ async getActionBoundarySnapshot(input) {
5283
+ const controller = this.requirePage(input.pageRef);
5284
+ await this.flushDomUpdateTask(controller);
5285
+ return this.actionSettler.captureSnapshot(controller);
5286
+ }
5020
5287
  async waitForVisualStability(input) {
5021
5288
  const controller = this.requirePage(input.pageRef);
5022
5289
  await this.flushDomUpdateTask(controller);
@@ -5027,6 +5294,20 @@ var AbpBrowserCoreEngine = class _AbpBrowserCoreEngine {
5027
5294
  });
5028
5295
  await this.flushDomUpdateTask(controller);
5029
5296
  }
5297
+ async waitForPostLoadQuiet(input) {
5298
+ const controller = this.requirePage(input.pageRef);
5299
+ await this.flushDomUpdateTask(controller);
5300
+ await this.actionSettler.waitForPostLoadQuiet({
5301
+ controller,
5302
+ timeoutMs: clampAbpActionSettleTimeout(input.timeoutMs),
5303
+ ...input.quietMs === void 0 ? {} : { quietMs: input.quietMs },
5304
+ ...input.captureWindowMs === void 0 ? {} : { captureWindowMs: input.captureWindowMs },
5305
+ ...input.signal === void 0 ? {} : { signal: input.signal }
5306
+ });
5307
+ if (controller.lifecycleState !== "closed") {
5308
+ await this.flushDomUpdateTask(controller);
5309
+ }
5310
+ }
5030
5311
  async readText(input) {
5031
5312
  const document = this.requireDocument(input.documentRef);
5032
5313
  const controller = this.requirePage(document.pageRef);