cdp-toolkit 2.0.0 → 2.2.0

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
@@ -1,9 +1,20 @@
1
+ var __esm = (fn, res, err) => () => {
2
+ if (fn)
3
+ try {
4
+ res = fn(fn = 0);
5
+ } catch (e) {
6
+ err = [e];
7
+ }
8
+ if (err)
9
+ throw err[0];
10
+ return res;
11
+ };
12
+
1
13
  // src/leases.ts
2
14
  import { AsyncLocalStorage } from "node:async_hooks";
3
15
  import { randomBytes } from "node:crypto";
4
16
  import { mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
5
17
  import { join } from "node:path";
6
- var DEFAULT_LEASE_TTL_MS = 900000;
7
18
  function leaseDir() {
8
19
  return process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
9
20
  }
@@ -11,7 +22,6 @@ function leaseTtlMs() {
11
22
  const raw = Number(process.env.CDP_LEASE_TTL_MS);
12
23
  return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LEASE_TTL_MS;
13
24
  }
14
- var longLived = false;
15
25
  function markLongLivedProcess(value = true) {
16
26
  longLived = value;
17
27
  }
@@ -49,17 +59,6 @@ function tokenParts(token) {
49
59
  return;
50
60
  return { backend, targetId, nonce };
51
61
  }
52
-
53
- class LeaseConflictError extends Error {
54
- targetId;
55
- holder;
56
- constructor(message, targetId, holder) {
57
- super(message);
58
- this.targetId = targetId;
59
- this.holder = holder;
60
- this.name = "LeaseConflictError";
61
- }
62
- }
63
62
  async function readLease(backend, targetId) {
64
63
  let raw;
65
64
  try {
@@ -150,7 +149,6 @@ async function releaseLeaseFor(backend, targetId) {
150
149
  });
151
150
  return { released: true };
152
151
  }
153
- var leaseScope = new AsyncLocalStorage;
154
152
  function withLeaseScope(lease, fn) {
155
153
  return leaseScope.run(lease, fn);
156
154
  }
@@ -217,7 +215,6 @@ async function assertLeaseOk(backend, targetId, ctx = {}) {
217
215
  }
218
216
  await touchLease(held, now);
219
217
  }
220
- var LEASE_FILE_RE = /^lease-(chrome|firefox)-(.+)\.json$/;
221
218
  async function listLeases(opts = {}) {
222
219
  const now = opts.now ?? Date.now();
223
220
  let names = [];
@@ -275,6 +272,21 @@ async function listLeases(opts = {}) {
275
272
  }
276
273
  return out;
277
274
  }
275
+ var DEFAULT_LEASE_TTL_MS = 900000, longLived = false, LeaseConflictError, leaseScope, LEASE_FILE_RE;
276
+ var init_leases = __esm(() => {
277
+ LeaseConflictError = class LeaseConflictError extends Error {
278
+ targetId;
279
+ holder;
280
+ constructor(message, targetId, holder) {
281
+ super(message);
282
+ this.targetId = targetId;
283
+ this.holder = holder;
284
+ this.name = "LeaseConflictError";
285
+ }
286
+ };
287
+ leaseScope = new AsyncLocalStorage;
288
+ LEASE_FILE_RE = /^lease-(chrome|firefox)-(.+)\.json$/;
289
+ });
278
290
 
279
291
  // src/origins.ts
280
292
  import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
@@ -285,7 +297,6 @@ function safeId2(id) {
285
297
  function originFile(backend, targetId) {
286
298
  return join2(leaseDir(), `origin-${backend}-${safeId2(targetId)}.json`);
287
299
  }
288
- var ORIGIN_FILE_RE = /^origin-(chrome|firefox)-(.+)\.json$/;
289
300
  async function recordOrigin(backend, targetId, opts = {}) {
290
301
  const record = {
291
302
  backend,
@@ -401,16 +412,13 @@ async function resolveLiveLabel(backend, label, liveIds) {
401
412
  }
402
413
  return { matchIds: [...matchIds], knownLabels: [...knownLabels].sort() };
403
414
  }
415
+ var ORIGIN_FILE_RE;
416
+ var init_origins = __esm(() => {
417
+ init_leases();
418
+ ORIGIN_FILE_RE = /^origin-(chrome|firefox)-(.+)\.json$/;
419
+ });
404
420
 
405
421
  // src/workers.ts
406
- var WORKER_SELECTOR_PREFIX = "worker:";
407
- var WORKER_CAPABLE_TOOLS = [
408
- "evaluate_script",
409
- "list_network_requests",
410
- "get_network_request",
411
- "list_console_messages"
412
- ];
413
- var WORKER_TARGET_TYPES = new Set(["service_worker", "shared_worker"]);
414
422
  function isWorkerSelector(selector) {
415
423
  return typeof selector === "string" && selector.startsWith(WORKER_SELECTOR_PREFIX);
416
424
  }
@@ -427,9 +435,6 @@ function resolveWorkerTargets(targets, needle) {
427
435
  liveWorkers
428
436
  };
429
437
  }
430
- var WORKER_EMPTY_NEEDLE_MESSAGE = "'worker:' needs a substring of the worker's url, e.g. worker:<extension-id> or worker:background.js";
431
- var WORKER_SELECTOR_UNSUPPORTED_MESSAGE = "target 'worker:<substring>' selects a service/shared worker, which this backend cannot address " + "(WebDriver BiDi has no extension service-worker target; Capability 'worker.targets' is Chrome-only). " + "Use --browser chrome to evaluate in, or record console/network from, an extension's background worker.";
432
- var WORKER_SELECTOR_PAGE_ONLY_MESSAGE = "target 'worker:<substring>' selects a service/shared worker, and this tool is page-only " + "(closing, selecting or releasing a worker is meaningless). The tools that accept a worker: target are " + `${WORKER_CAPABLE_TOOLS.join(", ")}.`;
433
438
  function workerWakeMisuseMessage(kind) {
434
439
  if (kind === "not-a-worker-selector") {
435
440
  return "'wake' only applies to a target of the form 'worker:<substring>'. A page is never asleep, and a bare " + "worker target id cannot be woken either: Chrome destroys the target when an MV3 worker is evicted and " + "mints a NEW id when it restarts, so only the url-substring form can name a worker that is not running.";
@@ -454,22 +459,20 @@ function workerMissMessage(needle, opts) {
454
459
  const scopes = opts.registeredScopes?.length ? ` Registered service-worker scopes in this browser: ${opts.registeredScopes.join(", ")}.` : " No service-worker registrations were reported by this browser at all.";
455
460
  return `no worker whose url contains '${needle}' could be reached${running}. ` + `A start was requested (wake:true) and no matching worker appeared.${scopes} ` + "If the extension is installed but its worker never starts, check the worker script for a top-level throw.";
456
461
  }
462
+ var WORKER_SELECTOR_PREFIX = "worker:", WORKER_CAPABLE_TOOLS, WORKER_TARGET_TYPES, WORKER_EMPTY_NEEDLE_MESSAGE = "'worker:' needs a substring of the worker's url, e.g. worker:<extension-id> or worker:background.js", WORKER_SELECTOR_UNSUPPORTED_MESSAGE, WORKER_SELECTOR_PAGE_ONLY_MESSAGE;
463
+ var init_workers = __esm(() => {
464
+ WORKER_CAPABLE_TOOLS = [
465
+ "evaluate_script",
466
+ "list_network_requests",
467
+ "get_network_request",
468
+ "list_console_messages"
469
+ ];
470
+ WORKER_TARGET_TYPES = new Set(["service_worker", "shared_worker"]);
471
+ WORKER_SELECTOR_UNSUPPORTED_MESSAGE = "target 'worker:<substring>' selects a service/shared worker, which this backend cannot address " + "(WebDriver BiDi has no extension service-worker target; Capability 'worker.targets' is Chrome-only). " + "Use --browser chrome to evaluate in, or record console/network from, an extension's background worker.";
472
+ WORKER_SELECTOR_PAGE_ONLY_MESSAGE = "target 'worker:<substring>' selects a service/shared worker, and this tool is page-only " + "(closing, selecting or releasing a worker is meaningless). The tools that accept a worker: target are " + `${WORKER_CAPABLE_TOOLS.join(", ")}.`;
473
+ });
457
474
 
458
475
  // src/client.ts
459
- var BASE = process.env.CDP_BASE ?? "http://127.0.0.1:9222";
460
- var DEFAULT_TIMEOUT_MS = Number(process.env.CDP_TIMEOUT_MS ?? 15000);
461
-
462
- class CdpError extends Error {
463
- code;
464
- data;
465
- constructor(message, code, data) {
466
- super(message);
467
- this.code = code;
468
- this.data = data;
469
- this.name = "CdpError";
470
- }
471
- }
472
-
473
476
  class CdpConnection {
474
477
  wsUrl;
475
478
  opts;
@@ -688,31 +691,29 @@ async function withPage(selector, fn, opts = {}) {
688
691
  conn.close();
689
692
  }
690
693
  }
694
+ var BASE, DEFAULT_TIMEOUT_MS, CdpError;
695
+ var init_client = __esm(() => {
696
+ init_leases();
697
+ init_origins();
698
+ init_workers();
699
+ BASE = process.env.CDP_BASE ?? "http://127.0.0.1:9222";
700
+ DEFAULT_TIMEOUT_MS = Number(process.env.CDP_TIMEOUT_MS ?? 15000);
701
+ CdpError = class CdpError extends Error {
702
+ code;
703
+ data;
704
+ constructor(message, code, data) {
705
+ super(message);
706
+ this.code = code;
707
+ this.data = data;
708
+ this.name = "CdpError";
709
+ }
710
+ };
711
+ });
691
712
 
692
713
  // src/activity.ts
693
- var BEACON_DATA_GLOBAL = "__cdpToolkitLastInput";
694
- var BEACON_INSTALLED_GLOBAL = "__cdpToolkitBeacon";
695
- var BEACON_EVENTS = ["pointerdown", "mousedown", "keydown", "wheel", "touchstart"];
696
- var BEACON_BODY = `
697
- if (!window.${BEACON_INSTALLED_GLOBAL}) {
698
- window.${BEACON_INSTALLED_GLOBAL} = true;
699
- var mark = function () { window.${BEACON_DATA_GLOBAL} = Date.now(); };
700
- var events = ${JSON.stringify([...BEACON_EVENTS])};
701
- for (var i = 0; i < events.length; i++) {
702
- window.addEventListener(events[i], mark, { capture: true, passive: true });
703
- }
704
- }`;
705
- var BEACON_SOURCE = `(function () {${BEACON_BODY}
706
- })();`;
707
- var BEACON_FUNCTION_DECLARATION = `function () {${BEACON_BODY}
708
- }`;
709
- var BEACON_READ_EXPRESSION = `(typeof window.${BEACON_DATA_GLOBAL} === "number" ? window.${BEACON_DATA_GLOBAL} : null)`;
710
- var DISPATCH_ATTRIBUTION_WINDOW_MS = 1500;
711
714
  function dispatchKey(backend, targetId) {
712
715
  return `${backend}:${targetId}`;
713
716
  }
714
- var dispatchLog = new Map;
715
- var DISPATCH_LOG_LIMIT = 512;
716
717
  function recordDispatch(backend, targetId, now = Date.now()) {
717
718
  const key = dispatchKey(backend, targetId);
718
719
  dispatchLog.delete(key);
@@ -724,7 +725,6 @@ function recordDispatch(backend, targetId, now = Date.now()) {
724
725
  dispatchLog.delete(oldest.value);
725
726
  }
726
727
  }
727
- var NON_SYNTHESIZING_INPUT_METHODS = new Set(["Input.setInterceptDrags", "Input.setIgnoreInputEvents"]);
728
728
  async function sendInput(conn, backend, targetId, method, params = {}) {
729
729
  if (!NON_SYNTHESIZING_INPUT_METHODS.has(method))
730
730
  recordDispatch(backend, targetId);
@@ -743,7 +743,6 @@ function humanActiveMs(beaconTs, dispatchAt, now = Date.now(), windowMs = DISPAT
743
743
  return null;
744
744
  return Math.max(0, now - beaconTs);
745
745
  }
746
- var CONTENTION_WINDOW_MS = 30000;
747
746
  function contentionWarning(ms, opts) {
748
747
  if (!opts.takeover)
749
748
  return;
@@ -765,8 +764,6 @@ async function readHumanActiveMs(driver, backend, targetId, now = Date.now()) {
765
764
  const beaconTs = await driver.readActivityBeacon(targetId).catch(() => null);
766
765
  return humanActiveMs(beaconTs, lastDispatchAt(backend, targetId), now);
767
766
  }
768
- var RENDERER_PROBE_TIMEOUT_MS = 500;
769
- var RENDERER_PROBE_EXPRESSION = `[1, ${BEACON_READ_EXPRESSION}]`;
770
767
  function rendererProbeSupported(driver) {
771
768
  return typeof driver.probeRenderer === "function";
772
769
  }
@@ -823,123 +820,27 @@ class BeaconSessions {
823
820
  } catch {}
824
821
  }
825
822
  }
826
-
827
- // src/tools/snapshot.ts
828
- var INTERACTIVE_ROLES = new Set([
829
- "button",
830
- "link",
831
- "textbox",
832
- "searchbox",
833
- "checkbox",
834
- "radio",
835
- "combobox",
836
- "listbox",
837
- "option",
838
- "menuitem",
839
- "menuitemcheckbox",
840
- "menuitemradio",
841
- "tab",
842
- "switch",
843
- "slider",
844
- "spinbutton",
845
- "textfield",
846
- "MenuItem",
847
- "Button"
848
- ]);
849
- async function resolveUid(conn, uid) {
850
- const { object } = await conn.send("DOM.resolveNode", {
851
- backendNodeId: uid
852
- });
853
- if (!object?.objectId) {
854
- throw new Error(`resolveUid: DOM.resolveNode returned no objectId for uid ${uid}`);
855
- }
856
- return { objectId: object.objectId };
857
- }
858
-
859
- // src/cdp/workers.ts
860
- var INVENTORY_FIRST_EVENT_MS = 1500;
861
- var INVENTORY_SETTLE_MS = 250;
862
- var WAKE_POLL_MS = 300;
863
- var WAKE_POLL_ATTEMPTS = 30;
864
- var NO_HOST_PAGE_MESSAGE = "cannot start a service worker: the ServiceWorker CDP domain is only reachable over a page session, " + "and this browser has no page target open. Open any tab (new_page) and retry — the tab does not have " + "to belong to the extension.";
865
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
866
- async function requestWorkerStart(needle) {
867
- const conn = await openBrowser();
868
- try {
869
- const host = (await listTargets()).find((t) => t.type === "page");
870
- if (!host)
871
- throw new CdpError(NO_HOST_PAGE_MESSAGE);
872
- const { sessionId } = await conn.send("Target.attachToTarget", {
873
- targetId: host.id,
874
- flatten: true
875
- });
876
- if (!sessionId)
877
- throw new CdpError("could not attach a session to host the ServiceWorker domain");
878
- const scopeById = new Map;
879
- const versions = [];
880
- conn.on("ServiceWorker.workerRegistrationUpdated", (params) => {
881
- for (const r of params.registrations ?? []) {
882
- if (r.isDeleted === true)
883
- continue;
884
- scopeById.set(String(r.registrationId), String(r.scopeURL ?? ""));
885
- }
886
- });
887
- conn.on("ServiceWorker.workerVersionUpdated", (params) => {
888
- for (const v of params.versions ?? []) {
889
- versions.push({ registrationId: String(v.registrationId), scriptURL: String(v.scriptURL ?? "") });
890
- }
891
- });
892
- await conn.send("ServiceWorker.enable", {}, { sessionId });
893
- await conn.waitFor("ServiceWorker.workerVersionUpdated", undefined, INVENTORY_FIRST_EVENT_MS).catch(() => {
894
- return;
895
- });
896
- await sleep(INVENTORY_SETTLE_MS);
897
- const scopes = [...new Set(scopeById.values())].filter((s) => s.length > 0).sort();
898
- const matched = new Set;
899
- for (const v of versions) {
900
- const scope = scopeById.get(v.registrationId);
901
- if (scope === undefined)
902
- continue;
903
- if (v.scriptURL.includes(needle) || scope.includes(needle))
904
- matched.add(scope);
905
- }
906
- if (matched.size === 0)
907
- return { startRequested: false, scopes };
908
- if (matched.size > 1) {
909
- throw new CdpError(`'worker:${needle}' matches more than one registered service-worker scope: ${[...matched].sort().join(", ")}. ` + "Narrow the substring.");
910
- }
911
- await conn.send("ServiceWorker.startWorker", { scopeURL: [...matched][0] }, { sessionId });
912
- return { startRequested: true, scopes };
913
- } finally {
914
- conn.close();
915
- }
916
- }
917
- async function resolveWorkerSelector(selector, opts) {
918
- const needle = workerNeedle(selector);
919
- if (needle === "")
920
- throw new CdpError(WORKER_EMPTY_NEEDLE_MESSAGE);
921
- const first = resolveWorkerTargets(await listTargets(), needle);
922
- if (first.matches.length > 1)
923
- throw new CdpError(workerAmbiguityMessage(needle, first.matches));
924
- if (first.matches.length === 1)
925
- return first.matches[0];
926
- if (!opts.wake) {
927
- throw new CdpError(workerMissMessage(needle, { wakeAttempted: false, liveWorkers: first.liveWorkers }));
928
- }
929
- const { startRequested, scopes } = await requestWorkerStart(needle);
930
- if (startRequested) {
931
- for (let i = 0;i < WAKE_POLL_ATTEMPTS; i++) {
932
- await sleep(WAKE_POLL_MS);
933
- const again = resolveWorkerTargets(await listTargets(), needle);
934
- if (again.matches.length > 1)
935
- throw new CdpError(workerAmbiguityMessage(needle, again.matches));
936
- if (again.matches.length === 1)
937
- return again.matches[0];
823
+ var BEACON_DATA_GLOBAL = "__cdpToolkitLastInput", BEACON_INSTALLED_GLOBAL = "__cdpToolkitBeacon", BEACON_EVENTS, BEACON_BODY, BEACON_SOURCE, BEACON_FUNCTION_DECLARATION, BEACON_READ_EXPRESSION, DISPATCH_ATTRIBUTION_WINDOW_MS = 1500, dispatchLog, DISPATCH_LOG_LIMIT = 512, NON_SYNTHESIZING_INPUT_METHODS, CONTENTION_WINDOW_MS = 30000, RENDERER_PROBE_TIMEOUT_MS = 500, RENDERER_PROBE_EXPRESSION;
824
+ var init_activity = __esm(() => {
825
+ BEACON_EVENTS = ["pointerdown", "mousedown", "keydown", "wheel", "touchstart"];
826
+ BEACON_BODY = `
827
+ if (!window.${BEACON_INSTALLED_GLOBAL}) {
828
+ window.${BEACON_INSTALLED_GLOBAL} = true;
829
+ var mark = function () { window.${BEACON_DATA_GLOBAL} = Date.now(); };
830
+ var events = ${JSON.stringify([...BEACON_EVENTS])};
831
+ for (var i = 0; i < events.length; i++) {
832
+ window.addEventListener(events[i], mark, { capture: true, passive: true });
938
833
  }
939
- }
940
- const final = resolveWorkerTargets(await listTargets(), needle);
941
- throw new CdpError(workerMissMessage(needle, { wakeAttempted: true, liveWorkers: final.liveWorkers, registeredScopes: scopes }));
942
- }
834
+ }`;
835
+ BEACON_SOURCE = `(function () {${BEACON_BODY}
836
+ })();`;
837
+ BEACON_FUNCTION_DECLARATION = `function () {${BEACON_BODY}
838
+ }`;
839
+ BEACON_READ_EXPRESSION = `(typeof window.${BEACON_DATA_GLOBAL} === "number" ? window.${BEACON_DATA_GLOBAL} : null)`;
840
+ dispatchLog = new Map;
841
+ NON_SYNTHESIZING_INPUT_METHODS = new Set(["Input.setInterceptDrags", "Input.setIgnoreInputEvents"]);
842
+ RENDERER_PROBE_EXPRESSION = `[1, ${BEACON_READ_EXPRESSION}]`;
843
+ });
943
844
 
944
845
  // src/tools/network_mock.ts
945
846
  function escapeRegExpChar(ch) {
@@ -991,7 +892,6 @@ function effectiveAction(rule, rnd) {
991
892
  return "fail";
992
893
  return rule.action;
993
894
  }
994
- var sessions = new Map;
995
895
  function delay(ms) {
996
896
  return new Promise((r) => setTimeout(r, ms));
997
897
  }
@@ -1117,28 +1017,15 @@ async function clearMocks(args = {}) {
1117
1017
  }
1118
1018
  return { cleared };
1119
1019
  }
1020
+ var sessions;
1021
+ var init_network_mock = __esm(() => {
1022
+ init_client();
1023
+ sessions = new Map;
1024
+ });
1120
1025
 
1121
1026
  // src/driver.ts
1122
1027
  import { mkdir as mkdir3, readFile as readFile3, unlink as unlink3, writeFile as writeFile3 } from "node:fs/promises";
1123
1028
  import { join as join3 } from "node:path";
1124
- var UID_STAMP_ATTR = "data-cdp-uid";
1125
- var LEGACY_NUMERIC_UID = /^[0-9]+$/;
1126
- var REQUIRED_CAPABILITIES = {
1127
- performance_start_trace: ["trace.performance"],
1128
- performance_stop_trace: ["trace.performance"],
1129
- performance_analyze_insight: ["trace.performance"],
1130
- performance_trace: ["trace.performance"],
1131
- take_heapsnapshot: ["heap.snapshot"],
1132
- lighthouse_audit: ["audit.lighthouse"],
1133
- start_screen_recording: ["capture.screencast"],
1134
- stop_screen_recording: ["capture.screencast"],
1135
- mock_request: ["network.intercept"],
1136
- list_mocks: ["network.intercept"],
1137
- clear_mocks: ["network.intercept"],
1138
- dispatch_mouse: ["input.raw"],
1139
- wait_for_download: ["browser.downloads"],
1140
- grant_permissions: ["browser.permissions"]
1141
- };
1142
1029
  function isDriverError(e) {
1143
1030
  return e instanceof Error && typeof e.code === "string";
1144
1031
  }
@@ -1185,8 +1072,156 @@ async function clearViewportRecord(scheme, targetId) {
1185
1072
  await unlink3(viewportRecordFile(scheme, targetId));
1186
1073
  } catch {}
1187
1074
  }
1075
+ var UID_STAMP_ATTR = "data-cdp-uid", LEGACY_NUMERIC_UID, REQUIRED_CAPABILITIES;
1076
+ var init_driver = __esm(() => {
1077
+ init_leases();
1078
+ LEGACY_NUMERIC_UID = /^[0-9]+$/;
1079
+ REQUIRED_CAPABILITIES = {
1080
+ performance_start_trace: ["trace.performance"],
1081
+ performance_stop_trace: ["trace.performance"],
1082
+ performance_analyze_insight: ["trace.performance"],
1083
+ performance_trace: ["trace.performance"],
1084
+ take_heapsnapshot: ["heap.snapshot"],
1085
+ lighthouse_audit: ["audit.lighthouse"],
1086
+ start_screen_recording: ["capture.screencast"],
1087
+ stop_screen_recording: ["capture.screencast"],
1088
+ mock_request: ["network.intercept"],
1089
+ list_mocks: ["network.intercept"],
1090
+ clear_mocks: ["network.intercept"],
1091
+ dispatch_mouse: ["input.raw"],
1092
+ wait_for_download: ["browser.downloads"],
1093
+ grant_permissions: ["browser.permissions"]
1094
+ };
1095
+ });
1096
+
1097
+ // src/cdp/driver.ts
1098
+ init_client();
1099
+ init_leases();
1100
+ init_activity();
1101
+
1102
+ // src/tools/snapshot.ts
1103
+ init_client();
1104
+ var INTERACTIVE_ROLES = new Set([
1105
+ "button",
1106
+ "link",
1107
+ "textbox",
1108
+ "searchbox",
1109
+ "checkbox",
1110
+ "radio",
1111
+ "combobox",
1112
+ "listbox",
1113
+ "option",
1114
+ "menuitem",
1115
+ "menuitemcheckbox",
1116
+ "menuitemradio",
1117
+ "tab",
1118
+ "switch",
1119
+ "slider",
1120
+ "spinbutton",
1121
+ "textfield",
1122
+ "MenuItem",
1123
+ "Button"
1124
+ ]);
1125
+ async function resolveUid(conn, uid) {
1126
+ const { object } = await conn.send("DOM.resolveNode", {
1127
+ backendNodeId: uid
1128
+ });
1129
+ if (!object?.objectId) {
1130
+ throw new Error(`resolveUid: DOM.resolveNode returned no objectId for uid ${uid}`);
1131
+ }
1132
+ return { objectId: object.objectId };
1133
+ }
1134
+
1135
+ // src/cdp/workers.ts
1136
+ init_client();
1137
+ init_workers();
1138
+ var INVENTORY_FIRST_EVENT_MS = 1500;
1139
+ var INVENTORY_SETTLE_MS = 250;
1140
+ var WAKE_POLL_MS = 300;
1141
+ var WAKE_POLL_ATTEMPTS = 30;
1142
+ var NO_HOST_PAGE_MESSAGE = "cannot start a service worker: the ServiceWorker CDP domain is only reachable over a page session, " + "and this browser has no page target open. Open any tab (new_page) and retry — the tab does not have " + "to belong to the extension.";
1143
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
1144
+ async function requestWorkerStart(needle) {
1145
+ const conn = await openBrowser();
1146
+ try {
1147
+ const host = (await listTargets()).find((t) => t.type === "page");
1148
+ if (!host)
1149
+ throw new CdpError(NO_HOST_PAGE_MESSAGE);
1150
+ const { sessionId } = await conn.send("Target.attachToTarget", {
1151
+ targetId: host.id,
1152
+ flatten: true
1153
+ });
1154
+ if (!sessionId)
1155
+ throw new CdpError("could not attach a session to host the ServiceWorker domain");
1156
+ const scopeById = new Map;
1157
+ const versions = [];
1158
+ conn.on("ServiceWorker.workerRegistrationUpdated", (params) => {
1159
+ for (const r of params.registrations ?? []) {
1160
+ if (r.isDeleted === true)
1161
+ continue;
1162
+ scopeById.set(String(r.registrationId), String(r.scopeURL ?? ""));
1163
+ }
1164
+ });
1165
+ conn.on("ServiceWorker.workerVersionUpdated", (params) => {
1166
+ for (const v of params.versions ?? []) {
1167
+ versions.push({ registrationId: String(v.registrationId), scriptURL: String(v.scriptURL ?? "") });
1168
+ }
1169
+ });
1170
+ await conn.send("ServiceWorker.enable", {}, { sessionId });
1171
+ await conn.waitFor("ServiceWorker.workerVersionUpdated", undefined, INVENTORY_FIRST_EVENT_MS).catch(() => {
1172
+ return;
1173
+ });
1174
+ await sleep(INVENTORY_SETTLE_MS);
1175
+ const scopes = [...new Set(scopeById.values())].filter((s) => s.length > 0).sort();
1176
+ const matched = new Set;
1177
+ for (const v of versions) {
1178
+ const scope = scopeById.get(v.registrationId);
1179
+ if (scope === undefined)
1180
+ continue;
1181
+ if (v.scriptURL.includes(needle) || scope.includes(needle))
1182
+ matched.add(scope);
1183
+ }
1184
+ if (matched.size === 0)
1185
+ return { startRequested: false, scopes };
1186
+ if (matched.size > 1) {
1187
+ throw new CdpError(`'worker:${needle}' matches more than one registered service-worker scope: ${[...matched].sort().join(", ")}. ` + "Narrow the substring.");
1188
+ }
1189
+ await conn.send("ServiceWorker.startWorker", { scopeURL: [...matched][0] }, { sessionId });
1190
+ return { startRequested: true, scopes };
1191
+ } finally {
1192
+ conn.close();
1193
+ }
1194
+ }
1195
+ async function resolveWorkerSelector(selector, opts) {
1196
+ const needle = workerNeedle(selector);
1197
+ if (needle === "")
1198
+ throw new CdpError(WORKER_EMPTY_NEEDLE_MESSAGE);
1199
+ const first = resolveWorkerTargets(await listTargets(), needle);
1200
+ if (first.matches.length > 1)
1201
+ throw new CdpError(workerAmbiguityMessage(needle, first.matches));
1202
+ if (first.matches.length === 1)
1203
+ return first.matches[0];
1204
+ if (!opts.wake) {
1205
+ throw new CdpError(workerMissMessage(needle, { wakeAttempted: false, liveWorkers: first.liveWorkers }));
1206
+ }
1207
+ const { startRequested, scopes } = await requestWorkerStart(needle);
1208
+ if (startRequested) {
1209
+ for (let i = 0;i < WAKE_POLL_ATTEMPTS; i++) {
1210
+ await sleep(WAKE_POLL_MS);
1211
+ const again = resolveWorkerTargets(await listTargets(), needle);
1212
+ if (again.matches.length > 1)
1213
+ throw new CdpError(workerAmbiguityMessage(needle, again.matches));
1214
+ if (again.matches.length === 1)
1215
+ return again.matches[0];
1216
+ }
1217
+ }
1218
+ const final = resolveWorkerTargets(await listTargets(), needle);
1219
+ throw new CdpError(workerMissMessage(needle, { wakeAttempted: true, liveWorkers: final.liveWorkers, registeredScopes: scopes }));
1220
+ }
1188
1221
 
1189
1222
  // src/cdp/driver.ts
1223
+ init_network_mock();
1224
+ init_driver();
1190
1225
  function driverError(code, message, data) {
1191
1226
  return Object.assign(new Error(message), { code, ...data !== undefined ? { data } : {} });
1192
1227
  }
@@ -1249,12 +1284,12 @@ async function awaitScrollSettle(conn) {
1249
1284
  return;
1250
1285
  });
1251
1286
  }
1252
- async function setValueOnObject(conn, objectId, value, sendInput2) {
1287
+ async function setValueOnObject(conn, objectId, value, sendInput) {
1253
1288
  await focusElement(conn, objectId);
1254
1289
  const fn = "function(){if('value'in this){this.value='';this.dispatchEvent(new Event('input',{bubbles:true}));}else if(this.isContentEditable){this.textContent='';}}";
1255
1290
  await conn.send("Runtime.callFunctionOn", { objectId, functionDeclaration: fn, returnByValue: true });
1256
1291
  if (value.length)
1257
- await sendInput2("Input.insertText", { text: value });
1292
+ await sendInput("Input.insertText", { text: value });
1258
1293
  }
1259
1294
  var NAMED_KEYS = {
1260
1295
  enter: { key: "Enter", code: "Enter", keyCode: 13, text: "\r" },
@@ -2287,7 +2322,13 @@ function createCdpDriver() {
2287
2322
  return new CdpBrowserDriver;
2288
2323
  }
2289
2324
 
2325
+ // src/leases-tools.ts
2326
+ init_activity();
2327
+ init_origins();
2328
+
2290
2329
  // src/reap.ts
2330
+ init_leases();
2331
+ init_origins();
2291
2332
  function staleAgentTabs(input) {
2292
2333
  const live = new Set(input.livePageIds);
2293
2334
  const out = [];
@@ -2334,6 +2375,7 @@ async function reapStaleAgentTabs(driver, backend) {
2334
2375
  }
2335
2376
 
2336
2377
  // src/shared-tools.ts
2378
+ init_driver();
2337
2379
  import { mkdir as mkdir5, writeFile as writeFile4 } from "node:fs/promises";
2338
2380
  import { dirname as dirname2, join as join4 } from "node:path";
2339
2381
 
@@ -2850,6 +2892,10 @@ async function stitchInto(fh, bands) {
2850
2892
  }
2851
2893
 
2852
2894
  // src/shared-tools.ts
2895
+ init_leases();
2896
+ init_activity();
2897
+ init_origins();
2898
+ init_workers();
2853
2899
  var ARTIFACT_DIR = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
2854
2900
  var STATE_DIR = process.env.CDP_STATE_DIR ?? "/tmp/cdp-toolkit";
2855
2901
 
@@ -3581,6 +3627,8 @@ var SHARED_TOOLS = {
3581
3627
  };
3582
3628
 
3583
3629
  // src/leases-tools.ts
3630
+ init_leases();
3631
+
3584
3632
  class LeaseToolError extends Error {
3585
3633
  }
3586
3634
  function backendOf2(driver) {
@@ -3696,10 +3744,13 @@ var LEASE_TOOLS = {
3696
3744
  };
3697
3745
 
3698
3746
  // src/tools/console.ts
3747
+ init_client();
3699
3748
  import { readFile as readFile4 } from "node:fs/promises";
3700
3749
 
3701
3750
  // src/tools/recorder.ts
3751
+ init_client();
3702
3752
  import { mkdir as mkdir6, appendFile, writeFile as writeFile5, copyFile } from "node:fs/promises";
3753
+ init_workers();
3703
3754
  function artifactDir() {
3704
3755
  return process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
3705
3756
  }
@@ -3926,11 +3977,11 @@ async function listConsoleMessages(args = {}) {
3926
3977
  if (args.reload) {
3927
3978
  const cap = await captureWindow(args.target, args.durationMs ?? DEFAULT_CAPTURE_MS, { wake: args.wake });
3928
3979
  await cap.stop();
3929
- const messages2 = await readConsoleEntries(cap.file);
3980
+ const messages = await readConsoleEntries(cap.file);
3930
3981
  return {
3931
3982
  target: cap.resolved,
3932
- count: messages2.length,
3933
- messages: messages2,
3983
+ count: messages.length,
3984
+ messages,
3934
3985
  droppedWrites: cap.droppedWrites()
3935
3986
  };
3936
3987
  }
@@ -3954,6 +4005,7 @@ async function getConsoleMessage(args = {}) {
3954
4005
  }
3955
4006
 
3956
4007
  // src/tools/network.ts
4008
+ init_client();
3957
4009
  import { readFile as readFile5 } from "node:fs/promises";
3958
4010
  var DEFAULT_CAPTURE_MS2 = 2500;
3959
4011
  function asHeaders(v) {
@@ -4075,15 +4127,15 @@ async function getNetworkRequest(args = {}) {
4075
4127
  const cap = await captureWindow(args.target, args.durationMs ?? DEFAULT_CAPTURE_MS2, { wake: args.wake });
4076
4128
  try {
4077
4129
  await cap.flush();
4078
- const match2 = (await readNetworkRequests(cap.file)).find((r) => r.url.includes(args.url));
4079
- if (!match2) {
4130
+ const match = (await readNetworkRequests(cap.file)).find((r) => r.url.includes(args.url));
4131
+ if (!match) {
4080
4132
  throw new CdpError(`no network request matched ${describeSelector()} in fresh capture`);
4081
4133
  }
4082
4134
  try {
4083
- const { body, base64Encoded } = await cap.conn.send("Network.getResponseBody", { requestId: match2.requestId });
4084
- return { ...match2, body, bodyBase64Encoded: base64Encoded };
4135
+ const { body, base64Encoded } = await cap.conn.send("Network.getResponseBody", { requestId: match.requestId });
4136
+ return { ...match, body, bodyBase64Encoded: base64Encoded };
4085
4137
  } catch {
4086
- return { ...match2, body: undefined, bodyBase64Encoded: undefined };
4138
+ return { ...match, body: undefined, bodyBase64Encoded: undefined };
4087
4139
  }
4088
4140
  } finally {
4089
4141
  await cap.stop();
@@ -4105,6 +4157,7 @@ async function getNetworkRequest(args = {}) {
4105
4157
  }
4106
4158
 
4107
4159
  // src/tools/performance.ts
4160
+ init_client();
4108
4161
  import { mkdir as mkdir7, readFile as readFile6, writeFile as writeFile6, stat, unlink as unlink4 } from "node:fs/promises";
4109
4162
  import { join as join5 } from "node:path";
4110
4163
  var ARTIFACT_DIR2 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
@@ -4337,6 +4390,7 @@ async function performanceAnalyzeInsight(args = {}) {
4337
4390
  }
4338
4391
 
4339
4392
  // src/tools/screencast.ts
4393
+ init_client();
4340
4394
  import { spawn } from "node:child_process";
4341
4395
  import { mkdir as mkdir8, rm as rm2, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
4342
4396
  import { join as join6 } from "node:path";
@@ -4701,6 +4755,7 @@ ffmpeg said: ${res.stderr.trim().slice(0, 800)}`);
4701
4755
  }
4702
4756
 
4703
4757
  // src/tools/heap.ts
4758
+ init_client();
4704
4759
  import { mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
4705
4760
  import { join as join7 } from "node:path";
4706
4761
  var ARTIFACT_DIR4 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
@@ -4741,6 +4796,7 @@ async function takeHeapsnapshot(args = {}) {
4741
4796
  }
4742
4797
 
4743
4798
  // src/tools/lighthouse.ts
4799
+ init_client();
4744
4800
  import { spawn as spawn2 } from "node:child_process";
4745
4801
  import { mkdir as mkdir10, readFile as readFile7, stat as stat3 } from "node:fs/promises";
4746
4802
  var ARTIFACT_DIR5 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
@@ -4876,7 +4932,12 @@ function truncate(s, max = 600) {
4876
4932
  return t.length > max ? `${t.slice(0, max)}…` : t;
4877
4933
  }
4878
4934
 
4935
+ // src/index.ts
4936
+ init_network_mock();
4937
+
4879
4938
  // src/tools/dispatch-mouse.ts
4939
+ init_activity();
4940
+ init_client();
4880
4941
  var CLICK_MODIFIER_BITS2 = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
4881
4942
  var BUTTONS = new Set(["left", "right", "middle"]);
4882
4943
  var CDP_EVENT_TYPE = {
@@ -4919,10 +4980,12 @@ async function dispatchMouse(args) {
4919
4980
  }
4920
4981
 
4921
4982
  // src/tools/downloads.ts
4983
+ init_client();
4922
4984
  import { readdir as readdir3, rename as rename2, stat as stat4 } from "node:fs/promises";
4923
4985
  import { basename, extname, join as join9 } from "node:path";
4924
4986
 
4925
4987
  // src/tools/browser-session.ts
4988
+ init_client();
4926
4989
  import { mkdir as mkdir11 } from "node:fs/promises";
4927
4990
  import { join as join8 } from "node:path";
4928
4991
  var ARTIFACT_DIR6 = process.env.CDP_ARTIFACT_DIR ?? "/tmp/cdp-toolkit";
@@ -5095,6 +5158,7 @@ async function waitForDownload(args = {}) {
5095
5158
  }
5096
5159
 
5097
5160
  // src/tools/permissions.ts
5161
+ init_client();
5098
5162
  function originOf(url) {
5099
5163
  try {
5100
5164
  const o = new URL(url).origin;
@@ -5144,6 +5208,7 @@ async function grantPermissions(args = {}) {
5144
5208
  }
5145
5209
 
5146
5210
  // src/index.ts
5211
+ init_client();
5147
5212
  var cdpDriver = createCdpDriver();
5148
5213
  function onCdp(fn) {
5149
5214
  return (args) => fn(cdpDriver, args);