browser-pilot 0.0.14 → 0.0.16

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 (44) hide show
  1. package/README.md +89 -667
  2. package/dist/actions.cjs +1073 -41
  3. package/dist/actions.d.cts +11 -3
  4. package/dist/actions.d.ts +11 -3
  5. package/dist/actions.mjs +1 -1
  6. package/dist/browser-ZCR6AA4D.mjs +11 -0
  7. package/dist/browser.cjs +1431 -62
  8. package/dist/browser.d.cts +4 -4
  9. package/dist/browser.d.ts +4 -4
  10. package/dist/browser.mjs +4 -4
  11. package/dist/cdp.cjs +5 -1
  12. package/dist/cdp.d.cts +1 -1
  13. package/dist/cdp.d.ts +1 -1
  14. package/dist/cdp.mjs +1 -1
  15. package/dist/{chunk-7NDR6V7S.mjs → chunk-6GBYX7C2.mjs} +1405 -528
  16. package/dist/{chunk-KIFB526Y.mjs → chunk-BVZALQT4.mjs} +5 -1
  17. package/dist/chunk-DTVRFXKI.mjs +35 -0
  18. package/dist/chunk-EZNZ72VA.mjs +563 -0
  19. package/dist/{chunk-SPSZZH22.mjs → chunk-LCNFBXB5.mjs} +9 -33
  20. package/dist/{chunk-IN5HPAPB.mjs → chunk-NNEHWWHL.mjs} +28 -10
  21. package/dist/chunk-TJ5B56NV.mjs +804 -0
  22. package/dist/{chunk-XMJABKCF.mjs → chunk-V3VLBQAM.mjs} +1073 -41
  23. package/dist/cli.mjs +2799 -1176
  24. package/dist/{client-Ck2nQksT.d.cts → client-B5QBRgIy.d.cts} +2 -0
  25. package/dist/{client-Ck2nQksT.d.ts → client-B5QBRgIy.d.ts} +2 -0
  26. package/dist/{client-3AFV2IAF.mjs → client-JWWZWO6L.mjs} +4 -2
  27. package/dist/index.cjs +1441 -52
  28. package/dist/index.d.cts +5 -5
  29. package/dist/index.d.ts +5 -5
  30. package/dist/index.mjs +19 -7
  31. package/dist/page-IUUTJ3SW.mjs +7 -0
  32. package/dist/providers.cjs +637 -2
  33. package/dist/providers.d.cts +2 -2
  34. package/dist/providers.d.ts +2 -2
  35. package/dist/providers.mjs +17 -3
  36. package/dist/{types-CjT0vClo.d.ts → types-BflRmiDz.d.cts} +17 -3
  37. package/dist/{types-BSoh5v1Y.d.cts → types-BzM-IfsL.d.ts} +17 -3
  38. package/dist/types-DeVSWhXj.d.cts +142 -0
  39. package/dist/types-DeVSWhXj.d.ts +142 -0
  40. package/package.json +1 -1
  41. package/dist/browser-LZTEHUDI.mjs +0 -9
  42. package/dist/chunk-BRAFQUMG.mjs +0 -229
  43. package/dist/types--wXNHUwt.d.cts +0 -56
  44. package/dist/types--wXNHUwt.d.ts +0 -56
@@ -168,7 +168,8 @@ function buildCDPClient(transport, options = {}) {
168
168
  pending.delete(response.id);
169
169
  clearTimeout(request.timer);
170
170
  if (response.error) {
171
- request.reject(new CDPError(response.error));
171
+ const error = typeof response.error === "string" ? { code: -32e3, message: response.error } : response.error;
172
+ request.reject(new CDPError(error));
172
173
  } else {
173
174
  request.resolve(response.result);
174
175
  }
@@ -284,6 +285,9 @@ function buildCDPClient(transport, options = {}) {
284
285
  get sessionId() {
285
286
  return currentSessionId;
286
287
  },
288
+ setSessionId(sessionId) {
289
+ currentSessionId = sessionId;
290
+ },
287
291
  get isConnected() {
288
292
  return connected;
289
293
  }
@@ -0,0 +1,35 @@
1
+ // src/cdp/protocol.ts
2
+ var CDPError = class extends Error {
3
+ code;
4
+ data;
5
+ constructor(error) {
6
+ super(error.message);
7
+ this.name = "CDPError";
8
+ this.code = error.code;
9
+ this.data = error.data;
10
+ }
11
+ };
12
+
13
+ // src/utils/json.ts
14
+ function isRecord(value) {
15
+ return typeof value === "object" && value !== null;
16
+ }
17
+ function stringifyUnknown(value) {
18
+ if (typeof value === "string") return value;
19
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
20
+ return String(value);
21
+ }
22
+ if (value === null) return "null";
23
+ if (value === void 0) return "undefined";
24
+ try {
25
+ return JSON.stringify(value);
26
+ } catch {
27
+ return Object.prototype.toString.call(value);
28
+ }
29
+ }
30
+
31
+ export {
32
+ CDPError,
33
+ isRecord,
34
+ stringifyUnknown
35
+ };
@@ -0,0 +1,563 @@
1
+ import {
2
+ createCDPClient
3
+ } from "./chunk-BVZALQT4.mjs";
4
+
5
+ // src/providers/browserbase.ts
6
+ var BrowserBaseProvider = class {
7
+ name = "browserbase";
8
+ apiKey;
9
+ projectId;
10
+ baseUrl;
11
+ constructor(options) {
12
+ this.apiKey = options.apiKey;
13
+ this.projectId = options.projectId;
14
+ this.baseUrl = options.baseUrl ?? "https://api.browserbase.com";
15
+ }
16
+ async createSession(options = {}) {
17
+ const response = await fetch(`${this.baseUrl}/v1/sessions`, {
18
+ method: "POST",
19
+ headers: {
20
+ "X-BB-API-Key": this.apiKey,
21
+ "Content-Type": "application/json"
22
+ },
23
+ body: JSON.stringify({
24
+ projectId: this.projectId,
25
+ browserSettings: {
26
+ viewport: options.width && options.height ? {
27
+ width: options.width,
28
+ height: options.height
29
+ } : void 0
30
+ },
31
+ ...options
32
+ })
33
+ });
34
+ if (!response.ok) {
35
+ const text = await response.text();
36
+ throw new Error(`BrowserBase createSession failed: ${response.status} ${text}`);
37
+ }
38
+ const session = await response.json();
39
+ const connectResponse = await fetch(`${this.baseUrl}/v1/sessions/${session.id}`, {
40
+ headers: {
41
+ "X-BB-API-Key": this.apiKey
42
+ }
43
+ });
44
+ if (!connectResponse.ok) {
45
+ throw new Error(`BrowserBase getSession failed: ${connectResponse.status}`);
46
+ }
47
+ const sessionDetails = await connectResponse.json();
48
+ if (!sessionDetails.connectUrl) {
49
+ throw new Error("BrowserBase session does not have a connectUrl");
50
+ }
51
+ return {
52
+ wsUrl: sessionDetails.connectUrl,
53
+ sessionId: session.id,
54
+ metadata: {
55
+ debugUrl: sessionDetails.debugUrl,
56
+ projectId: this.projectId,
57
+ status: sessionDetails.status
58
+ },
59
+ close: async () => {
60
+ await fetch(`${this.baseUrl}/v1/sessions/${session.id}`, {
61
+ method: "DELETE",
62
+ headers: {
63
+ "X-BB-API-Key": this.apiKey
64
+ }
65
+ });
66
+ }
67
+ };
68
+ }
69
+ async resumeSession(sessionId) {
70
+ const response = await fetch(`${this.baseUrl}/v1/sessions/${sessionId}`, {
71
+ headers: {
72
+ "X-BB-API-Key": this.apiKey
73
+ }
74
+ });
75
+ if (!response.ok) {
76
+ throw new Error(`BrowserBase resumeSession failed: ${response.status}`);
77
+ }
78
+ const session = await response.json();
79
+ if (!session.connectUrl) {
80
+ throw new Error("BrowserBase session does not have a connectUrl (may be closed)");
81
+ }
82
+ return {
83
+ wsUrl: session.connectUrl,
84
+ sessionId: session.id,
85
+ metadata: {
86
+ debugUrl: session.debugUrl,
87
+ projectId: this.projectId,
88
+ status: session.status
89
+ },
90
+ close: async () => {
91
+ await fetch(`${this.baseUrl}/v1/sessions/${sessionId}`, {
92
+ method: "DELETE",
93
+ headers: {
94
+ "X-BB-API-Key": this.apiKey
95
+ }
96
+ });
97
+ }
98
+ };
99
+ }
100
+ };
101
+
102
+ // src/providers/browserless.ts
103
+ var BrowserlessProvider = class {
104
+ name = "browserless";
105
+ token;
106
+ baseUrl;
107
+ constructor(options) {
108
+ this.token = options.token;
109
+ this.baseUrl = options.baseUrl ?? "wss://chrome.browserless.io";
110
+ }
111
+ async createSession(options = {}) {
112
+ const params = new URLSearchParams({
113
+ token: this.token
114
+ });
115
+ if (options.width && options.height) {
116
+ params.set("--window-size", `${options.width},${options.height}`);
117
+ }
118
+ if (options.proxy?.server) {
119
+ params.set("--proxy-server", options.proxy.server);
120
+ }
121
+ const wsUrl = `${this.baseUrl}?${params.toString()}`;
122
+ return {
123
+ wsUrl,
124
+ metadata: {
125
+ provider: "browserless"
126
+ },
127
+ close: async () => {
128
+ }
129
+ };
130
+ }
131
+ // Browserless doesn't support session resumption in the same way
132
+ // Each connection is a fresh browser instance
133
+ };
134
+
135
+ // src/providers/generic.ts
136
+ function sleep(ms) {
137
+ return new Promise((resolve) => setTimeout(resolve, ms));
138
+ }
139
+ async function fetchDevToolsJson(host, path, errorPrefix, options = {}) {
140
+ const protocol = host.includes("://") ? "" : "http://";
141
+ const attempts = options.attempts ?? 1;
142
+ let delayMs = options.initialDelayMs ?? 50;
143
+ const maxDelayMs = options.maxDelayMs ?? 250;
144
+ let lastError;
145
+ for (let attempt = 1; attempt <= attempts; attempt++) {
146
+ try {
147
+ const response = await fetch(`${protocol}${host}${path}`);
148
+ if (response.ok) {
149
+ return await response.json();
150
+ }
151
+ lastError = new Error(`${errorPrefix}: ${response.status}`);
152
+ } catch (error) {
153
+ lastError = new Error(
154
+ `${errorPrefix}: ${error instanceof Error ? error.message : String(error)}`
155
+ );
156
+ }
157
+ if (attempt < attempts) {
158
+ await sleep(delayMs);
159
+ delayMs = Math.min(delayMs * 2, maxDelayMs);
160
+ }
161
+ }
162
+ throw lastError ?? new Error(errorPrefix);
163
+ }
164
+ var GenericProvider = class {
165
+ name = "generic";
166
+ wsUrl;
167
+ constructor(options) {
168
+ this.wsUrl = options.wsUrl;
169
+ }
170
+ async createSession(_options = {}) {
171
+ return {
172
+ wsUrl: this.wsUrl,
173
+ metadata: {
174
+ provider: "generic"
175
+ },
176
+ close: async () => {
177
+ }
178
+ };
179
+ }
180
+ };
181
+ async function discoverTargets(host = "localhost:9222") {
182
+ return fetchDevToolsJson(host, "/json/list", "Failed to discover targets");
183
+ }
184
+ async function getBrowserWebSocketUrl(host = "localhost:9222") {
185
+ const info = await fetchDevToolsJson(host, "/json/version", "Failed to get browser info", {
186
+ attempts: 10,
187
+ initialDelayMs: 50,
188
+ maxDelayMs: 250
189
+ });
190
+ return info.webSocketDebuggerUrl;
191
+ }
192
+
193
+ // src/providers/local-discovery.ts
194
+ var CHANNEL_ORDER = ["stable", "beta", "dev", "canary"];
195
+ var DEFAULT_PROBE_TIMEOUT_MS = 1e3;
196
+ var DevToolsActivePortParseError = class extends Error {
197
+ constructor(message, reason) {
198
+ super(message);
199
+ this.reason = reason;
200
+ this.name = "DevToolsActivePortParseError";
201
+ }
202
+ };
203
+ function getRuntimeEnv() {
204
+ if (typeof process === "undefined") {
205
+ return {};
206
+ }
207
+ return process.env;
208
+ }
209
+ function getRuntimePlatform() {
210
+ if (typeof process === "undefined") {
211
+ return void 0;
212
+ }
213
+ return process.platform;
214
+ }
215
+ function normalizePlatform(platform) {
216
+ if (platform === "darwin" || platform === "linux" || platform === "win32") {
217
+ return platform;
218
+ }
219
+ throw new Error(`Unsupported platform: ${platform ?? "unknown"}`);
220
+ }
221
+ function trimTrailingSeparator(path) {
222
+ return path.replace(/[\\/]+$/, "");
223
+ }
224
+ function joinPath(platform, ...parts) {
225
+ const separator = platform === "win32" ? "\\" : "/";
226
+ const cleaned = parts.map((part, index) => {
227
+ if (index === 0) return trimTrailingSeparator(part);
228
+ return part.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "");
229
+ }).filter((part) => part.length > 0);
230
+ return cleaned.join(separator);
231
+ }
232
+ function resolveHomeDir(platform, env, explicitHomeDir) {
233
+ if (explicitHomeDir) {
234
+ return explicitHomeDir;
235
+ }
236
+ if (platform === "win32") {
237
+ return env["USERPROFILE"] ?? env["HOME"] ?? "";
238
+ }
239
+ return env["HOME"] ?? env["USERPROFILE"] ?? "";
240
+ }
241
+ function toFileFailure(target, error) {
242
+ const errno = error?.code;
243
+ if (errno === "ENOENT") {
244
+ return {
245
+ ...target,
246
+ reason: "missing-file",
247
+ message: `DevToolsActivePort not found at ${target.portFile}`
248
+ };
249
+ }
250
+ return {
251
+ ...target,
252
+ reason: "unreadable-file",
253
+ message: error instanceof Error ? error.message : `Could not read DevToolsActivePort at ${target.portFile}`
254
+ };
255
+ }
256
+ function toProbeFailure(target, wsUrl, error) {
257
+ const message = error instanceof Error ? error.message : String(error);
258
+ const lowerMessage = message.toLowerCase();
259
+ let reason = "connection-error";
260
+ if (lowerMessage.includes("refused") || lowerMessage.includes("econnrefused")) {
261
+ reason = "connection-refused";
262
+ } else if (lowerMessage.includes("timeout") || lowerMessage.includes("timed out")) {
263
+ reason = "connection-timeout";
264
+ } else if (lowerMessage.includes("closed")) {
265
+ reason = "unexpected-close";
266
+ } else if (lowerMessage.includes("browser.getversion") || lowerMessage.includes("cdp") || lowerMessage.includes("protocol")) {
267
+ reason = "cdp-error";
268
+ }
269
+ return {
270
+ ...target,
271
+ wsUrl,
272
+ reason,
273
+ message
274
+ };
275
+ }
276
+ async function readTextFile(path) {
277
+ const fs = await import("fs/promises");
278
+ return fs.readFile(path, "utf-8");
279
+ }
280
+ async function probeBrowserWebSocket(wsUrl, timeoutMs) {
281
+ let client;
282
+ try {
283
+ client = await createCDPClient(wsUrl, { timeout: timeoutMs });
284
+ const version = await client.send("Browser.getVersion", void 0, null);
285
+ return { browserVersion: version.product };
286
+ } finally {
287
+ await client?.close().catch(() => {
288
+ });
289
+ }
290
+ }
291
+ var defaultDependencies = {
292
+ readTextFile,
293
+ probeBrowserWebSocket,
294
+ getLegacyBrowserWebSocketUrl: getBrowserWebSocketUrl
295
+ };
296
+ function resolveChromeUserDataDirs(options = {}) {
297
+ const env = options.env ?? getRuntimeEnv();
298
+ const platform = normalizePlatform(options.platform ?? getRuntimePlatform());
299
+ const homeDir = resolveHomeDir(platform, env, options.homeDir);
300
+ if (!homeDir) {
301
+ throw new Error("Could not determine home directory for local Chrome discovery");
302
+ }
303
+ switch (platform) {
304
+ case "darwin": {
305
+ const base = joinPath(platform, homeDir, "Library", "Application Support", "Google");
306
+ return {
307
+ stable: joinPath(platform, base, "Chrome"),
308
+ beta: joinPath(platform, base, "Chrome Beta"),
309
+ dev: joinPath(platform, base, "Chrome Dev"),
310
+ canary: joinPath(platform, base, "Chrome Canary")
311
+ };
312
+ }
313
+ case "linux": {
314
+ const configHome = env["CHROME_CONFIG_HOME"] ?? env["XDG_CONFIG_HOME"] ?? joinPath(platform, homeDir, ".config");
315
+ return {
316
+ stable: joinPath(platform, configHome, "google-chrome"),
317
+ beta: joinPath(platform, configHome, "google-chrome-beta"),
318
+ dev: joinPath(platform, configHome, "google-chrome-dev"),
319
+ canary: joinPath(platform, configHome, "google-chrome-canary")
320
+ };
321
+ }
322
+ case "win32": {
323
+ const localAppData = env["LOCALAPPDATA"] ?? joinPath(platform, homeDir, "AppData", "Local");
324
+ const base = joinPath(platform, localAppData, "Google");
325
+ return {
326
+ stable: joinPath(platform, base, "Chrome", "User Data"),
327
+ beta: joinPath(platform, base, "Chrome Beta", "User Data"),
328
+ dev: joinPath(platform, base, "Chrome Dev", "User Data"),
329
+ canary: joinPath(platform, base, "Chrome SxS", "User Data")
330
+ };
331
+ }
332
+ }
333
+ throw new Error(`Unsupported platform for local Chrome discovery: ${platform}`);
334
+ }
335
+ function buildLocalBrowserScanTargets(options = {}) {
336
+ const env = options.env ?? getRuntimeEnv();
337
+ const platform = normalizePlatform(options.platform ?? getRuntimePlatform());
338
+ if (options.userDataDir) {
339
+ return [
340
+ {
341
+ channel: options.channel ?? "custom",
342
+ userDataDir: options.userDataDir,
343
+ portFile: joinPath(platform, options.userDataDir, "DevToolsActivePort")
344
+ }
345
+ ];
346
+ }
347
+ const dirs = resolveChromeUserDataDirs({
348
+ platform,
349
+ env,
350
+ homeDir: options.homeDir
351
+ });
352
+ const channels = options.channel ? [options.channel] : CHANNEL_ORDER;
353
+ return channels.map((channel) => ({
354
+ channel,
355
+ userDataDir: dirs[channel],
356
+ portFile: joinPath(platform, dirs[channel], "DevToolsActivePort")
357
+ }));
358
+ }
359
+ function parseDevToolsActivePortFile(content) {
360
+ const lines = content.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0);
361
+ if (lines.length !== 2) {
362
+ throw new DevToolsActivePortParseError(
363
+ `Expected exactly 2 non-empty lines in DevToolsActivePort, got ${lines.length}`,
364
+ "malformed-file"
365
+ );
366
+ }
367
+ const portText = lines[0];
368
+ const browserPath = lines[1];
369
+ const port = Number.parseInt(portText, 10);
370
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
371
+ throw new DevToolsActivePortParseError(
372
+ `Invalid DevToolsActivePort port: ${portText}`,
373
+ "invalid-port"
374
+ );
375
+ }
376
+ if (!browserPath.startsWith("/devtools/browser/") || browserPath.includes("..") || /[?#\s\\]/u.test(browserPath)) {
377
+ throw new DevToolsActivePortParseError(
378
+ `Invalid DevToolsActivePort browser path: ${browserPath}`,
379
+ "invalid-path"
380
+ );
381
+ }
382
+ return {
383
+ port,
384
+ browserPath,
385
+ wsUrl: `ws://127.0.0.1:${port}${browserPath}`
386
+ };
387
+ }
388
+ async function inspectScanTarget(target, options, deps) {
389
+ let content;
390
+ try {
391
+ content = await deps.readTextFile(target.portFile);
392
+ } catch (error) {
393
+ return { kind: "failure", failure: toFileFailure(target, error) };
394
+ }
395
+ let parsed;
396
+ try {
397
+ parsed = parseDevToolsActivePortFile(content);
398
+ } catch (error) {
399
+ if (error instanceof DevToolsActivePortParseError) {
400
+ return {
401
+ kind: "failure",
402
+ failure: {
403
+ ...target,
404
+ reason: error.reason,
405
+ message: error.message
406
+ }
407
+ };
408
+ }
409
+ throw error;
410
+ }
411
+ try {
412
+ const probe = await deps.probeBrowserWebSocket(
413
+ parsed.wsUrl,
414
+ options.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS
415
+ );
416
+ return {
417
+ kind: "candidate",
418
+ candidate: {
419
+ ...target,
420
+ port: parsed.port,
421
+ browserPath: parsed.browserPath,
422
+ wsUrl: parsed.wsUrl,
423
+ browserVersion: probe.browserVersion
424
+ }
425
+ };
426
+ } catch (error) {
427
+ return {
428
+ kind: "failure",
429
+ failure: toProbeFailure(target, parsed.wsUrl, error)
430
+ };
431
+ }
432
+ }
433
+ async function discoverLocalBrowsers(options = {}, deps = defaultDependencies) {
434
+ const scanTargets = buildLocalBrowserScanTargets(options);
435
+ const outcomes = await Promise.all(
436
+ scanTargets.map((target) => inspectScanTarget(target, options, deps))
437
+ );
438
+ const candidates = [];
439
+ const failures = [];
440
+ for (const outcome of outcomes) {
441
+ if (outcome.kind === "candidate") {
442
+ candidates.push(outcome.candidate);
443
+ } else {
444
+ failures.push(outcome.failure);
445
+ }
446
+ }
447
+ return { candidates, failures };
448
+ }
449
+ var BrowserEndpointResolutionError = class extends Error {
450
+ constructor(code, message, details = {}) {
451
+ super(message);
452
+ this.code = code;
453
+ this.details = details;
454
+ }
455
+ name = "BrowserEndpointResolutionError";
456
+ };
457
+ async function resolveBrowserEndpoint(options = {}, deps = defaultDependencies) {
458
+ if (options.explicitWsUrl) {
459
+ return {
460
+ wsUrl: options.explicitWsUrl,
461
+ source: "explicit-ws"
462
+ };
463
+ }
464
+ let localDiscovery;
465
+ if (options.allowLocalDiscovery ?? true) {
466
+ localDiscovery = await discoverLocalBrowsers(options, deps);
467
+ if (localDiscovery.candidates.length === 1) {
468
+ const candidate = localDiscovery.candidates[0];
469
+ return {
470
+ wsUrl: candidate.wsUrl,
471
+ source: "devtools-active-port",
472
+ channel: candidate.channel,
473
+ userDataDir: candidate.userDataDir
474
+ };
475
+ }
476
+ if (localDiscovery.candidates.length > 1) {
477
+ throw new BrowserEndpointResolutionError(
478
+ "multiple-local-browsers",
479
+ "Multiple local Chrome profiles are available for auto-discovery",
480
+ {
481
+ candidates: localDiscovery.candidates,
482
+ failures: localDiscovery.failures
483
+ }
484
+ );
485
+ }
486
+ }
487
+ if (options.allowLegacyHostFallback ?? true) {
488
+ const legacyHost = options.legacyHost ?? "localhost:9222";
489
+ try {
490
+ return {
491
+ wsUrl: await deps.getLegacyBrowserWebSocketUrl(legacyHost),
492
+ source: "json-version"
493
+ };
494
+ } catch (error) {
495
+ throw new BrowserEndpointResolutionError(
496
+ "browser-not-found",
497
+ "Could not resolve a browser endpoint",
498
+ {
499
+ candidates: localDiscovery?.candidates,
500
+ failures: localDiscovery?.failures,
501
+ legacyError: error instanceof Error ? error : new Error(String(error)),
502
+ legacyHost
503
+ }
504
+ );
505
+ }
506
+ }
507
+ throw new BrowserEndpointResolutionError(
508
+ "browser-not-found",
509
+ "Could not resolve a browser endpoint",
510
+ {
511
+ candidates: localDiscovery?.candidates,
512
+ failures: localDiscovery?.failures
513
+ }
514
+ );
515
+ }
516
+
517
+ // src/providers/index.ts
518
+ function createProvider(options) {
519
+ switch (options.provider) {
520
+ case "browserbase":
521
+ if (!options.apiKey) {
522
+ throw new Error("BrowserBase provider requires apiKey");
523
+ }
524
+ if (!options.projectId) {
525
+ throw new Error("BrowserBase provider requires projectId");
526
+ }
527
+ return new BrowserBaseProvider({
528
+ apiKey: options.apiKey,
529
+ projectId: options.projectId
530
+ });
531
+ case "browserless":
532
+ if (!options.apiKey) {
533
+ throw new Error("Browserless provider requires apiKey (token)");
534
+ }
535
+ return new BrowserlessProvider({
536
+ token: options.apiKey
537
+ });
538
+ case "generic":
539
+ if (!options.wsUrl) {
540
+ throw new Error("Generic provider requires wsUrl");
541
+ }
542
+ return new GenericProvider({
543
+ wsUrl: options.wsUrl
544
+ });
545
+ default:
546
+ throw new Error(`Unknown provider: ${options.provider}`);
547
+ }
548
+ }
549
+
550
+ export {
551
+ BrowserBaseProvider,
552
+ BrowserlessProvider,
553
+ GenericProvider,
554
+ discoverTargets,
555
+ getBrowserWebSocketUrl,
556
+ resolveChromeUserDataDirs,
557
+ buildLocalBrowserScanTargets,
558
+ parseDevToolsActivePortFile,
559
+ discoverLocalBrowsers,
560
+ BrowserEndpointResolutionError,
561
+ resolveBrowserEndpoint,
562
+ createProvider
563
+ };
@@ -1,32 +1,7 @@
1
- // src/utils/json.ts
2
- function isRecord(value) {
3
- return typeof value === "object" && value !== null;
4
- }
5
- function stringifyUnknown(value) {
6
- if (typeof value === "string") return value;
7
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
8
- return String(value);
9
- }
10
- if (value === null) return "null";
11
- if (value === void 0) return "undefined";
12
- try {
13
- return JSON.stringify(value);
14
- } catch {
15
- return Object.prototype.toString.call(value);
16
- }
17
- }
18
-
19
- // src/cdp/protocol.ts
20
- var CDPError = class extends Error {
21
- code;
22
- data;
23
- constructor(error) {
24
- super(error.message);
25
- this.name = "CDPError";
26
- this.code = error.code;
27
- this.data = error.data;
28
- }
29
- };
1
+ import {
2
+ CDPError,
3
+ isRecord
4
+ } from "./chunk-DTVRFXKI.mjs";
30
5
 
31
6
  // src/cdp/transport.ts
32
7
  function createTransport(wsUrl, options = {}) {
@@ -176,7 +151,8 @@ function buildCDPClient(transport, options = {}) {
176
151
  pending.delete(response.id);
177
152
  clearTimeout(request.timer);
178
153
  if (response.error) {
179
- request.reject(new CDPError(response.error));
154
+ const error = typeof response.error === "string" ? { code: -32e3, message: response.error } : response.error;
155
+ request.reject(new CDPError(error));
180
156
  } else {
181
157
  request.resolve(response.result);
182
158
  }
@@ -292,6 +268,9 @@ function buildCDPClient(transport, options = {}) {
292
268
  get sessionId() {
293
269
  return currentSessionId;
294
270
  },
271
+ setSessionId(sessionId) {
272
+ currentSessionId = sessionId;
273
+ },
295
274
  get isConnected() {
296
275
  return connected;
297
276
  }
@@ -300,9 +279,6 @@ function buildCDPClient(transport, options = {}) {
300
279
  }
301
280
 
302
281
  export {
303
- CDPError,
304
- isRecord,
305
- stringifyUnknown,
306
282
  createCDPClientFromTransport,
307
283
  createCDPClient
308
284
  };