@crouton-kit/capture 1.3.7 → 1.3.9

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.
Files changed (141) hide show
  1. package/bin/capture +32786 -9989
  2. package/package.json +9 -3
  3. package/src/capture.ts +86 -163
  4. package/src/cdp/a11y.ts +113 -14
  5. package/src/cdp/args.ts +300 -116
  6. package/src/cdp/bridge/protocol.ts +187 -1
  7. package/src/cdp/bridge/server.ts +211 -84
  8. package/src/cdp/bridge/spawn.ts +110 -1
  9. package/src/cdp/client.ts +13 -3
  10. package/src/cdp/commands/bridge-serve.ts +35 -4
  11. package/src/cdp/commands/cdp.ts +266 -69
  12. package/src/cdp/commands/gate-guard.ts +43 -0
  13. package/src/cdp/commands/lib.ts +339 -213
  14. package/src/cdp/commands/measure/census.ts +87 -0
  15. package/src/cdp/commands/measure/check.ts +109 -0
  16. package/src/cdp/commands/measure/diff.ts +120 -0
  17. package/src/cdp/commands/measure/explain.ts +133 -0
  18. package/src/cdp/commands/measure/index.ts +106 -0
  19. package/src/cdp/commands/measure/map-ax.ts +52 -0
  20. package/src/cdp/commands/measure/map-focus.ts +52 -0
  21. package/src/cdp/commands/measure/map-layers.ts +59 -0
  22. package/src/cdp/commands/measure/map-scroll.ts +94 -0
  23. package/src/cdp/commands/measure/snap.ts +416 -0
  24. package/src/cdp/commands/measure/sweep.ts +227 -0
  25. package/src/cdp/commands/motion/index.ts +61 -0
  26. package/src/cdp/commands/motion/jank.ts +132 -0
  27. package/src/cdp/commands/motion/mask.ts +92 -0
  28. package/src/cdp/commands/motion/rec.ts +534 -0
  29. package/src/cdp/commands/motion/response.ts +76 -0
  30. package/src/cdp/commands/motion/timeline.ts +152 -0
  31. package/src/cdp/commands/page/click.ts +194 -0
  32. package/src/cdp/commands/page/elements.ts +154 -0
  33. package/src/cdp/commands/page/exec.ts +317 -0
  34. package/src/cdp/commands/page/index.ts +72 -0
  35. package/src/cdp/commands/page/navigate.ts +330 -0
  36. package/src/cdp/commands/page/scroll.ts +107 -0
  37. package/src/cdp/commands/page/shot.ts +208 -0
  38. package/src/cdp/commands/page/type.ts +104 -0
  39. package/src/cdp/commands/tab/index.ts +59 -0
  40. package/src/cdp/commands/tab/list.ts +167 -0
  41. package/src/cdp/commands/tab/network.ts +162 -0
  42. package/src/cdp/commands/tab/open.ts +90 -0
  43. package/src/cdp/commands/tab/reset.ts +160 -0
  44. package/src/cdp/connection.ts +368 -37
  45. package/src/cdp/coordinates.ts +158 -0
  46. package/src/cdp/detect.ts +42 -13
  47. package/src/cdp/dispatch.ts +76 -26
  48. package/src/cdp/domains.ts +75 -0
  49. package/src/cdp/har-recorder.ts +648 -115
  50. package/src/cdp/leaf-grammar.ts +99 -0
  51. package/src/cdp/measure/census.ts +205 -0
  52. package/src/cdp/measure/check.ts +318 -0
  53. package/src/cdp/measure/collectors/animation.ts +385 -0
  54. package/src/cdp/measure/collectors/ax.ts +278 -0
  55. package/src/cdp/measure/collectors/focus.ts +1041 -0
  56. package/src/cdp/measure/collectors/forms.ts +905 -0
  57. package/src/cdp/measure/collectors/geometry.ts +1038 -0
  58. package/src/cdp/measure/collectors/hittest.ts +835 -0
  59. package/src/cdp/measure/collectors/layers.ts +697 -0
  60. package/src/cdp/measure/collectors/media.ts +522 -0
  61. package/src/cdp/measure/collectors/pixels.ts +1584 -0
  62. package/src/cdp/measure/collectors/queries.ts +464 -0
  63. package/src/cdp/measure/collectors/scroll.ts +599 -0
  64. package/src/cdp/measure/collectors/states.ts +992 -0
  65. package/src/cdp/measure/collectors/style-provenance.ts +643 -0
  66. package/src/cdp/measure/collectors/styles.ts +355 -0
  67. package/src/cdp/measure/collectors/text.ts +713 -0
  68. package/src/cdp/measure/diff.ts +470 -0
  69. package/src/cdp/measure/explain.ts +498 -0
  70. package/src/cdp/measure/map-ax.ts +633 -0
  71. package/src/cdp/measure/map-focus.ts +188 -0
  72. package/src/cdp/measure/map-layers.ts +177 -0
  73. package/src/cdp/measure/map-scroll.ts +317 -0
  74. package/src/cdp/measure/redaction.ts +51 -0
  75. package/src/cdp/measure/settle.ts +1051 -0
  76. package/src/cdp/measure/snapshot.ts +390 -0
  77. package/src/cdp/measure/sweep.ts +330 -0
  78. package/src/cdp/measure/types.ts +220 -0
  79. package/src/cdp/measure/v2/collectors.ts +19 -0
  80. package/src/cdp/measure/v2/orchestrator.ts +46 -0
  81. package/src/cdp/measure/v2/snap-selection.ts +33 -0
  82. package/src/cdp/measure/v2/target-lock.ts +15 -0
  83. package/src/cdp/measure/v2/target.ts +16 -0
  84. package/src/cdp/motion/jank.ts +433 -0
  85. package/src/cdp/motion/mask.ts +421 -0
  86. package/src/cdp/motion/recorder.ts +764 -0
  87. package/src/cdp/motion/response.ts +356 -0
  88. package/src/cdp/motion/timeline.ts +215 -0
  89. package/src/cdp/record.ts +5 -212
  90. package/src/cdp/recorder-bridge.ts +1894 -0
  91. package/src/cdp/recorder-client.ts +326 -0
  92. package/src/cdp/scope-lock.ts +73 -0
  93. package/src/cdp/screenshot.ts +199 -66
  94. package/src/cdp/source-map.ts +309 -0
  95. package/src/cdp/targets.ts +21 -1
  96. package/src/cdp/timing.ts +87 -0
  97. package/src/cdp/types.ts +87 -6
  98. package/src/cdp/viewport.ts +21 -0
  99. package/src/cdp.ts +12 -58
  100. package/src/command-help.ts +29 -0
  101. package/src/command-resolution.ts +22 -0
  102. package/src/command-walker.ts +35 -0
  103. package/src/contracts/a11y.ts +33 -0
  104. package/src/contracts/cursor.ts +35 -0
  105. package/src/contracts/index.ts +15 -0
  106. package/src/contracts/motion.ts +19 -0
  107. package/src/contracts/neutral.ts +56 -0
  108. package/src/contracts/primitives.ts +205 -0
  109. package/src/contracts/release.ts +17 -0
  110. package/src/contracts/results.ts +208 -0
  111. package/src/contracts/routes.ts +140 -0
  112. package/src/contracts/snapshot.ts +92 -0
  113. package/src/cursor/index.ts +13 -0
  114. package/src/cursor/service.ts +310 -0
  115. package/src/errors.ts +71 -0
  116. package/src/har-manager.ts +992 -41
  117. package/src/interact.ts +410 -98
  118. package/src/output/artifact-lifecycle.ts +371 -0
  119. package/src/output/artifact.ts +526 -0
  120. package/src/output/diff.ts +111 -0
  121. package/src/output/exact-raw.ts +114 -0
  122. package/src/output/render.ts +987 -0
  123. package/src/output/selector.ts +185 -0
  124. package/src/output/structured.ts +211 -0
  125. package/src/registry.ts +208 -0
  126. package/src/session/artifacts.ts +481 -0
  127. package/src/session/commands.ts +1237 -368
  128. package/src/session/coordinator.ts +251 -0
  129. package/src/session/har-filter.ts +57 -0
  130. package/src/session/log-tailer.ts +653 -0
  131. package/src/session-context.ts +302 -34
  132. package/src/vault/bundle.ts +32 -17
  133. package/src/cdp/commands/exec.ts +0 -105
  134. package/src/cdp/commands/har.ts +0 -128
  135. package/src/cdp/commands/tabs.ts +0 -183
  136. package/src/cdp/commands/traffic.ts +0 -121
  137. package/src/cdp/commands/ui.ts +0 -172
  138. package/src/cdp/execute.ts +0 -113
  139. package/src/cdp/har-output.ts +0 -47
  140. package/src/cdp/usage.ts +0 -77
  141. package/src/tab-session.ts +0 -91
package/src/cdp/record.ts CHANGED
@@ -1,223 +1,16 @@
1
1
  import { CDPClient } from './client.js';
2
- import { detectCdpPort } from './detect.js';
3
2
  import {
4
3
  findTab,
5
- findTabByIdAcrossEndpoints,
6
- findTabByUrlAcrossEndpoints,
7
4
  listTargets,
8
5
  openTab,
9
6
  type CDPTarget,
10
7
  } from './targets.js';
11
- import { HARRecorder } from './har-recorder.js';
12
- import { writeHarAndPrintSummary } from './har-output.js';
13
- import { type HAREntry } from '../har-manager.js';
14
-
15
- export interface RecordOptions {
16
- port?: number;
17
- targetId?: string;
18
- duration?: number;
19
- harOutPath?: string;
20
- }
21
-
22
- export interface RecordResult {
23
- harPath: string | undefined;
24
- entryCount: number;
25
- har: { log: { entries: HAREntry[] } };
26
- }
27
-
28
- export async function recordTraffic(
29
- options: RecordOptions,
30
- ): Promise<RecordResult> {
31
- let port = options.port ?? 0;
32
- const duration = options.duration ?? 10;
33
-
34
- if (!options.targetId) {
35
- throw new Error('Use --target <tabId> to target a tab. Run "capture list" to see available tabs.');
36
- }
37
-
38
- const resolved = await findTabByIdAcrossEndpoints(options.targetId, options.port);
39
- const tab = resolved?.tab ?? null;
40
- if (resolved) {
41
- port = resolved.port;
42
- }
43
- if (!tab) {
44
- throw new Error(
45
- `No tab found for target "${options.targetId}". Run "capture list" to see available tabs.`,
46
- );
47
- }
48
-
49
- if (!tab.webSocketDebuggerUrl) {
50
- throw new Error('Tab has no WebSocket debugger URL');
51
- }
52
-
53
- const client = new CDPClient(tab.webSocketDebuggerUrl);
54
- await client.waitReady();
55
-
56
- console.error(
57
- `Using target ${tab.id.slice(0, 8)} on port ${port} (${tab.url})`,
58
- );
59
-
60
- const recorder = new HARRecorder(client);
61
- await recorder.start();
62
-
63
- console.error(
64
- `Recording traffic on target ${tab.id.slice(0, 8)} on port ${port} (${tab.url}) for ${duration}s... (click around in the browser)`,
65
- );
66
-
67
- await new Promise((r) => setTimeout(r, duration * 1000));
68
-
69
- const har = await recorder.finish();
70
- const harPath = writeHarAndPrintSummary(har, options.harOutPath);
71
-
72
- client.close();
73
-
74
- return { harPath, entryCount: har.log.entries.length, har };
75
- }
76
-
77
- export interface NavigateAndRecordOptions {
78
- port?: number;
79
- url: string;
80
- targetId?: string;
81
- harOutPath?: string;
82
- settle?: number;
83
- }
84
-
85
- export interface NavigateAndRecordResult {
86
- harPath: string | undefined;
87
- entryCount: number;
88
- har: { log: { entries: HAREntry[] } };
89
- tab: CDPTarget;
90
- timedOut: boolean;
91
- }
92
-
93
- export async function navigateAndRecord(
94
- options: NavigateAndRecordOptions,
95
- ): Promise<NavigateAndRecordResult> {
96
- let requestedUrl: URL;
97
- try {
98
- requestedUrl = new URL(options.url);
99
- } catch {
100
- throw new Error(`Invalid URL: ${options.url}`);
101
- }
102
- const settle = options.settle ?? 2000;
103
-
104
- // Find tab — prefer exact target or an already-open matching URL across all endpoints.
105
- let port = options.port ?? 0;
106
- let tab: CDPTarget | null = null;
107
- let isNewTab = false;
108
-
109
- if (options.targetId) {
110
- const resolved = await findTabByIdAcrossEndpoints(options.targetId, options.port);
111
- if (!resolved) {
112
- throw new Error(
113
- `No tab found with target ID "${options.targetId}". Tab may have been closed.`,
114
- );
115
- }
116
- port = resolved.port;
117
- tab = resolved.tab;
118
- } else {
119
- const matched = await findTabByUrlAcrossEndpoints(options.url, options.port);
120
- if (matched) {
121
- port = matched.port;
122
- tab = matched.tab;
123
- } else {
124
- port = options.port ?? (await detectCdpPort());
125
- const domain = requestedUrl.hostname;
126
- tab = await findTab(port, domain);
127
- if (!tab) {
128
- tab = await openTab(port, options.url);
129
- isNewTab = true;
130
- }
131
- }
132
- }
133
- if (!tab.webSocketDebuggerUrl) {
134
- throw new Error('Tab has no WebSocket debugger URL');
135
- }
136
-
137
- const client = new CDPClient(tab.webSocketDebuggerUrl);
138
- await client.waitReady();
139
- await client.send('Page.enable');
140
-
141
- console.error(
142
- `Using target ${tab.id.slice(0, 8)} on port ${port} (${tab.url})`,
143
- );
144
-
145
- // Start recording BEFORE navigation
146
- const recorder = new HARRecorder(client);
147
- await recorder.start();
148
-
149
- if (!isNewTab) {
150
- // Navigate existing tab
151
- console.error(`Navigating to: ${options.url}`);
152
- const navResult = (await client.send('Page.navigate', {
153
- url: options.url,
154
- })) as { loaderId?: string; errorText?: string };
155
- // A fragment-only change against the current document is a same-document
156
- // navigation: Chrome updates location.hash but does NOT reload the page, so
157
- // SPAs that read the fragment on mount (e.g. Excalidraw's #url= scene import)
158
- // never see it. Same-document navigations return no loaderId. When that
159
- // happens, force a genuine cross-document load by bouncing through
160
- // about:blank and re-navigating, so the target URL (fragment included) is
161
- // delivered to a freshly-mounted document. A plain Page.reload here races
162
- // the still-committing fragment nav and can reload the pre-fragment URL.
163
- if (!navResult.loaderId) {
164
- await client.send('Page.navigate', { url: 'about:blank' });
165
- await client.send('Page.navigate', { url: options.url });
166
- }
167
- }
168
-
169
- const deadline = 60_000;
170
- const t0 = Date.now();
171
- let timedOut = false;
172
- let har!: { log: { entries: HAREntry[] } };
173
-
174
- try {
175
- await Promise.race([
176
- (async () => {
177
- // Wait for load event
178
- await new Promise<void>((resolve) => {
179
- const timer = setTimeout(() => {
180
- console.error('Page load timeout (10s), continuing with settle...');
181
- resolve();
182
- }, 10000);
183
- client.on('Page.loadEventFired', () => {
184
- clearTimeout(timer);
185
- resolve();
186
- });
187
- });
188
-
189
- // Settle time for SPAs that load after DOMContentLoaded
190
- console.error(`Settling for ${settle}ms...`);
191
- await new Promise((r) => setTimeout(r, settle));
192
-
193
- har = await recorder.finish();
194
- })(),
195
- new Promise<never>((_, reject) => {
196
- const t = setTimeout(() => reject(new Error('__navigate_timeout__')), deadline - (Date.now() - t0));
197
- // Don't keep process alive just for the deadline timer
198
- if (typeof t === 'object' && 'unref' in t) t.unref();
199
- }),
200
- ]);
201
- } catch (err) {
202
- if (err instanceof Error && err.message === '__navigate_timeout__') {
203
- timedOut = true;
204
- console.error('Navigate timeout (60s) — returning partial HAR');
205
- har = recorder.finishPartial();
206
- } else {
207
- throw err;
208
- }
209
- }
210
-
211
- const harPath = writeHarAndPrintSummary(har, options.harOutPath);
212
-
213
- client.close();
214
-
215
- // Refresh target info
216
- const updatedTab = (await findTab(port, options.url)) ?? tab;
217
-
218
- return { harPath, entryCount: har.log.entries.length, har, tab: updatedTab, timedOut };
219
- }
220
8
 
9
+ /**
10
+ * Opens (or reuses) a tab for `url` and waits for its load event — `tab open`'s
11
+ * load-wait helper. Navigation of an existing tab lives in
12
+ * `./commands/page/navigate.ts` via ordinary page targeting.
13
+ */
221
14
  export async function navigateAndWait(
222
15
  port: number,
223
16
  url: string,