@crouton-kit/capture 1.3.10 → 1.3.12

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/bin/capture CHANGED
@@ -8391,19 +8391,42 @@ async function navigateAndWait(port, url, options = {}) {
8391
8391
  throw new Error("New tab has no WebSocket debugger URL");
8392
8392
  }
8393
8393
  const client = new CDPClient(tab.webSocketDebuggerUrl);
8394
- await client.waitReady();
8395
- await client.send("Page.enable");
8396
- await new Promise((resolve11, reject) => {
8397
- const timer = setTimeout(
8398
- () => reject(new Error(`Page load timeout: ${url}`)),
8399
- timeout
8400
- );
8401
- client.on("Page.loadEventFired", () => {
8402
- clearTimeout(timer);
8403
- resolve11();
8394
+ try {
8395
+ await client.waitReady();
8396
+ await client.send("Page.enable");
8397
+ let timer;
8398
+ let loadHandler;
8399
+ let loadTimeoutError;
8400
+ let resolveLoad;
8401
+ const loadPromise = new Promise((resolve11) => {
8402
+ resolveLoad = resolve11;
8403
+ loadHandler = () => {
8404
+ if (timer) clearTimeout(timer);
8405
+ resolveLoad();
8406
+ };
8407
+ client.on("Page.loadEventFired", loadHandler);
8408
+ timer = setTimeout(() => {
8409
+ loadTimeoutError = new Error(`Page load timeout: ${url}`);
8410
+ resolveLoad();
8411
+ }, timeout);
8404
8412
  });
8405
- });
8406
- client.close();
8413
+ try {
8414
+ const result = await client.send("Runtime.evaluate", {
8415
+ expression: "document.readyState",
8416
+ returnByValue: true
8417
+ });
8418
+ const readyState = result?.result?.value;
8419
+ if (readyState !== "complete") {
8420
+ await loadPromise;
8421
+ if (loadTimeoutError) throw loadTimeoutError;
8422
+ }
8423
+ } finally {
8424
+ if (timer) clearTimeout(timer);
8425
+ if (loadHandler) client.off("Page.loadEventFired", loadHandler);
8426
+ }
8427
+ } finally {
8428
+ client.close();
8429
+ }
8407
8430
  const targets = await listTargets(port);
8408
8431
  const refreshed = targets.find((t) => t.id === tab.id);
8409
8432
  return refreshed ?? tab;
@@ -9799,7 +9822,7 @@ function validateHarAppendBatch(value, source) {
9799
9822
  return { entries, incompleteLifecycles };
9800
9823
  }
9801
9824
  function captureVersion() {
9802
- const version = "1.3.10";
9825
+ const version = "1.3.12";
9803
9826
  return typeof version === "string" && version.length > 0 ? version : "development";
9804
9827
  }
9805
9828
  function token() {
@@ -11558,7 +11581,7 @@ function wallTime(value) {
11558
11581
  }
11559
11582
  }
11560
11583
  function captureVersion2() {
11561
- const version = "1.3.10";
11584
+ const version = "1.3.12";
11562
11585
  return typeof version === "string" && version.length > 0 ? version : "development";
11563
11586
  }
11564
11587
  function deepFreeze(value) {
@@ -241019,7 +241042,7 @@ CDP_PORT / CDP_TARGET pin the browser + tab for orchestrators \u2014 precedence:
241019
241042
  explicit flag > active session > env.`;
241020
241043
  }
241021
241044
  function printVersion() {
241022
- const declared = "1.3.10";
241045
+ const declared = "1.3.12";
241023
241046
  if (declared) {
241024
241047
  console.log(declared);
241025
241048
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crouton-kit/capture",
3
- "version": "1.3.10",
3
+ "version": "1.3.12",
4
4
  "description": "Browser automation and UI validation via CDP — session-based screenshots, HAR, a11y, click/type, and JS exec",
5
5
  "bin": {
6
6
  "capture": "./bin/capture"
package/src/cdp/record.ts CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  findTab,
4
4
  listTargets,
5
5
  openTab,
6
- type CDPTarget,
7
6
  } from './targets.js';
7
+ import { type CDPTarget } from './types.js';
8
8
 
9
9
  /**
10
10
  * Opens (or reuses) a tab for `url` and waits for its load event — `tab open`'s
@@ -32,23 +32,49 @@ export async function navigateAndWait(
32
32
  throw new Error('New tab has no WebSocket debugger URL');
33
33
  }
34
34
 
35
- // Wait for page load
35
+ // Wait for page load. The client owns a page WebSocket, so close it even
36
+ // when connection, readiness, timeout, or target-refresh work fails.
36
37
  const client = new CDPClient(tab.webSocketDebuggerUrl);
37
- await client.waitReady();
38
- await client.send('Page.enable');
38
+ try {
39
+ await client.waitReady();
40
+ await client.send('Page.enable');
39
41
 
40
- await new Promise<void>((resolve, reject) => {
41
- const timer = setTimeout(
42
- () => reject(new Error(`Page load timeout: ${url}`)),
43
- timeout,
44
- );
45
- client.on('Page.loadEventFired', () => {
46
- clearTimeout(timer);
47
- resolve();
42
+ let timer: NodeJS.Timeout | undefined;
43
+ let loadHandler: ((params: unknown) => void) | undefined;
44
+ let loadTimeoutError: Error | undefined;
45
+ let resolveLoad!: () => void;
46
+ const loadPromise = new Promise<void>((resolve) => {
47
+ resolveLoad = resolve;
48
+ loadHandler = () => {
49
+ if (timer) clearTimeout(timer);
50
+ resolveLoad();
51
+ };
52
+ // Arm the event before checking readyState: the load event may fire
53
+ // while the readiness query is in flight.
54
+ client.on('Page.loadEventFired', loadHandler);
55
+ timer = setTimeout(() => {
56
+ loadTimeoutError = new Error(`Page load timeout: ${url}`);
57
+ resolveLoad();
58
+ }, timeout);
48
59
  });
49
- });
50
60
 
51
- client.close();
61
+ try {
62
+ const result = await client.send('Runtime.evaluate', {
63
+ expression: 'document.readyState',
64
+ returnByValue: true,
65
+ });
66
+ const readyState = (result as { result?: { value?: unknown } } | undefined)?.result?.value;
67
+ if (readyState !== 'complete') {
68
+ await loadPromise;
69
+ if (loadTimeoutError) throw loadTimeoutError;
70
+ }
71
+ } finally {
72
+ if (timer) clearTimeout(timer);
73
+ if (loadHandler) client.off('Page.loadEventFired', loadHandler);
74
+ }
75
+ } finally {
76
+ client.close();
77
+ }
52
78
 
53
79
  // Refresh target info — find by ID to avoid returning a different tab with same URL
54
80
  const targets = await listTargets(port);