browser-pilot 0.0.16 → 0.0.18

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 (34) hide show
  1. package/README.md +39 -0
  2. package/dist/actions.cjs +797 -69
  3. package/dist/actions.d.cts +101 -4
  4. package/dist/actions.d.ts +101 -4
  5. package/dist/actions.mjs +17 -1
  6. package/dist/{browser-ZCR6AA4D.mjs → browser-GHQRYU4R.mjs} +2 -2
  7. package/dist/browser.cjs +1366 -72
  8. package/dist/browser.d.cts +230 -6
  9. package/dist/browser.d.ts +230 -6
  10. package/dist/browser.mjs +37 -5
  11. package/dist/{chunk-EZNZ72VA.mjs → chunk-ASEIFKKV.mjs} +126 -0
  12. package/dist/{chunk-TJ5B56NV.mjs → chunk-FSB25GRR.mjs} +129 -1
  13. package/dist/chunk-MIJ7UIKB.mjs +96 -0
  14. package/dist/{chunk-6GBYX7C2.mjs → chunk-MRY3HRFJ.mjs} +799 -353
  15. package/dist/chunk-OIHU7OFY.mjs +91 -0
  16. package/dist/{chunk-NNEHWWHL.mjs → chunk-SW52ALBD.mjs} +588 -5
  17. package/dist/{chunk-V3VLBQAM.mjs → chunk-ZDODXEBD.mjs} +586 -69
  18. package/dist/cli.mjs +784 -176
  19. package/dist/combobox-RAKBA2BW.mjs +6 -0
  20. package/dist/index.cjs +1669 -71
  21. package/dist/index.d.cts +58 -7
  22. package/dist/index.d.ts +58 -7
  23. package/dist/index.mjs +192 -3
  24. package/dist/{page-IUUTJ3SW.mjs → page-SD64DY3F.mjs} +1 -1
  25. package/dist/providers.cjs +127 -0
  26. package/dist/providers.d.cts +38 -3
  27. package/dist/providers.d.ts +38 -3
  28. package/dist/providers.mjs +3 -1
  29. package/dist/{types-BzM-IfsL.d.ts → types-B_v62K7C.d.ts} +146 -2
  30. package/dist/{types-DeVSWhXj.d.cts → types-D2pJQpWs.d.cts} +7 -1
  31. package/dist/{types-DeVSWhXj.d.ts → types-D2pJQpWs.d.ts} +7 -1
  32. package/dist/{types-BflRmiDz.d.cts → types-Yuybzq53.d.cts} +146 -2
  33. package/dist/upload-E6MCC2OF.mjs +6 -0
  34. package/package.json +10 -3
@@ -2,6 +2,108 @@ import {
2
2
  createCDPClient
3
3
  } from "./chunk-BVZALQT4.mjs";
4
4
 
5
+ // src/providers/browser-use.ts
6
+ var BrowserUseProvider = class {
7
+ name = "browser-use";
8
+ apiKey;
9
+ baseUrl;
10
+ proxyCountryCode;
11
+ profileId;
12
+ timeout;
13
+ allowResizing;
14
+ customProxy;
15
+ constructor(options) {
16
+ this.apiKey = options.apiKey;
17
+ this.baseUrl = options.baseUrl ?? "https://api.browser-use.com/api/v2";
18
+ this.proxyCountryCode = options.proxyCountryCode === void 0 ? "uk" : options.proxyCountryCode;
19
+ this.profileId = options.profileId;
20
+ this.timeout = options.timeout;
21
+ this.allowResizing = options.allowResizing;
22
+ this.customProxy = options.customProxy;
23
+ }
24
+ async createSession(options = {}) {
25
+ const body = {};
26
+ body["proxyCountryCode"] = this.proxyCountryCode;
27
+ if (options.width) body["browserScreenWidth"] = options.width;
28
+ if (options.height) body["browserScreenHeight"] = options.height;
29
+ if (this.profileId) body["profileId"] = this.profileId;
30
+ if (this.timeout !== void 0) body["timeout"] = this.timeout;
31
+ if (this.allowResizing !== void 0) body["allowResizing"] = this.allowResizing;
32
+ if (this.customProxy) body["customProxy"] = this.customProxy;
33
+ const response = await fetch(`${this.baseUrl}/browsers`, {
34
+ method: "POST",
35
+ headers: {
36
+ "X-Browser-Use-API-Key": this.apiKey,
37
+ "Content-Type": "application/json"
38
+ },
39
+ body: JSON.stringify(body)
40
+ });
41
+ if (!response.ok) {
42
+ const text = await response.text();
43
+ this.throwApiError(response.status, text);
44
+ }
45
+ const session = await response.json();
46
+ if (!session.cdpUrl) {
47
+ throw new Error("Browser Use session does not have a cdpUrl");
48
+ }
49
+ return this.toProviderSession(session);
50
+ }
51
+ async resumeSession(sessionId) {
52
+ const response = await fetch(`${this.baseUrl}/browsers/${sessionId}`, {
53
+ headers: {
54
+ "X-Browser-Use-API-Key": this.apiKey
55
+ }
56
+ });
57
+ if (!response.ok) {
58
+ const text = await response.text();
59
+ throw new Error(`Browser Use resumeSession failed: ${response.status} ${text}`);
60
+ }
61
+ const session = await response.json();
62
+ if (session.status !== "active" || !session.cdpUrl) {
63
+ throw new Error(
64
+ "Browser Use session is not active or does not have a cdpUrl (may be stopped)"
65
+ );
66
+ }
67
+ return this.toProviderSession(session);
68
+ }
69
+ toProviderSession(session) {
70
+ return {
71
+ wsUrl: session.cdpUrl,
72
+ sessionId: session.id,
73
+ metadata: {
74
+ liveUrl: session.liveUrl,
75
+ status: session.status,
76
+ timeoutAt: session.timeoutAt,
77
+ proxyCountryCode: this.proxyCountryCode
78
+ },
79
+ close: async () => {
80
+ await fetch(`${this.baseUrl}/browsers/${session.id}`, {
81
+ method: "PATCH",
82
+ headers: {
83
+ "X-Browser-Use-API-Key": this.apiKey,
84
+ "Content-Type": "application/json"
85
+ },
86
+ body: JSON.stringify({ action: "stop" })
87
+ });
88
+ }
89
+ };
90
+ }
91
+ throwApiError(status, body) {
92
+ switch (status) {
93
+ case 402:
94
+ throw new Error(`Browser Use: insufficient credits (min $0.10 required). ${body}`);
95
+ case 403:
96
+ throw new Error(`Browser Use: invalid API key. ${body}`);
97
+ case 422:
98
+ throw new Error(`Browser Use: validation error. ${body}`);
99
+ case 429:
100
+ throw new Error(`Browser Use: rate limit exceeded. ${body}`);
101
+ default:
102
+ throw new Error(`Browser Use createSession failed: ${status} ${body}`);
103
+ }
104
+ }
105
+ };
106
+
5
107
  // src/providers/browserbase.ts
6
108
  var BrowserBaseProvider = class {
7
109
  name = "browserbase";
@@ -514,6 +616,17 @@ async function resolveBrowserEndpoint(options = {}, deps = defaultDependencies)
514
616
  );
515
617
  }
516
618
 
619
+ // src/runtime/env.ts
620
+ function getProcessEnv() {
621
+ if (typeof globalThis.process !== "undefined" && globalThis.process.env) {
622
+ return globalThis.process.env;
623
+ }
624
+ return {};
625
+ }
626
+ function getEnv(name) {
627
+ return getProcessEnv()[name];
628
+ }
629
+
517
630
  // src/providers/index.ts
518
631
  function createProvider(options) {
519
632
  switch (options.provider) {
@@ -535,6 +648,18 @@ function createProvider(options) {
535
648
  return new BrowserlessProvider({
536
649
  token: options.apiKey
537
650
  });
651
+ case "browser-use": {
652
+ const apiKey = options.apiKey ?? getEnv("BROWSER_USE_API_KEY");
653
+ if (!apiKey) {
654
+ throw new Error("Browser Use provider requires apiKey or BROWSER_USE_API_KEY env var");
655
+ }
656
+ return new BrowserUseProvider({
657
+ apiKey,
658
+ proxyCountryCode: options.proxyCountryCode === void 0 ? "uk" : options.proxyCountryCode,
659
+ profileId: options.profileId,
660
+ timeout: options.cloudTimeout
661
+ });
662
+ }
538
663
  case "generic":
539
664
  if (!options.wsUrl) {
540
665
  throw new Error("Generic provider requires wsUrl");
@@ -548,6 +673,7 @@ function createProvider(options) {
548
673
  }
549
674
 
550
675
  export {
676
+ BrowserUseProvider,
551
677
  BrowserBaseProvider,
552
678
  BrowserlessProvider,
553
679
  GenericProvider,
@@ -3,7 +3,109 @@ import {
3
3
  } from "./chunk-LCNFBXB5.mjs";
4
4
  import {
5
5
  Page
6
- } from "./chunk-6GBYX7C2.mjs";
6
+ } from "./chunk-MRY3HRFJ.mjs";
7
+
8
+ // src/providers/browser-use.ts
9
+ var BrowserUseProvider = class {
10
+ name = "browser-use";
11
+ apiKey;
12
+ baseUrl;
13
+ proxyCountryCode;
14
+ profileId;
15
+ timeout;
16
+ allowResizing;
17
+ customProxy;
18
+ constructor(options) {
19
+ this.apiKey = options.apiKey;
20
+ this.baseUrl = options.baseUrl ?? "https://api.browser-use.com/api/v2";
21
+ this.proxyCountryCode = options.proxyCountryCode === void 0 ? "uk" : options.proxyCountryCode;
22
+ this.profileId = options.profileId;
23
+ this.timeout = options.timeout;
24
+ this.allowResizing = options.allowResizing;
25
+ this.customProxy = options.customProxy;
26
+ }
27
+ async createSession(options = {}) {
28
+ const body = {};
29
+ body["proxyCountryCode"] = this.proxyCountryCode;
30
+ if (options.width) body["browserScreenWidth"] = options.width;
31
+ if (options.height) body["browserScreenHeight"] = options.height;
32
+ if (this.profileId) body["profileId"] = this.profileId;
33
+ if (this.timeout !== void 0) body["timeout"] = this.timeout;
34
+ if (this.allowResizing !== void 0) body["allowResizing"] = this.allowResizing;
35
+ if (this.customProxy) body["customProxy"] = this.customProxy;
36
+ const response = await fetch(`${this.baseUrl}/browsers`, {
37
+ method: "POST",
38
+ headers: {
39
+ "X-Browser-Use-API-Key": this.apiKey,
40
+ "Content-Type": "application/json"
41
+ },
42
+ body: JSON.stringify(body)
43
+ });
44
+ if (!response.ok) {
45
+ const text = await response.text();
46
+ this.throwApiError(response.status, text);
47
+ }
48
+ const session = await response.json();
49
+ if (!session.cdpUrl) {
50
+ throw new Error("Browser Use session does not have a cdpUrl");
51
+ }
52
+ return this.toProviderSession(session);
53
+ }
54
+ async resumeSession(sessionId) {
55
+ const response = await fetch(`${this.baseUrl}/browsers/${sessionId}`, {
56
+ headers: {
57
+ "X-Browser-Use-API-Key": this.apiKey
58
+ }
59
+ });
60
+ if (!response.ok) {
61
+ const text = await response.text();
62
+ throw new Error(`Browser Use resumeSession failed: ${response.status} ${text}`);
63
+ }
64
+ const session = await response.json();
65
+ if (session.status !== "active" || !session.cdpUrl) {
66
+ throw new Error(
67
+ "Browser Use session is not active or does not have a cdpUrl (may be stopped)"
68
+ );
69
+ }
70
+ return this.toProviderSession(session);
71
+ }
72
+ toProviderSession(session) {
73
+ return {
74
+ wsUrl: session.cdpUrl,
75
+ sessionId: session.id,
76
+ metadata: {
77
+ liveUrl: session.liveUrl,
78
+ status: session.status,
79
+ timeoutAt: session.timeoutAt,
80
+ proxyCountryCode: this.proxyCountryCode
81
+ },
82
+ close: async () => {
83
+ await fetch(`${this.baseUrl}/browsers/${session.id}`, {
84
+ method: "PATCH",
85
+ headers: {
86
+ "X-Browser-Use-API-Key": this.apiKey,
87
+ "Content-Type": "application/json"
88
+ },
89
+ body: JSON.stringify({ action: "stop" })
90
+ });
91
+ }
92
+ };
93
+ }
94
+ throwApiError(status, body) {
95
+ switch (status) {
96
+ case 402:
97
+ throw new Error(`Browser Use: insufficient credits (min $0.10 required). ${body}`);
98
+ case 403:
99
+ throw new Error(`Browser Use: invalid API key. ${body}`);
100
+ case 422:
101
+ throw new Error(`Browser Use: validation error. ${body}`);
102
+ case 429:
103
+ throw new Error(`Browser Use: rate limit exceeded. ${body}`);
104
+ default:
105
+ throw new Error(`Browser Use createSession failed: ${status} ${body}`);
106
+ }
107
+ }
108
+ };
7
109
 
8
110
  // src/providers/browserbase.ts
9
111
  var BrowserBaseProvider = class {
@@ -514,6 +616,17 @@ async function resolveBrowserEndpoint(options = {}, deps = defaultDependencies)
514
616
  );
515
617
  }
516
618
 
619
+ // src/runtime/env.ts
620
+ function getProcessEnv() {
621
+ if (typeof globalThis.process !== "undefined" && globalThis.process.env) {
622
+ return globalThis.process.env;
623
+ }
624
+ return {};
625
+ }
626
+ function getEnv(name) {
627
+ return getProcessEnv()[name];
628
+ }
629
+
517
630
  // src/providers/index.ts
518
631
  function createProvider(options) {
519
632
  switch (options.provider) {
@@ -535,6 +648,18 @@ function createProvider(options) {
535
648
  return new BrowserlessProvider({
536
649
  token: options.apiKey
537
650
  });
651
+ case "browser-use": {
652
+ const apiKey = options.apiKey ?? getEnv("BROWSER_USE_API_KEY");
653
+ if (!apiKey) {
654
+ throw new Error("Browser Use provider requires apiKey or BROWSER_USE_API_KEY env var");
655
+ }
656
+ return new BrowserUseProvider({
657
+ apiKey,
658
+ proxyCountryCode: options.proxyCountryCode === void 0 ? "uk" : options.proxyCountryCode,
659
+ profileId: options.profileId,
660
+ timeout: options.cloudTimeout
661
+ });
662
+ }
538
663
  case "generic":
539
664
  if (!options.wsUrl) {
540
665
  throw new Error("Generic provider requires wsUrl");
@@ -611,6 +736,9 @@ var Browser = class _Browser {
611
736
  }
612
737
  const provider = createProvider(connectOptions);
613
738
  const session = await provider.createSession(connectOptions.session);
739
+ if (session.metadata?.["liveUrl"]) {
740
+ console.error(`Live viewer: ${session.metadata["liveUrl"]}`);
741
+ }
614
742
  const cdp = await createCDPClient(session.wsUrl, {
615
743
  debug: connectOptions.debug,
616
744
  timeout: connectOptions.timeout
@@ -0,0 +1,96 @@
1
+ // src/browser/combobox.ts
2
+ var DEFAULT_LISTBOX_SELECTORS = [
3
+ '[role="listbox"]',
4
+ '[role="menu"]',
5
+ '[role="tree"]',
6
+ 'ul[class*="dropdown"]',
7
+ 'ul[class*="option"]',
8
+ 'ul[class*="list"]',
9
+ 'div[class*="dropdown"]',
10
+ 'div[class*="menu"]'
11
+ ];
12
+ var DEFAULT_OPTION_SELECTORS = [
13
+ '[role="option"]',
14
+ '[role="menuitem"]',
15
+ '[role="treeitem"]',
16
+ "li"
17
+ ];
18
+ async function chooseOption(page, config) {
19
+ const {
20
+ trigger,
21
+ listbox,
22
+ optionSelector,
23
+ searchText,
24
+ value,
25
+ match = "contains",
26
+ timeout = 1e4
27
+ } = config;
28
+ try {
29
+ await page.click(trigger, { timeout });
30
+ const listboxSelectors = listbox ? Array.isArray(listbox) ? listbox : [listbox] : DEFAULT_LISTBOX_SELECTORS;
31
+ const listboxFound = await page.waitFor(listboxSelectors, {
32
+ timeout: Math.min(timeout, 3e3),
33
+ optional: true,
34
+ state: "visible"
35
+ });
36
+ if (!listboxFound) {
37
+ return {
38
+ success: false,
39
+ failedAt: "open",
40
+ error: "Listbox did not appear after clicking trigger"
41
+ };
42
+ }
43
+ if (searchText) {
44
+ try {
45
+ const triggerSel = Array.isArray(trigger) ? trigger[0] : trigger;
46
+ await page.type(triggerSel, searchText, {
47
+ delay: 30,
48
+ timeout: Math.min(timeout, 3e3)
49
+ });
50
+ await new Promise((resolve) => setTimeout(resolve, 200));
51
+ } catch {
52
+ return { success: false, failedAt: "search", error: "Failed to type search text" };
53
+ }
54
+ }
55
+ const optionSelectors = optionSelector ? [optionSelector] : DEFAULT_OPTION_SELECTORS;
56
+ const matchFn = match === "exact" ? "exact" : match === "startsWith" ? "startsWith" : "contains";
57
+ const clickedOption = await page.evaluate(`(() => {
58
+ const selectors = ${JSON.stringify(optionSelectors)};
59
+ const targetValue = ${JSON.stringify(value)};
60
+ const matchMode = ${JSON.stringify(matchFn)};
61
+
62
+ for (const sel of selectors) {
63
+ const options = document.querySelectorAll(sel);
64
+ for (const opt of options) {
65
+ const text = (opt.textContent || '').trim();
66
+ let matches = false;
67
+ if (matchMode === 'exact') matches = text === targetValue;
68
+ else if (matchMode === 'startsWith') matches = text.startsWith(targetValue);
69
+ else matches = text.includes(targetValue);
70
+
71
+ if (matches) {
72
+ opt.click();
73
+ return text;
74
+ }
75
+ }
76
+ }
77
+ return null;
78
+ })()`);
79
+ if (!clickedOption) {
80
+ return { success: false, failedAt: "select", error: `No option matching "${value}" found` };
81
+ }
82
+ return {
83
+ success: true,
84
+ selectedText: String(clickedOption)
85
+ };
86
+ } catch (error) {
87
+ return {
88
+ success: false,
89
+ error: error instanceof Error ? error.message : String(error)
90
+ };
91
+ }
92
+ }
93
+
94
+ export {
95
+ chooseOption
96
+ };