browser-pilot 0.0.7 → 0.0.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.
package/dist/index.mjs CHANGED
@@ -1,23 +1,22 @@
1
1
  import {
2
- Tracer,
3
- devices,
4
- disableTracing,
5
- enableTracing,
6
- getTracer
7
- } from "./chunk-ZIQA4JOT.mjs";
8
- import {
2
+ AudioInput,
3
+ AudioOutput,
9
4
  Browser,
10
- ElementNotFoundError,
11
- NavigationError,
12
5
  Page,
13
6
  RequestInterceptor,
14
- TimeoutError,
7
+ bufferToBase64,
8
+ calculateRMS,
15
9
  connect,
10
+ generateSilence,
11
+ generateTone,
12
+ grantAudioPermissions,
13
+ parseWavHeader,
14
+ pcmToWav,
16
15
  waitForAnyElement,
17
16
  waitForElement,
18
17
  waitForNavigation,
19
18
  waitForNetworkIdle
20
- } from "./chunk-PCNEJAJ7.mjs";
19
+ } from "./chunk-7OSR2CAE.mjs";
21
20
  import {
22
21
  CDPError,
23
22
  createCDPClient
@@ -32,9 +31,346 @@ import {
32
31
  } from "./chunk-R3PS4PCM.mjs";
33
32
  import {
34
33
  BatchExecutor,
35
- addBatchToPage
36
- } from "./chunk-6RB3GKQP.mjs";
34
+ ElementNotFoundError,
35
+ NavigationError,
36
+ TimeoutError,
37
+ addBatchToPage,
38
+ validateSteps
39
+ } from "./chunk-KKW2SZLV.mjs";
40
+
41
+ // src/audio/flags.ts
42
+ function getAudioChromeFlags(options) {
43
+ const flags = [
44
+ "--use-fake-device-for-media-stream",
45
+ "--use-fake-ui-for-media-stream",
46
+ "--autoplay-policy=no-user-gesture-required"
47
+ ];
48
+ if (options?.inputWavPath) {
49
+ let path = options.inputWavPath;
50
+ if (options.noLoop) {
51
+ path += "%noloop";
52
+ }
53
+ flags.push(`--use-file-for-fake-audio-capture=${path}`);
54
+ }
55
+ return flags;
56
+ }
57
+
58
+ // src/audio/transcribe.ts
59
+ async function transcribe(audio, options) {
60
+ const apiKey = options?.apiKey ?? getEnvVar("OPENAI_API_KEY");
61
+ if (!apiKey) {
62
+ throw new Error(
63
+ "OpenAI API key required for transcription. Set OPENAI_API_KEY environment variable or pass apiKey option."
64
+ );
65
+ }
66
+ if (audio.left.length === 0) {
67
+ return { text: "", audioDurationMs: 0, apiDurationMs: 0 };
68
+ }
69
+ const model = options?.model ?? "whisper-1";
70
+ const responseFormat = options?.responseFormat ?? "text";
71
+ const wavBuffer = pcmToWav({
72
+ left: audio.left,
73
+ right: audio.right.length > 0 ? audio.right : void 0,
74
+ sampleRate: audio.sampleRate
75
+ });
76
+ const boundary = `----bpAudio${Date.now()}`;
77
+ const parts = [];
78
+ appendFormField(parts, boundary, "file", new Uint8Array(wavBuffer), "audio.wav", "audio/wav");
79
+ appendFormTextField(parts, boundary, "model", model);
80
+ appendFormTextField(parts, boundary, "response_format", responseFormat);
81
+ if (options?.language) {
82
+ appendFormTextField(parts, boundary, "language", options.language);
83
+ }
84
+ if (options?.prompt) {
85
+ appendFormTextField(parts, boundary, "prompt", options.prompt);
86
+ }
87
+ const closing = new TextEncoder().encode(`\r
88
+ --${boundary}--\r
89
+ `);
90
+ parts.push(closing);
91
+ const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
92
+ const body = new Uint8Array(totalLength);
93
+ let offset = 0;
94
+ for (const part of parts) {
95
+ body.set(part, offset);
96
+ offset += part.length;
97
+ }
98
+ const start = Date.now();
99
+ const response = await fetch("https://api.openai.com/v1/audio/transcriptions", {
100
+ method: "POST",
101
+ headers: {
102
+ Authorization: `Bearer ${apiKey}`,
103
+ "Content-Type": `multipart/form-data; boundary=${boundary}`
104
+ },
105
+ body
106
+ });
107
+ const apiDurationMs = Date.now() - start;
108
+ if (!response.ok) {
109
+ const errorBody = await response.text().catch(() => "");
110
+ throw new Error(`Whisper API error (${response.status}): ${errorBody}`);
111
+ }
112
+ let text;
113
+ if (responseFormat === "text") {
114
+ text = (await response.text()).trim();
115
+ } else {
116
+ const json = await response.json();
117
+ text = json.text ?? "";
118
+ }
119
+ return {
120
+ text,
121
+ audioDurationMs: audio.durationMs,
122
+ apiDurationMs
123
+ };
124
+ }
125
+ function isTranscriptionAvailable() {
126
+ return !!getEnvVar("OPENAI_API_KEY");
127
+ }
128
+ function getEnvVar(name) {
129
+ if (typeof globalThis.process !== "undefined" && globalThis.process.env) {
130
+ return globalThis.process.env[name];
131
+ }
132
+ return void 0;
133
+ }
134
+ function appendFormTextField(parts, boundary, name, value) {
135
+ const text = `\r
136
+ --${boundary}\r
137
+ Content-Disposition: form-data; name="${name}"\r
138
+ \r
139
+ ${value}`;
140
+ parts.push(new TextEncoder().encode(text));
141
+ }
142
+ function appendFormField(parts, boundary, name, data, filename, contentType) {
143
+ const header = `\r
144
+ --${boundary}\r
145
+ Content-Disposition: form-data; name="${name}"; filename="${filename}"\r
146
+ Content-Type: ${contentType}\r
147
+ \r
148
+ `;
149
+ parts.push(new TextEncoder().encode(header));
150
+ parts.push(data);
151
+ }
152
+
153
+ // src/emulation/devices.ts
154
+ var devices = {
155
+ "iPhone 14": {
156
+ name: "iPhone 14",
157
+ viewport: {
158
+ width: 390,
159
+ height: 844,
160
+ deviceScaleFactor: 3,
161
+ isMobile: true,
162
+ hasTouch: true
163
+ },
164
+ userAgent: {
165
+ userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
166
+ platform: "iPhone",
167
+ userAgentMetadata: {
168
+ mobile: true,
169
+ platform: "iOS",
170
+ platformVersion: "16.0"
171
+ }
172
+ }
173
+ },
174
+ "iPhone 14 Pro Max": {
175
+ name: "iPhone 14 Pro Max",
176
+ viewport: {
177
+ width: 430,
178
+ height: 932,
179
+ deviceScaleFactor: 3,
180
+ isMobile: true,
181
+ hasTouch: true
182
+ },
183
+ userAgent: {
184
+ userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
185
+ platform: "iPhone"
186
+ }
187
+ },
188
+ "Pixel 7": {
189
+ name: "Pixel 7",
190
+ viewport: {
191
+ width: 412,
192
+ height: 915,
193
+ deviceScaleFactor: 2.625,
194
+ isMobile: true,
195
+ hasTouch: true
196
+ },
197
+ userAgent: {
198
+ userAgent: "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",
199
+ platform: "Linux armv8l",
200
+ userAgentMetadata: {
201
+ mobile: true,
202
+ platform: "Android",
203
+ platformVersion: "13",
204
+ model: "Pixel 7"
205
+ }
206
+ }
207
+ },
208
+ "iPad Pro 11": {
209
+ name: "iPad Pro 11",
210
+ viewport: {
211
+ width: 834,
212
+ height: 1194,
213
+ deviceScaleFactor: 2,
214
+ isMobile: true,
215
+ hasTouch: true
216
+ },
217
+ userAgent: {
218
+ userAgent: "Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
219
+ platform: "iPad"
220
+ }
221
+ },
222
+ "Desktop Chrome": {
223
+ name: "Desktop Chrome",
224
+ viewport: {
225
+ width: 1920,
226
+ height: 1080,
227
+ deviceScaleFactor: 1,
228
+ isMobile: false,
229
+ hasTouch: false
230
+ },
231
+ userAgent: {
232
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
233
+ platform: "Win32",
234
+ userAgentMetadata: {
235
+ brands: [
236
+ { brand: "Not_A Brand", version: "8" },
237
+ { brand: "Chromium", version: "120" },
238
+ { brand: "Google Chrome", version: "120" }
239
+ ],
240
+ platform: "Windows",
241
+ platformVersion: "10.0.0",
242
+ architecture: "x86",
243
+ bitness: "64",
244
+ mobile: false
245
+ }
246
+ }
247
+ },
248
+ "Desktop Firefox": {
249
+ name: "Desktop Firefox",
250
+ viewport: {
251
+ width: 1920,
252
+ height: 1080,
253
+ deviceScaleFactor: 1,
254
+ isMobile: false,
255
+ hasTouch: false
256
+ },
257
+ userAgent: {
258
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
259
+ platform: "Win32"
260
+ }
261
+ }
262
+ };
263
+
264
+ // src/trace/tracer.ts
265
+ var LEVEL_ORDER = {
266
+ debug: 0,
267
+ info: 1,
268
+ warn: 2,
269
+ error: 3
270
+ };
271
+ var Tracer = class _Tracer {
272
+ options;
273
+ constructor(options = {}) {
274
+ this.options = {
275
+ enabled: options.enabled ?? false,
276
+ output: options.output ?? "console",
277
+ callback: options.callback,
278
+ level: options.level ?? "info",
279
+ includeTimings: options.includeTimings ?? true
280
+ };
281
+ }
282
+ /**
283
+ * Emit a trace event
284
+ */
285
+ emit(event) {
286
+ if (!this.options.enabled) return;
287
+ if (LEVEL_ORDER[event.level] < LEVEL_ORDER[this.options.level]) {
288
+ return;
289
+ }
290
+ const fullEvent = {
291
+ ...event,
292
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
293
+ };
294
+ switch (this.options.output) {
295
+ case "console":
296
+ this.logToConsole(fullEvent);
297
+ break;
298
+ case "callback":
299
+ this.options.callback?.(fullEvent);
300
+ break;
301
+ case "silent":
302
+ break;
303
+ }
304
+ }
305
+ /**
306
+ * Log event to console
307
+ */
308
+ logToConsole(event) {
309
+ const { level, category, action, selectorUsed, success, durationMs, error } = event;
310
+ const icon = success === true ? "\u2713" : success === false ? "\u2717" : "\u25CB";
311
+ const timing = this.options.includeTimings && durationMs !== void 0 ? ` (${durationMs}ms)` : "";
312
+ const selector = selectorUsed ? ` ${selectorUsed}` : "";
313
+ const errorStr = error ? ` - ${error}` : "";
314
+ const message = `[${level.toUpperCase()}] [${category}] ${icon} ${action}${selector}${timing}${errorStr}`;
315
+ switch (level) {
316
+ case "debug":
317
+ console.debug(message);
318
+ break;
319
+ case "info":
320
+ console.info(message);
321
+ break;
322
+ case "warn":
323
+ console.warn(message);
324
+ break;
325
+ case "error":
326
+ console.error(message);
327
+ break;
328
+ }
329
+ }
330
+ /**
331
+ * Create a child tracer with modified options
332
+ */
333
+ child(options) {
334
+ return new _Tracer({ ...this.options, ...options });
335
+ }
336
+ /**
337
+ * Enable tracing
338
+ */
339
+ enable() {
340
+ this.options.enabled = true;
341
+ }
342
+ /**
343
+ * Disable tracing
344
+ */
345
+ disable() {
346
+ this.options.enabled = false;
347
+ }
348
+ /**
349
+ * Check if tracing is enabled
350
+ */
351
+ get isEnabled() {
352
+ return this.options.enabled;
353
+ }
354
+ };
355
+ var globalTracer = null;
356
+ function getTracer() {
357
+ if (!globalTracer) {
358
+ globalTracer = new Tracer({ enabled: false });
359
+ }
360
+ return globalTracer;
361
+ }
362
+ function enableTracing(options = {}) {
363
+ globalTracer = new Tracer({ ...options, enabled: true });
364
+ return globalTracer;
365
+ }
366
+ function disableTracing() {
367
+ if (globalTracer) {
368
+ globalTracer.disable();
369
+ }
370
+ }
37
371
  export {
372
+ AudioInput,
373
+ AudioOutput,
38
374
  BatchExecutor,
39
375
  Browser,
40
376
  BrowserBaseProvider,
@@ -48,6 +384,8 @@ export {
48
384
  TimeoutError,
49
385
  Tracer,
50
386
  addBatchToPage,
387
+ bufferToBase64,
388
+ calculateRMS,
51
389
  connect,
52
390
  createCDPClient,
53
391
  createProvider,
@@ -55,8 +393,17 @@ export {
55
393
  disableTracing,
56
394
  discoverTargets,
57
395
  enableTracing,
396
+ generateSilence,
397
+ generateTone,
398
+ getAudioChromeFlags,
58
399
  getBrowserWebSocketUrl,
59
400
  getTracer,
401
+ grantAudioPermissions,
402
+ isTranscriptionAvailable,
403
+ parseWavHeader,
404
+ pcmToWav,
405
+ transcribe,
406
+ validateSteps,
60
407
  waitForAnyElement,
61
408
  waitForElement,
62
409
  waitForNavigation,
@@ -1,5 +1,5 @@
1
- import { P as Provider, a as CreateSessionOptions, b as ProviderSession, C as ConnectOptions } from './types-D_uDqh0Z.cjs';
2
- export { c as ProxyConfig } from './types-D_uDqh0Z.cjs';
1
+ import { P as Provider, C as CreateSessionOptions, a as ProviderSession, b as ConnectOptions } from './types--wXNHUwt.cjs';
2
+ export { c as ProxyConfig } from './types--wXNHUwt.cjs';
3
3
 
4
4
  /**
5
5
  * BrowserBase provider implementation
@@ -1,5 +1,5 @@
1
- import { P as Provider, a as CreateSessionOptions, b as ProviderSession, C as ConnectOptions } from './types-D_uDqh0Z.js';
2
- export { c as ProxyConfig } from './types-D_uDqh0Z.js';
1
+ import { P as Provider, C as CreateSessionOptions, a as ProviderSession, b as ConnectOptions } from './types--wXNHUwt.js';
2
+ export { c as ProxyConfig } from './types--wXNHUwt.js';
3
3
 
4
4
  /**
5
5
  * BrowserBase provider implementation
@@ -53,4 +53,4 @@ interface ConnectOptions {
53
53
  timeout?: number;
54
54
  }
55
55
 
56
- export type { ConnectOptions as C, Provider as P, CreateSessionOptions as a, ProviderSession as b, ProxyConfig as c };
56
+ export type { CreateSessionOptions as C, Provider as P, ProviderSession as a, ConnectOptions as b, ProxyConfig as c };
@@ -53,4 +53,4 @@ interface ConnectOptions {
53
53
  timeout?: number;
54
54
  }
55
55
 
56
- export type { ConnectOptions as C, Provider as P, CreateSessionOptions as a, ProviderSession as b, ProxyConfig as c };
56
+ export type { CreateSessionOptions as C, Provider as P, ProviderSession as a, ConnectOptions as b, ProxyConfig as c };