browser-use 0.7.1 → 0.7.3

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.
@@ -499,7 +499,7 @@ export declare class BrowserSession {
499
499
  private _scrollWithCdpGesture;
500
500
  /**
501
501
  * Scroll the current page container
502
- * @param pixels - Number of pixels to scroll (positive = up, negative = down)
502
+ * @param pixels - Number of pixels to scroll (positive = down, negative = up)
503
503
  */
504
504
  private _scrollContainer;
505
505
  /**
@@ -1404,7 +1404,11 @@ export class BrowserSession {
1404
1404
  });
1405
1405
  const reconnectTask = this._auto_reconnect();
1406
1406
  this._reconnectTask = reconnectTask;
1407
- void reconnectTask.finally(() => {
1407
+ void reconnectTask
1408
+ .catch((error) => {
1409
+ this.logger.warning(`Automatic reconnect failed: ${error instanceof Error ? error.message : String(error)}`);
1410
+ })
1411
+ .finally(() => {
1408
1412
  if (this._reconnectTask === reconnectTask) {
1409
1413
  this._reconnectTask = null;
1410
1414
  }
@@ -2572,7 +2576,7 @@ export class BrowserSession {
2572
2576
  }
2573
2577
  }
2574
2578
  if (direction === 'up' || direction === 'down') {
2575
- const pixels = direction === 'down' ? -normalizedAmount : normalizedAmount;
2579
+ const pixels = direction === 'down' ? normalizedAmount : -normalizedAmount;
2576
2580
  await this._withAbort(this._scrollContainer(pixels), signal);
2577
2581
  return;
2578
2582
  }
@@ -5293,7 +5297,7 @@ export class BrowserSession {
5293
5297
  }
5294
5298
  /**
5295
5299
  * Scroll the current page container
5296
- * @param pixels - Number of pixels to scroll (positive = up, negative = down)
5300
+ * @param pixels - Number of pixels to scroll (positive = down, negative = up)
5297
5301
  */
5298
5302
  async _scrollContainer(pixels) {
5299
5303
  const page = await this.getCurrentPage();
@@ -17,5 +17,11 @@ export declare abstract class BaseWatchdog {
17
17
  detach_from_session(): void;
18
18
  protected onAttached(): void;
19
19
  protected onDetached(): void;
20
+ /**
21
+ * Run fire-and-forget background work without letting a rejection surface
22
+ * as an unhandled promise rejection (which terminates the process on
23
+ * modern Node). Failures are logged at debug level.
24
+ */
25
+ protected runBackground(label: string, work: Promise<unknown>): void;
20
26
  private _collectHandlerMethods;
21
27
  }
@@ -91,6 +91,16 @@ export class BaseWatchdog {
91
91
  }
92
92
  onAttached() { }
93
93
  onDetached() { }
94
+ /**
95
+ * Run fire-and-forget background work without letting a rejection surface
96
+ * as an unhandled promise rejection (which terminates the process on
97
+ * modern Node). Failures are logged at debug level.
98
+ */
99
+ runBackground(label, work) {
100
+ void work.catch((error) => {
101
+ this.browser_session.logger.debug(`[${this.constructor.name}] ${label} failed: ${error instanceof Error ? error.message : String(error)}`);
102
+ });
103
+ }
94
104
  _collectHandlerMethods() {
95
105
  const methodNames = new Set();
96
106
  let prototype = Object.getPrototypeOf(this);
@@ -12,7 +12,7 @@ export class CDPSessionWatchdog extends BaseWatchdog {
12
12
  await this._teardownCdpMonitoring();
13
13
  }
14
14
  onDetached() {
15
- void this._teardownCdpMonitoring();
15
+ this.runBackground('teardown CDP monitoring', this._teardownCdpMonitoring());
16
16
  }
17
17
  async _ensureCdpMonitoring() {
18
18
  if (this._rootCdpSession) {
@@ -69,7 +69,7 @@ export class CrashWatchdog extends BaseWatchdog {
69
69
  return;
70
70
  }
71
71
  const crashListener = (payload) => {
72
- void this._handlePageCrash(page, payload);
72
+ this.runBackground('handle page crash', this._handlePageCrash(page, payload));
73
73
  };
74
74
  const requestListener = (payload) => {
75
75
  this._trackRequestStart(payload);
@@ -215,7 +215,7 @@ export class CrashWatchdog extends BaseWatchdog {
215
215
  return;
216
216
  }
217
217
  this._healthInterval = setInterval(() => {
218
- void this._runHealthCheck();
218
+ this.runBackground('run health check', this._runHealthCheck());
219
219
  }, this._healthCheckIntervalMs);
220
220
  }
221
221
  _stopHealthMonitor() {
@@ -77,7 +77,7 @@ export class DownloadsWatchdog extends BaseWatchdog {
77
77
  this._downloadCompleteCallbacks = [];
78
78
  this._networkDownloads.clear();
79
79
  this._detectedDownloadUrls.clear();
80
- void this._stopCdpDownloadMonitoring();
80
+ this.runBackground('stop CDP download monitoring', this._stopCdpDownloadMonitoring());
81
81
  }
82
82
  on_TabCreatedEvent() {
83
83
  return null;
@@ -199,7 +199,7 @@ export class DownloadsWatchdog extends BaseWatchdog {
199
199
  this._downloadCompleteCallbacks = [];
200
200
  this._networkDownloads.clear();
201
201
  this._detectedDownloadUrls.clear();
202
- void this._stopCdpDownloadMonitoring();
202
+ this.runBackground('stop CDP download monitoring', this._stopCdpDownloadMonitoring());
203
203
  }
204
204
  _normalizeCallbackRegistration(on_start_or_options, on_progress, on_complete) {
205
205
  if (on_start_or_options &&
@@ -229,10 +229,10 @@ export class DownloadsWatchdog extends BaseWatchdog {
229
229
  await session.send?.('Network.enable');
230
230
  this._cdpSession = session;
231
231
  const onResponseReceived = (payload) => {
232
- void this._handleNetworkResponse(payload);
232
+ this.runBackground('handle network response', this._handleNetworkResponse(payload));
233
233
  };
234
234
  const onLoadingFinished = (payload) => {
235
- void this._handleNetworkLoadingFinished(payload);
235
+ this.runBackground('handle loading finished', this._handleNetworkLoadingFinished(payload));
236
236
  };
237
237
  session.on?.('Network.responseReceived', onResponseReceived);
238
238
  session.on?.('Network.loadingFinished', onLoadingFinished);
@@ -125,7 +125,7 @@ export class HarRecordingWatchdog extends BaseWatchdog {
125
125
  }
126
126
  }
127
127
  onDetached() {
128
- void this._teardownCapture();
128
+ this.runBackground('teardown HAR capture', this._teardownCapture());
129
129
  }
130
130
  _resolveConfiguredHarPath() {
131
131
  const configuredPath = this.browser_session.browser_profile.config.record_har_path;
@@ -20,7 +20,7 @@ export class PopupsWatchdog extends BaseWatchdog {
20
20
  await this._detachCdpDialogHandlers();
21
21
  }
22
22
  onDetached() {
23
- void this._detachCdpDialogHandlers();
23
+ this.runBackground('detach CDP dialog handlers', this._detachCdpDialogHandlers());
24
24
  }
25
25
  async _attachCdpDialogHandler(targetId, page) {
26
26
  if (this._dialogListenersRegistered.has(targetId)) {
@@ -30,7 +30,7 @@ export class PopupsWatchdog extends BaseWatchdog {
30
30
  const session = (await this.browser_session.get_or_create_cdp_session(page));
31
31
  await session.send?.('Page.enable');
32
32
  const handler = (payload) => {
33
- void this._handleJavascriptDialog(payload, session);
33
+ this.runBackground('handle javascript dialog', this._handleJavascriptDialog(payload, session));
34
34
  };
35
35
  session.on?.('Page.javascriptDialogOpening', handler);
36
36
  this._dialogListenersRegistered.add(targetId);
@@ -70,7 +70,7 @@ export class RecordingWatchdog extends BaseWatchdog {
70
70
  await this._startCdpScreencastIfConfigured();
71
71
  }
72
72
  onDetached() {
73
- void this._stopCdpScreencastIfStarted();
73
+ this.runBackground('stop CDP screencast', this._stopCdpScreencastIfStarted());
74
74
  this._detachVideoListeners();
75
75
  }
76
76
  _recordingDisabledByDomainPolicy() {
@@ -161,7 +161,7 @@ export class RecordingWatchdog extends BaseWatchdog {
161
161
  else if (typeof page.removeListener === 'function') {
162
162
  page.removeListener('close', listener);
163
163
  }
164
- void this._captureVideoArtifact(page);
164
+ this.runBackground('capture video artifact', this._captureVideoArtifact(page));
165
165
  };
166
166
  page.on('close', listener);
167
167
  this._videoCloseListeners.set(page, listener);
@@ -222,6 +222,9 @@ export class RecordingWatchdog extends BaseWatchdog {
222
222
  flags: 'a',
223
223
  mode: 0o600,
224
224
  });
225
+ stream.on('error', (error) => {
226
+ this.browser_session.logger.warning(`[RecordingWatchdog] CDP screencast stream error: ${error.message}`);
227
+ });
225
228
  chmodPrivatePath(filePath, 0o600);
226
229
  const handler = (payload) => {
227
230
  const frameData = typeof payload?.data === 'string' ? payload.data : '';
@@ -17,6 +17,7 @@ export declare class CodeAgent {
17
17
  constructor(options: CodeAgentOptions);
18
18
  add_cell(source: string): import("./views.js").CodeCell;
19
19
  execute_cell(source: string): Promise<import("./views.js").CodeCell>;
20
+ private _run_cell;
20
21
  run(max_steps?: number): Promise<CodeAgentHistoryList>;
21
22
  get history(): CodeAgentHistoryList;
22
23
  close(): Promise<void>;
@@ -29,7 +29,9 @@ export class CodeAgent {
29
29
  return this.session.add_cell(source);
30
30
  }
31
31
  async execute_cell(source) {
32
- const cell = this.add_cell(source);
32
+ return this._run_cell(this.add_cell(source));
33
+ }
34
+ async _run_cell(cell) {
33
35
  const startedAt = Date.now() / 1000;
34
36
  cell.status = 'running';
35
37
  cell.execution_count = this.session.increment_execution_count();
@@ -92,7 +94,7 @@ export class CodeAgent {
92
94
  const pending = this.session.cells.filter((cell) => cell.status === 'pending');
93
95
  const toRun = pending.slice(0, Math.max(max_steps, 0));
94
96
  for (const cell of toRun) {
95
- await this.execute_cell(cell.source);
97
+ await this._run_cell(cell);
96
98
  }
97
99
  return this.history;
98
100
  }
@@ -358,7 +358,7 @@ export class Registry {
358
358
  }));
359
359
  replace_sensitive_data(params, sensitiveData, currentUrl) {
360
360
  const secretPattern = /<secret>(.*?)<\/secret>/g;
361
- const applicableSecrets = {};
361
+ const applicableSecrets = Object.create(null);
362
362
  for (const [domainOrKey, content] of Object.entries(sensitiveData)) {
363
363
  if (content && typeof content === 'object' && !Array.isArray(content)) {
364
364
  if (currentUrl &&
@@ -371,6 +371,13 @@ export class Registry {
371
371
  applicableSecrets[domainOrKey] = content;
372
372
  }
373
373
  }
374
+ // Filter out empty values so they are reported as missing instead of
375
+ // silently replacing placeholders with empty strings.
376
+ for (const key of Object.keys(applicableSecrets)) {
377
+ if (!applicableSecrets[key]) {
378
+ delete applicableSecrets[key];
379
+ }
380
+ }
374
381
  const cloneValue = (value) => {
375
382
  if (Array.isArray(value)) {
376
383
  return value.map((item) => cloneValue(item));
@@ -383,21 +390,30 @@ export class Registry {
383
390
  const processed = cloneValue(params);
384
391
  const replaced = new Set();
385
392
  const missing = new Set();
393
+ const resolveSecret = (placeholder) => {
394
+ replaced.add(placeholder);
395
+ const replacement = applicableSecrets[placeholder];
396
+ if (placeholder.endsWith('bu_2fa_code')) {
397
+ return generateTotpCode(replacement);
398
+ }
399
+ return replacement;
400
+ };
386
401
  const traverse = (value) => {
387
402
  if (typeof value === 'string') {
388
- return value.replace(secretPattern, (_, placeholderValue) => {
403
+ const withTagsReplaced = value.replace(secretPattern, (_, placeholderValue) => {
389
404
  const placeholder = String(placeholderValue);
390
405
  if (placeholder in applicableSecrets) {
391
- replaced.add(placeholder);
392
- const replacement = applicableSecrets[placeholder];
393
- if (placeholder.endsWith('bu_2fa_code')) {
394
- return generateTotpCode(replacement);
395
- }
396
- return replacement;
406
+ return resolveSecret(placeholder);
397
407
  }
398
408
  missing.add(placeholder);
399
409
  return `<secret>${placeholder}</secret>`;
400
410
  });
411
+ // Handle literal secrets ("user_name" without tags) for cases where
412
+ // the LLM forgets the <secret> tags but uses the exact placeholder.
413
+ if (withTagsReplaced in applicableSecrets) {
414
+ return resolveSecret(withTagsReplaced);
415
+ }
416
+ return withTagsReplaced;
401
417
  }
402
418
  if (Array.isArray(value)) {
403
419
  return value.map(traverse);
@@ -1,4 +1,4 @@
1
- import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartRefusalParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
2
  export class DeepSeekMessageSerializer {
3
3
  serialize(messages) {
4
4
  return messages.map((message) => this.serializeMessage(message));
@@ -38,9 +38,26 @@ export class DeepSeekMessageSerializer {
38
38
  };
39
39
  }
40
40
  if (message instanceof AssistantMessage) {
41
+ let content = null;
42
+ if (typeof message.content === 'string') {
43
+ content = message.content;
44
+ }
45
+ else if (Array.isArray(message.content)) {
46
+ content = message.content.flatMap((part) => {
47
+ if (part instanceof ContentPartTextParam) {
48
+ return [{ type: 'text', text: part.text }];
49
+ }
50
+ if (part instanceof ContentPartRefusalParam) {
51
+ return [
52
+ { type: 'text', text: `[Refusal] ${part.refusal}` },
53
+ ];
54
+ }
55
+ return [];
56
+ });
57
+ }
41
58
  return {
42
59
  role: 'assistant',
43
- content: typeof message.content === 'string' ? message.content : null,
60
+ content,
44
61
  // DeepSeek supports tool calls in newer models
45
62
  tool_calls: message.tool_calls?.map((toolCall) => ({
46
63
  id: toolCall.id,
@@ -1,4 +1,4 @@
1
- import { GoogleGenAI } from '@google/genai';
1
+ import { GoogleGenAI, ThinkingLevel } from '@google/genai';
2
2
  import { ModelProviderError } from '../exceptions.js';
3
3
  import { ChatInvokeCompletion } from '../views.js';
4
4
  import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
@@ -19,6 +19,12 @@ const buildGoogleHttpOptions = (httpOptions) => {
19
19
  resolvedHttpOptions.headers = headers;
20
20
  return resolvedHttpOptions;
21
21
  };
22
+ const googleThinkingLevelByName = {
23
+ minimal: ThinkingLevel.MINIMAL,
24
+ low: ThinkingLevel.LOW,
25
+ medium: ThinkingLevel.MEDIUM,
26
+ high: ThinkingLevel.HIGH,
27
+ };
22
28
  export class ChatGoogle {
23
29
  model;
24
30
  provider = 'google';
@@ -212,15 +218,17 @@ export class ChatGoogle {
212
218
  async ainvoke(messages, output_format, options = {}) {
213
219
  const serializer = new GoogleMessageSerializer();
214
220
  const { contents, systemInstruction } = serializer.serializeWithSystem(messages, this.includeSystemInUser);
215
- const generationConfig = this.config ? { ...this.config } : {};
221
+ const requestConfig = this.config
222
+ ? { ...this.config }
223
+ : {};
216
224
  if (this.temperature !== null) {
217
- generationConfig.temperature = this.temperature;
225
+ requestConfig.temperature = this.temperature;
218
226
  }
219
227
  if (this.topP !== null) {
220
- generationConfig.topP = this.topP;
228
+ requestConfig.topP = this.topP;
221
229
  }
222
230
  if (this.seed !== null) {
223
- generationConfig.seed = this.seed;
231
+ requestConfig.seed = this.seed;
224
232
  }
225
233
  const isGemini3Pro = this.model.includes('gemini-3-pro');
226
234
  const isGemini3Flash = this.model.includes('gemini-3-flash');
@@ -229,18 +237,18 @@ export class ChatGoogle {
229
237
  if (level === 'minimal' || level === 'medium') {
230
238
  level = 'low';
231
239
  }
232
- generationConfig.thinkingConfig = {
233
- thinkingLevel: level.toUpperCase(),
240
+ requestConfig.thinkingConfig = {
241
+ thinkingLevel: googleThinkingLevelByName[level],
234
242
  };
235
243
  }
236
244
  else if (isGemini3Flash) {
237
245
  if (this.thinkingLevel !== null) {
238
- generationConfig.thinkingConfig = {
239
- thinkingLevel: this.thinkingLevel.toUpperCase(),
246
+ requestConfig.thinkingConfig = {
247
+ thinkingLevel: googleThinkingLevelByName[this.thinkingLevel],
240
248
  };
241
249
  }
242
250
  else {
243
- generationConfig.thinkingConfig = {
251
+ requestConfig.thinkingConfig = {
244
252
  thinkingBudget: this.thinkingBudget === null ? -1 : this.thinkingBudget,
245
253
  };
246
254
  }
@@ -253,11 +261,11 @@ export class ChatGoogle {
253
261
  budget = -1;
254
262
  }
255
263
  if (budget !== null) {
256
- generationConfig.thinkingConfig = { thinkingBudget: budget };
264
+ requestConfig.thinkingConfig = { thinkingBudget: budget };
257
265
  }
258
266
  }
259
267
  if (this.maxOutputTokens !== null) {
260
- generationConfig.maxOutputTokens = this.maxOutputTokens;
268
+ requestConfig.maxOutputTokens = this.maxOutputTokens;
261
269
  }
262
270
  // Try to get schema from output_format
263
271
  const schemaForJson = (() => {
@@ -289,8 +297,8 @@ export class ChatGoogle {
289
297
  }
290
298
  }
291
299
  if (cleanSchemaForJson && this.supportsStructuredOutput) {
292
- generationConfig.responseMimeType = 'application/json';
293
- generationConfig.responseSchema = cleanSchemaForJson;
300
+ requestConfig.responseMimeType = 'application/json';
301
+ requestConfig.responseSchema = cleanSchemaForJson;
294
302
  }
295
303
  const requestContents = contents.map((entry) => ({
296
304
  ...entry,
@@ -309,22 +317,25 @@ export class ChatGoogle {
309
317
  }
310
318
  }
311
319
  }
312
- const request = {
313
- model: this.model,
314
- contents: requestContents,
315
- };
316
320
  if (systemInstruction && !this.includeSystemInUser) {
317
- request.systemInstruction = {
321
+ requestConfig.systemInstruction = {
318
322
  role: 'system',
319
323
  parts: [{ text: systemInstruction }],
320
324
  };
321
325
  }
322
- if (Object.keys(generationConfig).length > 0) {
323
- request.generationConfig = generationConfig;
326
+ if (options.signal) {
327
+ requestConfig.abortSignal = options.signal;
328
+ }
329
+ const request = {
330
+ model: this.model,
331
+ contents: requestContents,
332
+ };
333
+ if (Object.keys(requestConfig).length > 0) {
334
+ request.config = requestConfig;
324
335
  }
325
336
  for (let attempt = 0; attempt < this.maxRetries; attempt += 1) {
326
337
  try {
327
- const result = await this.client.models.generateContent(request, options.signal ? { signal: options.signal } : undefined);
338
+ const result = await this.client.models.generateContent(request);
328
339
  const candidate = result.candidates?.[0];
329
340
  const textParts = candidate?.content?.parts?.filter((p) => p.text) || [];
330
341
  const text = textParts.map((p) => p.text).join('');
@@ -45,9 +45,12 @@ export class GroqMessageSerializer {
45
45
  arguments: toolCall.functionCall.arguments,
46
46
  },
47
47
  }));
48
+ // Groq expects assistant content as plain text; AssistantMessage.text
49
+ // already joins the text parts (refusal parts excluded).
50
+ const content = message.content == null ? null : message.text;
48
51
  return {
49
52
  role: 'assistant',
50
- content: typeof message.content === 'string' ? message.content : null,
53
+ content,
51
54
  tool_calls: toolCalls,
52
55
  };
53
56
  }
@@ -1,4 +1,4 @@
1
- import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartRefusalParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
2
  export class OpenAIMessageSerializer {
3
3
  serialize(messages) {
4
4
  return messages.map((message) => this.serializeMessage(message));
@@ -45,9 +45,24 @@ export class OpenAIMessageSerializer {
45
45
  arguments: toolCall.functionCall.arguments,
46
46
  },
47
47
  }));
48
+ let content = null;
49
+ if (typeof message.content === 'string') {
50
+ content = message.content;
51
+ }
52
+ else if (Array.isArray(message.content)) {
53
+ content = message.content.flatMap((part) => {
54
+ if (part instanceof ContentPartTextParam) {
55
+ return [{ type: 'text', text: part.text }];
56
+ }
57
+ if (part instanceof ContentPartRefusalParam) {
58
+ return [{ type: 'refusal', refusal: part.refusal }];
59
+ }
60
+ return [];
61
+ });
62
+ }
48
63
  return {
49
64
  role: 'assistant',
50
- content: typeof message.content === 'string' ? message.content : null, // OpenAI expects string or null for content in assistant message if tool_calls are present
65
+ content,
51
66
  tool_calls: toolCalls,
52
67
  refusal: message.refusal || undefined,
53
68
  };
@@ -979,7 +979,7 @@ export const run_direct_command = async (argv, options = {}) => {
979
979
  writeLine(environment.stdout, 'Cleared 0 cookies');
980
980
  }
981
981
  else {
982
- const addCookies = session.browser_context.addCookies;
982
+ const addCookies = session.browser_context.addCookies?.bind(session.browser_context);
983
983
  if (blockedCookies.length > 0 && !addCookies) {
984
984
  throw new Error('Browser context does not support preserving blocked cookies');
985
985
  }
@@ -996,7 +996,7 @@ export const run_direct_command = async (argv, options = {}) => {
996
996
  const allCookies = (await session.get_cookies?.({ include_blocked: true })) ?? [];
997
997
  const remaining = allCookies.filter((cookie) => !cookieMatchesUrl(cookie, url));
998
998
  const removedCount = allCookies.length - remaining.length;
999
- const addCookies = session.browser_context.addCookies;
999
+ const addCookies = session.browser_context.addCookies?.bind(session.browser_context);
1000
1000
  if (remaining.length > 0 && !addCookies) {
1001
1001
  throw new Error('Browser context does not support preserving non-matching cookies');
1002
1002
  }
@@ -236,9 +236,9 @@ export class TokenCost {
236
236
  return {
237
237
  new_prompt_tokens: usage.prompt_tokens,
238
238
  new_prompt_cost: uncachedPrompt * (pricing.input_cost_per_token ?? 0),
239
- prompt_read_cached_tokens: cached || null,
240
- prompt_read_cached_cost: cached
241
- ? cached * (pricing.cache_read_input_token_cost ?? 0)
239
+ prompt_read_cached_tokens: usage.prompt_cached_tokens ?? null,
240
+ prompt_read_cached_cost: cached && pricing.cache_read_input_token_cost
241
+ ? cached * pricing.cache_read_input_token_cost
242
242
  : null,
243
243
  prompt_cached_creation_tokens: usage.prompt_cache_creation_tokens ?? null,
244
244
  prompt_cache_creation_cost: usage.prompt_cache_creation_tokens &&
package/dist/utils.js CHANGED
@@ -196,7 +196,7 @@ export const is_unsafe_pattern = (pattern) => {
196
196
  const [, ...rest] = pattern.split('://');
197
197
  pattern = rest.join('://');
198
198
  }
199
- const bare_domain = pattern.replace('.*', '').replace('*.', '');
199
+ const bare_domain = pattern.replaceAll('.*', '').replaceAll('*.', '');
200
200
  return bare_domain.includes('*');
201
201
  };
202
202
  export const merge_dicts = (a, b, path = []) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-use",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "A TypeScript-first library for programmatic browser control, designed for building AI-powered web agents.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -286,6 +286,12 @@
286
286
  "test:coverage": "vitest run --coverage",
287
287
  "test:watch": "vitest --watch",
288
288
  "test:pack": "node scripts/smoke-pack.mjs",
289
+ "version:check": "node scripts/update-version.mjs --check",
290
+ "version:sync": "node scripts/update-version.mjs sync",
291
+ "version:bump": "node scripts/update-version.mjs",
292
+ "version:patch": "node scripts/update-version.mjs patch",
293
+ "version:minor": "node scripts/update-version.mjs minor",
294
+ "version:major": "node scripts/update-version.mjs major",
289
295
  "check": "pnpm lint && pnpm typecheck && pnpm typecheck:test && pnpm test:unit && pnpm test:integration && pnpm test:e2e && pnpm test:pack",
290
296
  "commit": "cz",
291
297
  "typecheck": "tsc --noEmit",
@@ -354,7 +360,7 @@
354
360
  "@types/turndown": "^5.0.6",
355
361
  "@typescript-eslint/eslint-plugin": "^8.54.0",
356
362
  "@typescript-eslint/parser": "^8.54.0",
357
- "@vitest/coverage-v8": "^4.0.18",
363
+ "@vitest/coverage-v8": "^4.1.8",
358
364
  "commitizen": "^4.3.1",
359
365
  "cz-conventional-changelog": "^3.3.0",
360
366
  "eslint": "^9.39.2",
@@ -366,7 +372,7 @@
366
372
  "tsx": "^4.21.0",
367
373
  "typescript": "^5.9.3",
368
374
  "vite": "^7.3.2",
369
- "vitest": "^4.0.18"
375
+ "vitest": "^4.1.8"
370
376
  },
371
377
  "pnpm": {
372
378
  "onlyBuiltDependencies": [
@@ -384,7 +390,7 @@
384
390
  "fast-xml-builder": "1.2.0",
385
391
  "fast-xml-parser": "5.7.3",
386
392
  "flatted": "3.4.2",
387
- "hono": "4.12.18",
393
+ "hono": "4.12.23",
388
394
  "ip-address": "10.2.0",
389
395
  "lodash": "4.18.1",
390
396
  "minimatch": "10.2.4",