browser-debugger-cli 0.0.1-alpha.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.
Files changed (58) hide show
  1. package/README.md +85 -0
  2. package/dist/collectors/console.d.ts +17 -0
  3. package/dist/collectors/console.d.ts.map +1 -0
  4. package/dist/collectors/console.js +65 -0
  5. package/dist/collectors/console.js.map +1 -0
  6. package/dist/collectors/dom.d.ts +21 -0
  7. package/dist/collectors/dom.d.ts.map +1 -0
  8. package/dist/collectors/dom.js +88 -0
  9. package/dist/collectors/dom.js.map +1 -0
  10. package/dist/collectors/network.d.ts +19 -0
  11. package/dist/collectors/network.d.ts.map +1 -0
  12. package/dist/collectors/network.js +114 -0
  13. package/dist/collectors/network.js.map +1 -0
  14. package/dist/connection/cdp.d.ts +99 -0
  15. package/dist/connection/cdp.d.ts.map +1 -0
  16. package/dist/connection/cdp.js +317 -0
  17. package/dist/connection/cdp.js.map +1 -0
  18. package/dist/connection/finder.d.ts +11 -0
  19. package/dist/connection/finder.d.ts.map +1 -0
  20. package/dist/connection/finder.js +23 -0
  21. package/dist/connection/finder.js.map +1 -0
  22. package/dist/connection/launcher.d.ts +30 -0
  23. package/dist/connection/launcher.d.ts.map +1 -0
  24. package/dist/connection/launcher.js +134 -0
  25. package/dist/connection/launcher.js.map +1 -0
  26. package/dist/connection/tabs.d.ts +49 -0
  27. package/dist/connection/tabs.d.ts.map +1 -0
  28. package/dist/connection/tabs.js +216 -0
  29. package/dist/connection/tabs.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +431 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/session/BdgSession.d.ts +62 -0
  35. package/dist/session/BdgSession.d.ts.map +1 -0
  36. package/dist/session/BdgSession.js +172 -0
  37. package/dist/session/BdgSession.js.map +1 -0
  38. package/dist/types.d.ts +159 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/utils/pageLoad.d.ts +21 -0
  43. package/dist/utils/pageLoad.d.ts.map +1 -0
  44. package/dist/utils/pageLoad.js +85 -0
  45. package/dist/utils/pageLoad.js.map +1 -0
  46. package/dist/utils/session.d.ts +104 -0
  47. package/dist/utils/session.d.ts.map +1 -0
  48. package/dist/utils/session.js +244 -0
  49. package/dist/utils/session.js.map +1 -0
  50. package/dist/utils/url.d.ts +6 -0
  51. package/dist/utils/url.d.ts.map +1 -0
  52. package/dist/utils/url.js +11 -0
  53. package/dist/utils/url.js.map +1 -0
  54. package/dist/utils/validation.d.ts +12 -0
  55. package/dist/utils/validation.d.ts.map +1 -0
  56. package/dist/utils/validation.js +20 -0
  57. package/dist/utils/validation.js.map +1 -0
  58. package/package.json +56 -0
@@ -0,0 +1,317 @@
1
+ import WebSocket from 'ws';
2
+ /**
3
+ * Chrome DevTools Protocol WebSocket connection manager.
4
+ *
5
+ * Handles bidirectional communication with Chrome via CDP:
6
+ * - Request/response correlation with message IDs
7
+ * - Event subscription and handling
8
+ * - Connection lifecycle (connect, reconnect, keepalive)
9
+ * - Graceful error handling and cleanup
10
+ */
11
+ export class CDPConnection {
12
+ ws = null;
13
+ messageId = 0;
14
+ pendingMessages = new Map();
15
+ nextHandlerId = 0;
16
+ eventHandlers = new Map(); // Event params typed at call site
17
+ // Keepalive state
18
+ pingInterval = null;
19
+ pongTimeout = null;
20
+ missedPongs = 0;
21
+ MAX_MISSED_PONGS = 3;
22
+ // Reconnection state
23
+ wsUrl = '';
24
+ autoReconnect = false;
25
+ reconnectAttempts = 0;
26
+ MAX_RECONNECT_ATTEMPTS = 5;
27
+ isIntentionallyClosed = false;
28
+ onReconnect;
29
+ /**
30
+ * Connect to Chrome via WebSocket.
31
+ *
32
+ * @param wsUrl - WebSocket debugger URL from CDP target
33
+ * @param options - Connection configuration options
34
+ * @throws Error if connection fails after all retries
35
+ */
36
+ async connect(wsUrl, options = {}) {
37
+ const { maxRetries = 3, autoReconnect = false, onReconnect } = options;
38
+ this.wsUrl = wsUrl;
39
+ this.autoReconnect = autoReconnect;
40
+ this.onReconnect = onReconnect;
41
+ this.isIntentionallyClosed = false;
42
+ let lastError;
43
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
44
+ try {
45
+ await this.attemptConnection(wsUrl, options);
46
+ this.reconnectAttempts = 0;
47
+ return;
48
+ }
49
+ catch (error) {
50
+ lastError = error;
51
+ if (attempt < maxRetries - 1) {
52
+ const delay = Math.min(1000 * Math.pow(2, attempt), 5000);
53
+ console.error(`Connection attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
54
+ await new Promise(resolve => setTimeout(resolve, delay));
55
+ }
56
+ }
57
+ }
58
+ throw new Error(`Failed to connect after ${maxRetries} attempts: ${lastError?.message}`);
59
+ }
60
+ attemptConnection(wsUrl, options = {}) {
61
+ const timeout = options.timeout ?? 10000;
62
+ return new Promise((resolve, reject) => {
63
+ this.ws = new WebSocket(wsUrl);
64
+ const connectTimeout = setTimeout(() => {
65
+ reject(new Error('Connection timeout'));
66
+ this.ws?.close();
67
+ }, timeout);
68
+ this.ws.on('open', () => {
69
+ clearTimeout(connectTimeout);
70
+ this.startKeepalive(options.keepaliveInterval ?? 30000);
71
+ resolve();
72
+ });
73
+ this.ws.on('error', (error) => {
74
+ clearTimeout(connectTimeout);
75
+ reject(error);
76
+ });
77
+ this.ws.on('close', async (code, reason) => {
78
+ this.stopKeepalive();
79
+ if (this.isIntentionallyClosed) {
80
+ return;
81
+ }
82
+ console.error(`WebSocket closed: ${code} - ${reason.toString()}`);
83
+ // Reject all pending messages
84
+ this.pendingMessages.forEach((pending) => {
85
+ clearTimeout(pending.timeout);
86
+ pending.reject(new Error('WebSocket connection closed'));
87
+ });
88
+ this.pendingMessages.clear();
89
+ // Attempt reconnection if enabled
90
+ if (this.autoReconnect && this.reconnectAttempts < this.MAX_RECONNECT_ATTEMPTS) {
91
+ await this.attemptReconnection();
92
+ }
93
+ });
94
+ this.ws.on('pong', () => {
95
+ this.missedPongs = 0;
96
+ if (this.pongTimeout) {
97
+ clearTimeout(this.pongTimeout);
98
+ this.pongTimeout = null;
99
+ }
100
+ });
101
+ this.ws.on('message', (data) => {
102
+ try {
103
+ const message = JSON.parse(data.toString());
104
+ // Handle responses
105
+ if (message.id !== undefined) {
106
+ const pending = this.pendingMessages.get(message.id);
107
+ if (pending) {
108
+ this.pendingMessages.delete(message.id);
109
+ clearTimeout(pending.timeout);
110
+ if (message.error) {
111
+ pending.reject(new Error(message.error.message));
112
+ }
113
+ else {
114
+ pending.resolve(message.result);
115
+ }
116
+ }
117
+ }
118
+ // Handle events
119
+ if (message.method) {
120
+ const handlers = this.eventHandlers.get(message.method);
121
+ if (handlers) {
122
+ handlers.forEach(handler => handler(message.params));
123
+ }
124
+ }
125
+ }
126
+ catch (error) {
127
+ console.error('Failed to parse CDP message:', error);
128
+ }
129
+ });
130
+ });
131
+ }
132
+ async attemptReconnection() {
133
+ this.reconnectAttempts++;
134
+ const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 10000);
135
+ console.error(`Reconnecting in ${delay}ms... (attempt ${this.reconnectAttempts}/${this.MAX_RECONNECT_ATTEMPTS})`);
136
+ await new Promise(resolve => setTimeout(resolve, delay));
137
+ try {
138
+ await this.attemptConnection(this.wsUrl);
139
+ this.reconnectAttempts = 0;
140
+ console.error('Reconnected successfully');
141
+ // Re-enable domains
142
+ if (this.onReconnect) {
143
+ await this.onReconnect();
144
+ }
145
+ }
146
+ catch (error) {
147
+ console.error('Reconnection failed:', error);
148
+ }
149
+ }
150
+ startKeepalive(interval) {
151
+ this.pingInterval = setInterval(() => {
152
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
153
+ this.missedPongs++;
154
+ if (this.missedPongs >= this.MAX_MISSED_PONGS) {
155
+ console.error('Connection lost: no pong received');
156
+ this.ws.close(1001, 'No pong received');
157
+ return;
158
+ }
159
+ this.ws.ping();
160
+ this.pongTimeout = setTimeout(() => {
161
+ console.error('Pong timeout');
162
+ }, 5000);
163
+ }
164
+ }, interval);
165
+ }
166
+ stopKeepalive() {
167
+ if (this.pingInterval) {
168
+ clearInterval(this.pingInterval);
169
+ this.pingInterval = null;
170
+ }
171
+ if (this.pongTimeout) {
172
+ clearTimeout(this.pongTimeout);
173
+ this.pongTimeout = null;
174
+ }
175
+ }
176
+ /**
177
+ * Get the CDP port from the WebSocket URL.
178
+ *
179
+ * @returns CDP port number
180
+ * @throws Error if not connected or URL is invalid
181
+ */
182
+ getPort() {
183
+ if (!this.wsUrl) {
184
+ throw new Error('Not connected - no WebSocket URL available');
185
+ }
186
+ try {
187
+ const url = new URL(this.wsUrl);
188
+ return parseInt(url.port, 10);
189
+ }
190
+ catch (error) {
191
+ throw new Error(`Invalid WebSocket URL: ${this.wsUrl}`);
192
+ }
193
+ }
194
+ /**
195
+ * Send a CDP command and wait for the response.
196
+ *
197
+ * @param method - CDP method name (e.g., 'Page.navigate', 'DOM.getDocument')
198
+ * @param params - Method parameters
199
+ * @param sessionId - Optional session ID for commands sent to specific targets
200
+ * @returns Promise resolving to the command result
201
+ * @throws Error if not connected or command times out (30s)
202
+ *
203
+ * @remarks
204
+ * Return type is `any` because CDP response structures vary by method.
205
+ * Callers should type-assert the result based on the specific method called.
206
+ */
207
+ async send(method, params = {}, sessionId) {
208
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
209
+ throw new Error('Not connected to browser');
210
+ }
211
+ const id = ++this.messageId;
212
+ const message = { id, method, params };
213
+ // Add sessionId if provided (for commands sent to specific targets)
214
+ if (sessionId) {
215
+ message.sessionId = sessionId;
216
+ }
217
+ return new Promise((resolve, reject) => {
218
+ const timeout = setTimeout(() => {
219
+ const pending = this.pendingMessages.get(id);
220
+ if (pending) {
221
+ this.pendingMessages.delete(id);
222
+ reject(new Error(`Command timeout: ${method}`));
223
+ }
224
+ }, 30000);
225
+ this.pendingMessages.set(id, {
226
+ resolve: (value) => {
227
+ clearTimeout(timeout);
228
+ resolve(value);
229
+ },
230
+ reject: (error) => {
231
+ clearTimeout(timeout);
232
+ reject(error);
233
+ },
234
+ timeout
235
+ });
236
+ this.ws.send(JSON.stringify(message));
237
+ });
238
+ }
239
+ /**
240
+ * Register an event handler for CDP events.
241
+ *
242
+ * @param event - CDP event name (e.g., 'Network.requestWillBeSent')
243
+ * @param handler - Callback function to handle the event
244
+ * @returns Handler ID for later removal with off()
245
+ *
246
+ * @remarks
247
+ * Handler parameter type is `any` for flexibility. Callers should use typed
248
+ * event parameter interfaces (e.g., `CDPNetworkRequestParams`) at call site.
249
+ */
250
+ on(event, handler) {
251
+ if (!this.eventHandlers.has(event)) {
252
+ this.eventHandlers.set(event, new Map());
253
+ }
254
+ const handlerId = ++this.nextHandlerId;
255
+ this.eventHandlers.get(event).set(handlerId, handler);
256
+ return handlerId;
257
+ }
258
+ /**
259
+ * Remove a specific event handler.
260
+ *
261
+ * @param event - CDP event name
262
+ * @param handlerId - Handler ID returned from on()
263
+ */
264
+ off(event, handlerId) {
265
+ const handlers = this.eventHandlers.get(event);
266
+ if (handlers) {
267
+ handlers.delete(handlerId);
268
+ if (handlers.size === 0) {
269
+ this.eventHandlers.delete(event);
270
+ }
271
+ }
272
+ }
273
+ /**
274
+ * Remove all event handlers for a specific event or all events.
275
+ *
276
+ * @param event - Optional event name. If omitted, removes all handlers for all events.
277
+ */
278
+ removeAllListeners(event) {
279
+ if (event) {
280
+ this.eventHandlers.delete(event);
281
+ }
282
+ else {
283
+ this.eventHandlers.clear();
284
+ }
285
+ }
286
+ /**
287
+ * Close the WebSocket connection and clean up resources.
288
+ *
289
+ * @param code - WebSocket close code (default: 1000 for normal closure)
290
+ * @param reason - Human-readable close reason
291
+ */
292
+ close(code = 1000, reason = 'Normal closure') {
293
+ this.isIntentionallyClosed = true;
294
+ this.autoReconnect = false;
295
+ this.stopKeepalive();
296
+ // Clear all pending messages
297
+ this.pendingMessages.forEach((pending) => {
298
+ clearTimeout(pending.timeout);
299
+ pending.reject(new Error('Connection closed'));
300
+ });
301
+ this.pendingMessages.clear();
302
+ if (this.ws) {
303
+ this.ws.close(code, reason);
304
+ this.ws = null;
305
+ }
306
+ this.removeAllListeners();
307
+ }
308
+ /**
309
+ * Check if the WebSocket connection is open and ready.
310
+ *
311
+ * @returns True if connected and ready to send/receive
312
+ */
313
+ isConnected() {
314
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
315
+ }
316
+ }
317
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../../src/connection/cdp.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;AAG3B;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAa;IAChB,EAAE,GAAqB,IAAI,CAAC;IAC5B,SAAS,GAAG,CAAC,CAAC;IACd,eAAe,GAAG,IAAI,GAAG,EAI7B,CAAC;IACG,aAAa,GAAG,CAAC,CAAC;IAClB,aAAa,GAAG,IAAI,GAAG,EAA8C,CAAC,CAAE,kCAAkC;IAElH,kBAAkB;IACV,YAAY,GAA0B,IAAI,CAAC;IAC3C,WAAW,GAA0B,IAAI,CAAC;IAC1C,WAAW,GAAG,CAAC,CAAC;IACP,gBAAgB,GAAG,CAAC,CAAC;IAEtC,qBAAqB;IACb,KAAK,GAAG,EAAE,CAAC;IACX,aAAa,GAAG,KAAK,CAAC;IACtB,iBAAiB,GAAG,CAAC,CAAC;IACb,sBAAsB,GAAG,CAAC,CAAC;IACpC,qBAAqB,GAAG,KAAK,CAAC;IAC9B,WAAW,CAAuB;IAE1C;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,UAA6B,EAAE;QAC1D,MAAM,EACJ,UAAU,GAAG,CAAC,EACd,aAAa,GAAG,KAAK,EACrB,WAAW,EACZ,GAAG,OAAO,CAAC;QAEZ,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QAEnC,IAAI,SAA4B,CAAC;QACjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;YACtD,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAC7C,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;gBAC3B,OAAO;YACT,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,KAAc,CAAC;gBAC3B,IAAI,OAAO,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC;oBAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;oBAC1D,OAAO,CAAC,KAAK,CAAC,sBAAsB,OAAO,GAAG,CAAC,wBAAwB,KAAK,OAAO,CAAC,CAAC;oBACrF,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,cAAc,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3F,CAAC;IAEO,iBAAiB,CAAC,KAAa,EAAE,UAA6B,EAAE;QACtE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;QAEzC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;YAE/B,MAAM,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;gBACrC,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBACxC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;YACnB,CAAC,EAAE,OAAO,CAAC,CAAC;YAEZ,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBACtB,YAAY,CAAC,cAAc,CAAC,CAAC;gBAC7B,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC;gBACxD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC5B,YAAY,CAAC,cAAc,CAAC,CAAC;gBAC7B,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;gBACzC,IAAI,CAAC,aAAa,EAAE,CAAC;gBAErB,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBAED,OAAO,CAAC,KAAK,CAAC,qBAAqB,IAAI,MAAM,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBAElE,8BAA8B;gBAC9B,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;oBACvC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBAC9B,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;gBAC3D,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;gBAE7B,kCAAkC;gBAClC,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBAC/E,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACnC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBACtB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;gBACrB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;gBAC1B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAuB,EAAE,EAAE;gBAChD,IAAI,CAAC;oBACH,MAAM,OAAO,GAAe,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAExD,mBAAmB;oBACnB,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;wBAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;wBACrD,IAAI,OAAO,EAAE,CAAC;4BACZ,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;4BACxC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;4BAC9B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gCAClB,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;4BACnD,CAAC;iCAAM,CAAC;gCACN,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;4BAClC,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,gBAAgB;oBAChB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;wBACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;wBACxD,IAAI,QAAQ,EAAE,CAAC;4BACb,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;wBACvD,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;gBACvD,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9E,OAAO,CAAC,KAAK,CAAC,mBAAmB,KAAK,kBAAkB,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,sBAAsB,GAAG,CAAC,CAAC;QAElH,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAEzD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAE1C,oBAAoB;YACpB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,QAAgB;QACrC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACrD,IAAI,CAAC,WAAW,EAAE,CAAC;gBAEnB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAC9C,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;oBACnD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;oBACxC,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;gBAEf,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE;oBACjC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;gBAChC,CAAC,EAAE,IAAI,CAAC,CAAC;YACX,CAAC;QACH,CAAC,EAAE,QAAQ,CAAC,CAAC;IACf,CAAC;IAEO,aAAa;QACnB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,IAAI,CAAC,MAAc,EAAE,SAA8B,EAAE,EAAE,SAAkB;QAC7E,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC;QAC5B,MAAM,OAAO,GAAwC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAE5E,oEAAoE;QACpE,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QAChC,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7C,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBAChC,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE;gBAC3B,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;oBACjB,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjB,CAAC;gBACD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAChB,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;gBACD,OAAO;aACR,CAAC,CAAC;YAEH,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;OAUG;IACH,EAAE,CAAC,KAAa,EAAE,OAA8B;QAC9C,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,SAAS,GAAG,EAAE,IAAI,CAAC,aAAa,CAAC;QACvC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACvD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAa,EAAE,SAAiB;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC3B,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACxB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,KAAc;QAC/B,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,GAAG,IAAI,EAAE,MAAM,GAAG,gBAAgB;QAC1C,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,6BAA6B;QAC7B,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACvC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAE7B,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;QAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,CAAC;IACnE,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Validate that a target still exists in Chrome.
3
+ *
4
+ * Used to detect when a tab has been closed during collection.
5
+ *
6
+ * @param targetId - CDP target ID to validate
7
+ * @param port - Chrome debugging port
8
+ * @returns True if target still exists, false otherwise
9
+ */
10
+ export declare function validateTarget(targetId: string, port?: number): Promise<boolean>;
11
+ //# sourceMappingURL=finder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finder.d.ts","sourceRoot":"","sources":["../../src/connection/finder.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,SAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAWpF"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Validate that a target still exists in Chrome.
3
+ *
4
+ * Used to detect when a tab has been closed during collection.
5
+ *
6
+ * @param targetId - CDP target ID to validate
7
+ * @param port - Chrome debugging port
8
+ * @returns True if target still exists, false otherwise
9
+ */
10
+ export async function validateTarget(targetId, port = 9222) {
11
+ try {
12
+ const response = await fetch(`http://127.0.0.1:${port}/json/list`);
13
+ if (!response.ok) {
14
+ return false;
15
+ }
16
+ const targets = await response.json();
17
+ return targets.some(t => t.id === targetId);
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ //# sourceMappingURL=finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finder.js","sourceRoot":"","sources":["../../src/connection/finder.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,IAAI,GAAG,IAAI;IAChE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,YAAY,CAAC,CAAC;QACnE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,OAAO,GAAgB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { LaunchedChrome } from '../types.js';
2
+ export interface LaunchOptions {
3
+ port?: number;
4
+ userDataDir?: string;
5
+ headless?: boolean;
6
+ url?: string;
7
+ }
8
+ /**
9
+ * Launch Chrome with remote debugging enabled using chrome-launcher.
10
+ *
11
+ * Supports macOS, Linux, and Windows. Chrome will be launched with
12
+ * the specified debugging port and user data directory.
13
+ *
14
+ * @param options - Launch configuration options
15
+ * @returns LaunchedChrome instance with PID and kill method
16
+ * @throws Error if Chrome fails to launch or CDP doesn't become available
17
+ *
18
+ * @remarks
19
+ * Chrome 136+ requires --user-data-dir with a non-default directory.
20
+ * Uses chrome-launcher for cross-platform Chrome detection and launching.
21
+ */
22
+ export declare function launchChrome(options?: LaunchOptions): Promise<LaunchedChrome>;
23
+ /**
24
+ * Check if Chrome is already running with CDP on the specified port.
25
+ *
26
+ * @param port - Chrome debugging port to check
27
+ * @returns True if Chrome is running and CDP is available
28
+ */
29
+ export declare function isChromeRunning(port?: number): Promise<boolean>;
30
+ //# sourceMappingURL=launcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../../src/connection/launcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqDvF;AA4DD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,GAAE,MAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAS3E"}
@@ -0,0 +1,134 @@
1
+ import * as chromeLauncher from 'chrome-launcher';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import * as fs from 'fs';
5
+ /**
6
+ * Launch Chrome with remote debugging enabled using chrome-launcher.
7
+ *
8
+ * Supports macOS, Linux, and Windows. Chrome will be launched with
9
+ * the specified debugging port and user data directory.
10
+ *
11
+ * @param options - Launch configuration options
12
+ * @returns LaunchedChrome instance with PID and kill method
13
+ * @throws Error if Chrome fails to launch or CDP doesn't become available
14
+ *
15
+ * @remarks
16
+ * Chrome 136+ requires --user-data-dir with a non-default directory.
17
+ * Uses chrome-launcher for cross-platform Chrome detection and launching.
18
+ */
19
+ export async function launchChrome(options = {}) {
20
+ const port = options.port ?? 9222;
21
+ const headless = options.headless ?? false;
22
+ const startingUrl = options.url ?? 'about:blank';
23
+ // Use persistent user-data-dir if not provided
24
+ const userDataDir = options.userDataDir ?? getPersistentUserDataDir();
25
+ console.error(`Launching Chrome with CDP on port ${port}...`);
26
+ console.error(`User data directory: ${userDataDir}`);
27
+ // Build Chrome launch flags
28
+ const chromeFlags = [
29
+ `--remote-debugging-port=${port}`,
30
+ `--user-data-dir=${userDataDir}`,
31
+ '--no-first-run',
32
+ '--no-default-browser-check',
33
+ '--disable-search-engine-choice-screen',
34
+ ];
35
+ if (headless) {
36
+ chromeFlags.push('--headless=new');
37
+ }
38
+ try {
39
+ const chrome = await chromeLauncher.launch({
40
+ port,
41
+ chromePath: findChromeBinary(), // Let chrome-launcher find Chrome
42
+ chromeFlags,
43
+ startingUrl,
44
+ ignoreDefaultFlags: false,
45
+ });
46
+ console.error(`Chrome launched successfully (PID: ${chrome.pid})`);
47
+ // Wait for CDP to be fully available
48
+ await waitForCDP(port);
49
+ // Return LaunchedChrome instance
50
+ return {
51
+ pid: chrome.pid,
52
+ port: chrome.port,
53
+ kill: async () => {
54
+ try {
55
+ await chrome.kill();
56
+ }
57
+ catch (error) {
58
+ console.error(`Error killing Chrome: ${error instanceof Error ? error.message : String(error)}`);
59
+ }
60
+ },
61
+ };
62
+ }
63
+ catch (error) {
64
+ throw new Error(`Failed to launch Chrome: ${error instanceof Error ? error.message : String(error)}`);
65
+ }
66
+ }
67
+ /**
68
+ * Find Chrome binary path for the current platform.
69
+ *
70
+ * Returns undefined to let chrome-launcher use its own detection logic.
71
+ * Can be extended to support custom paths if needed.
72
+ *
73
+ * @returns Chrome binary path or undefined for auto-detection
74
+ */
75
+ function findChromeBinary() {
76
+ // Let chrome-launcher handle Chrome detection
77
+ // It already supports macOS, Linux, Windows, and various Chrome flavors
78
+ return undefined;
79
+ }
80
+ /**
81
+ * Get the default persistent user-data-dir path.
82
+ *
83
+ * Uses ~/.bdg/chrome-profile to persist cookies, settings, and other
84
+ * browser state across bdg sessions. This allows cookies to be saved
85
+ * and avoids showing cookie consent dialogs on every run.
86
+ *
87
+ * @returns Absolute path to persistent user-data-dir
88
+ */
89
+ function getPersistentUserDataDir() {
90
+ const homeDir = os.homedir();
91
+ const userDataDir = path.join(homeDir, '.bdg', 'chrome-profile');
92
+ // Create directory if it doesn't exist
93
+ if (!fs.existsSync(userDataDir)) {
94
+ fs.mkdirSync(userDataDir, { recursive: true });
95
+ }
96
+ return userDataDir;
97
+ }
98
+ /**
99
+ * Wait for Chrome CDP to become available.
100
+ *
101
+ * Polls the CDP version endpoint until it responds successfully.
102
+ *
103
+ * @param port - CDP port to check
104
+ * @param maxWaitMs - Maximum time to wait in milliseconds
105
+ * @throws Error if CDP doesn't become available within timeout
106
+ */
107
+ async function waitForCDP(port, maxWaitMs = 10000) {
108
+ const startTime = Date.now();
109
+ while (Date.now() - startTime < maxWaitMs) {
110
+ if (await isChromeRunning(port)) {
111
+ return; // CDP is ready!
112
+ }
113
+ await new Promise(resolve => setTimeout(resolve, 200));
114
+ }
115
+ throw new Error(`CDP not available on port ${port} after ${maxWaitMs}ms`);
116
+ }
117
+ /**
118
+ * Check if Chrome is already running with CDP on the specified port.
119
+ *
120
+ * @param port - Chrome debugging port to check
121
+ * @returns True if Chrome is running and CDP is available
122
+ */
123
+ export async function isChromeRunning(port = 9222) {
124
+ try {
125
+ const response = await fetch(`http://127.0.0.1:${port}/json/version`, {
126
+ signal: AbortSignal.timeout(2000), // 2 second timeout
127
+ });
128
+ return response.ok;
129
+ }
130
+ catch {
131
+ return false;
132
+ }
133
+ }
134
+ //# sourceMappingURL=launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../src/connection/launcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { CDPConnection } from './cdp.js';
2
+ import { CDPTarget } from '../types.js';
3
+ /**
4
+ * Find the best matching target from a list of tabs.
5
+ *
6
+ * @param url - Target URL to find (will be normalized)
7
+ * @param targets - List of available targets
8
+ * @returns Best matching target or null if no match found
9
+ */
10
+ export declare function findBestTarget(url: string, targets: CDPTarget[]): CDPTarget | null;
11
+ /**
12
+ * Create a new tab with the specified URL using CDP.
13
+ *
14
+ * @param url - URL to open in the new tab
15
+ * @param cdp - CDP connection instance
16
+ * @returns Target information for the new tab
17
+ */
18
+ export declare function createNewTab(url: string, cdp: CDPConnection): Promise<CDPTarget>;
19
+ /**
20
+ * Navigate an existing tab to a new URL using CDP.
21
+ *
22
+ * @param targetId - CDP target ID to navigate
23
+ * @param url - URL to navigate to
24
+ * @param cdp - CDP connection instance
25
+ */
26
+ export declare function navigateToUrl(targetId: string, url: string, cdp: CDPConnection): Promise<void>;
27
+ /**
28
+ * Wait for a target to be ready (URL matches expected).
29
+ *
30
+ * @param targetId - CDP target ID to wait for
31
+ * @param expectedUrl - Expected URL (normalized)
32
+ * @param cdp - CDP connection instance
33
+ * @param maxWaitMs - Maximum time to wait in milliseconds
34
+ */
35
+ export declare function waitForTargetReady(targetId: string, expectedUrl: string, cdp: CDPConnection, maxWaitMs?: number): Promise<void>;
36
+ /**
37
+ * Create a new tab or find existing tab with the target URL.
38
+ *
39
+ * This is the main entry point for tab management.
40
+ * It tries to find an existing tab first, and if not found,
41
+ * creates a new one.
42
+ *
43
+ * @param url - Target URL
44
+ * @param cdp - CDP connection instance
45
+ * @param reuseTab - If true, navigate existing tab instead of creating new one
46
+ * @returns Target information
47
+ */
48
+ export declare function createOrFindTarget(url: string, cdp: CDPConnection, reuseTab?: boolean): Promise<CDPTarget>;
49
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/connection/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,SAAS,EAKV,MAAM,aAAa,CAAC;AA8DrB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,EAAE,GACnB,SAAS,GAAG,IAAI,CAgClB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,SAAS,CAAC,CA0CpB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,aAAa,EAClB,SAAS,SAAQ,GAChB,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,aAAa,EAClB,QAAQ,UAAQ,GACf,OAAO,CAAC,SAAS,CAAC,CAqCpB"}