arn-browser 0.1.6 → 0.1.8

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 (24) hide show
  1. package/bin/cli.js +43 -0
  2. package/bin/install.js +420 -0
  3. package/package.json +8 -3
  4. package/src/index.d.ts +16 -6
  5. package/src/index.js +7 -4
  6. package/src/utility/{multilogin_token_manager.js → mlx_token.js} +32 -43
  7. package/src/utility/{launchBrowser.d.ts → playwright/pwLaunch.d.ts} +15 -7
  8. package/src/utility/{launchBrowser.js → playwright/pwLaunch.js} +61 -30
  9. package/src/{all_routes/routeWithSuperagent.d.ts → utility/playwright/routes/pwRoute.d.ts} +4 -4
  10. package/src/{all_routes/routeWithSuperagent.js → utility/playwright/routes/pwRoute.js} +2 -2
  11. package/src/utility/proxy-utility/proxy-chain.js +4 -3
  12. package/src/utility/proxy-utility/proxy-helper.js +1 -1
  13. package/src/utility/puppeteer/ppLaunch.d.ts +199 -0
  14. package/src/utility/puppeteer/ppLaunch.js +723 -0
  15. package/src/utility/puppeteer/routes/ppRoute.d.ts +64 -0
  16. package/src/utility/puppeteer/routes/ppRoute.js +326 -0
  17. /package/src/{human-cursor → utility/playwright/human-cursor}/HumanCursor.js +0 -0
  18. /package/src/{human-cursor → utility/playwright/human-cursor}/bezier.js +0 -0
  19. /package/src/{human-cursor → utility/playwright/human-cursor}/index.d.ts +0 -0
  20. /package/src/{human-cursor → utility/playwright/human-cursor}/index.js +0 -0
  21. /package/src/{human-cursor → utility/playwright/human-cursor}/randomizer.js +0 -0
  22. /package/src/{human-cursor → utility/playwright/human-cursor}/tweening.js +0 -0
  23. /package/src/utility/{playwright-helper.d.ts → playwright/playwright-helper.d.ts} +0 -0
  24. /package/src/utility/{playwright-helper.js → playwright/playwright-helper.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { Browser, BrowserContext, Page } from "playwright";
2
2
  import type { FingerprintGeneratorOptions } from "fingerprint-generator";
3
- import type { HumanPage, CreateCursorOptions } from "../human-cursor/index";
3
+ import type { HumanPage, CreateCursorOptions } from "./human-cursor/index";
4
4
  type Screen = FingerprintGeneratorOptions["screen"];
5
5
  /**
6
6
  * Proxy configuration object.
@@ -119,7 +119,7 @@ export interface MultiloginOptions {
119
119
  /**
120
120
  * Options for launching the browser.
121
121
  */
122
- export interface LaunchOptions {
122
+ export interface PwLaunchOptions {
123
123
  // ========================================================================
124
124
  // 1. GENERAL & NETWORK
125
125
  // ========================================================================
@@ -141,7 +141,15 @@ export interface LaunchOptions {
141
141
 
142
142
  /**
143
143
  * Which browser engine to launch.
144
- * Default: "chromium"
144
+ *
145
+ * - `"chromium"`: Playwright's bundled Chromium
146
+ * - `"chrome"`: Alias for Chromium
147
+ * - `"firefox"`: Playwright's bundled Firefox
148
+ * - `"brave"`: Brave Browser (requires local binary)
149
+ * - `"camoufox"`: Camoufox anti-detect Firefox (requires local binary)
150
+ * - `"multilogin"`: Multilogin anti-detect browser (via API)
151
+ *
152
+ * Default: `"chromium"`
145
153
  */
146
154
  which_browser?: "chromium" | "chrome" | "firefox" | "brave" | "braveLauncher" | "camoufox" | "multilogin";
147
155
 
@@ -152,8 +160,8 @@ export interface LaunchOptions {
152
160
  /**
153
161
  * Path to a persistent profile.
154
162
  * - If absolute path: Uses that path exactly (no prefix added).
155
- * - If folder name: Creates inside `~/.arn-browser/persistent/` AND adds a browser prefix (e.g., `brave_myProfile`).
156
- * - If null: Creates a temporary, random profile in `~/.arn-browser/temp/`.
163
+ * - If folder name: Creates inside `~/.arn-browser/pw/persistent/` AND adds a browser prefix (e.g., `brave_myProfile`).
164
+ * - If null: Creates a temporary, random profile in `~/.arn-browser/pw/temp/`.
157
165
  */
158
166
  profile_path?: string | null;
159
167
 
@@ -293,9 +301,9 @@ export interface BrowserControllerError {
293
301
  * The object returned by launchBrowser.
294
302
  * Check launchError to discriminate between success and failure states.
295
303
  */
296
- export type BrowserController = BrowserControllerSuccess | BrowserControllerError;
304
+ export type PwBrowserController = BrowserControllerSuccess | BrowserControllerError;
297
305
 
298
306
  /**
299
307
  * Launches a browser based on the provided options.
300
308
  */
301
- export function launchBrowser(options: LaunchOptions): Promise<BrowserController>;
309
+ export function pwLaunch(options?: PwLaunchOptions): Promise<PwBrowserController>;
@@ -17,11 +17,11 @@ import { newInjectedContext, FingerprintInjector } from "fingerprint-injector";
17
17
  import { FingerprintGenerator } from "fingerprint-generator";
18
18
 
19
19
  // Internal Utilities
20
- import { getMultiloginToken } from "./multilogin_token_manager.js";
21
- import { deleteDirectoryWithRetries } from "./deleteDirectory.js";
20
+ import { getMultiloginToken } from "../mlx_token.js";
21
+ import { deleteDirectoryWithRetries } from "../deleteDirectory.js";
22
22
 
23
23
  // Human Cursor - for human-like mouse movements
24
- import { createCursor } from "../human-cursor/index.js";
24
+ import { createCursor } from "./human-cursor/index.js";
25
25
 
26
26
  // Camoufox Special
27
27
  import { launchOptions } from "camoufox-js";
@@ -40,7 +40,8 @@ const detectedOs = osMap[process.platform] || "windows";
40
40
  const MULTILOGIN_LAUNCHER_URL = "https://launcher.mlx.yt:45001";
41
41
  const MULTILOGIN_FOLDER_ID = "bad9e7e1-cfab-4c8d-bd19-91aa82929711";
42
42
 
43
- const BASE_PROFILE_DIR = path.join(os.homedir(), ".arn-browser");
43
+ const ARN_BROWSER_DIR = path.join(os.homedir(), ".arn-browser");
44
+ const BASE_PROFILE_DIR = path.join(ARN_BROWSER_DIR, "profiles", "pw");
44
45
  const PERSISTENT_DIR = path.join(BASE_PROFILE_DIR, "persistent");
45
46
  const TEMP_DIR = path.join(BASE_PROFILE_DIR, "temp");
46
47
 
@@ -75,37 +76,63 @@ function resolveProfilePath(nameOrPath, browserName) {
75
76
 
76
77
  /**
77
78
  * Locates binaries for manual browsers (Brave).
79
+ * Uses ~/.arn-browser/browsers/{browser}/{executable}
78
80
  */
79
81
  function getBinaryPath(browserName) {
80
82
  const isWindows = process.platform === "win32";
81
- const homeDir = os.homedir();
83
+ const browsersDir = path.join(ARN_BROWSER_DIR, "browsers");
82
84
 
83
- let binaryPath = "";
85
+ const binaryMap = {
86
+ brave: isWindows
87
+ ? path.join(browsersDir, "brave", "brave.exe")
88
+ : path.join(browsersDir, "brave", "brave"),
89
+ };
84
90
 
85
- if (browserName === "brave") {
86
- if (isWindows) {
87
- // Windows: Standard custom install path in Downloads
88
- binaryPath = path.join(homeDir, "Downloads", "brave", "brave.exe");
89
- } else {
90
- // Linux: Primary check in .cache (common for script installs)
91
- const cachePath = path.join(homeDir, ".cache", "brave", "brave");
92
- const downloadsPath = path.join(homeDir, "Downloads", "brave", "brave");
93
-
94
- if (fs.existsSync(cachePath)) {
95
- binaryPath = cachePath;
96
- } else if (fs.existsSync(downloadsPath)) {
97
- binaryPath = downloadsPath;
98
- } else {
99
- // Default to cache path for the error message if neither is found
100
- binaryPath = cachePath;
101
- }
102
- }
91
+ const binaryPath = binaryMap[browserName];
92
+ if (!binaryPath) {
93
+ throw new Error(
94
+ `░░░░░ [LaunchBrowser] Unknown browser for getBinaryPath: ${browserName}`
95
+ );
96
+ }
97
+
98
+ if (!fs.existsSync(binaryPath)) {
99
+ throw new Error(
100
+ `░░░░░ [LaunchBrowser] ${browserName} binary not found at: ${binaryPath}\n` +
101
+ ` Run "node bin/cli.js install" to install browsers.`
102
+ );
103
+ }
104
+
105
+ return binaryPath;
106
+ }
107
+
108
+ /**
109
+ * Gets the executable path for Playwright-managed browsers (Chromium, Firefox).
110
+ * Uses ~/.arn-browser/browsers/{browser}/{executable}
111
+ */
112
+ function getPlaywrightExePath(browserName) {
113
+ const isWindows = process.platform === "win32";
114
+ const browsersDir = path.join(ARN_BROWSER_DIR, "browsers");
115
+
116
+ const binaryMap = {
117
+ chromium: isWindows
118
+ ? path.join(browsersDir, "chromium", "chrome.exe")
119
+ : path.join(browsersDir, "chromium", "chrome"),
120
+ firefox: isWindows
121
+ ? path.join(browsersDir, "firefox", "firefox.exe")
122
+ : path.join(browsersDir, "firefox", "firefox"),
123
+ };
124
+
125
+ const binaryPath = binaryMap[browserName];
126
+ if (!binaryPath) {
127
+ throw new Error(
128
+ `░░░░░ [LaunchBrowser] Unknown browser: ${browserName}`
129
+ );
103
130
  }
104
131
 
105
- if (!binaryPath || !fs.existsSync(binaryPath)) {
132
+ if (!fs.existsSync(binaryPath)) {
106
133
  throw new Error(
107
- `░░░░░ [LaunchBrowser] Binary not found for ${browserName} at: ${binaryPath}\n` +
108
- ` Linux checked: ~/.cache/brave/brave AND ~/Downloads/brave/brave`
134
+ `░░░░░ [LaunchBrowser] ${browserName} binary not found at: ${binaryPath}\n` +
135
+ ` Run "node bin/cli.js install" to install browsers.`
109
136
  );
110
137
  }
111
138
 
@@ -237,7 +264,7 @@ function getFingerprintConfig(browserType, screenOptions = null) {
237
264
  // 3. MAIN LAUNCHER ENTRY POINT
238
265
  // ==========================================================================
239
266
 
240
- export async function launchBrowser({
267
+ export async function pwLaunch({
241
268
  // Common
242
269
  timezoneId = null,
243
270
  proxy,
@@ -407,7 +434,7 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, hum
407
434
  const ignoreDefaultArgs = ["--enable-automation"];
408
435
 
409
436
  if (CapSolver) {
410
- const extPath = path.resolve(`./utility/browser-fingerprint/CapSolver`);
437
+ const extPath = path.resolve(`./src/utility/browser-fingerprint/CapSolver`);
411
438
  args.push(`--disable-extensions-except=${extPath}`, `--load-extension=${extPath}`);
412
439
  }
413
440
 
@@ -428,6 +455,7 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, hum
428
455
  // Launch standard browser (not persistent context)
429
456
  const browser = await chromium.launch({
430
457
  headless: false,
458
+ executablePath: getPlaywrightExePath("chromium"),
431
459
  proxy: proxyObj,
432
460
  args: args,
433
461
  ignoreDefaultArgs: ignoreDefaultArgs,
@@ -469,6 +497,7 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, hum
469
497
  // Logic: Native Persistent Launch. No fingerprint-injector.
470
498
  const context = await chromium.launchPersistentContext(activePath, {
471
499
  headless: false,
500
+ executablePath: getPlaywrightExePath("chromium"),
472
501
  proxy: proxyObj,
473
502
  args: args,
474
503
  timezoneId: tz,
@@ -524,6 +553,7 @@ async function firefoxLauncher({ profilePath, proxy, timezoneId, humanize_option
524
553
 
525
554
  const browser = await firefox.launch({
526
555
  headless: false,
556
+ executablePath: getPlaywrightExePath("firefox"),
527
557
  proxy: proxyObj,
528
558
  ignoreDefaultArgs: ["--enable-automation"],
529
559
  firefoxUserPrefs: firefoxUserPrefs,
@@ -565,6 +595,7 @@ async function firefoxLauncher({ profilePath, proxy, timezoneId, humanize_option
565
595
 
566
596
  const context = await firefox.launchPersistentContext(activePath, {
567
597
  headless: false,
598
+ executablePath: getPlaywrightExePath("firefox"),
568
599
  proxy: proxyObj,
569
600
  timezoneId: tz,
570
601
  ignoreDefaultArgs: ["--enable-automation"],
@@ -701,7 +732,7 @@ async function braveLauncher({ profilePath, proxy, CapSolver, timezoneId, humani
701
732
  ];
702
733
  const ignoreDefaultArgs = ["--enable-automation"];
703
734
  if (CapSolver) {
704
- const extPath = path.resolve(`./utility/browser-fingerprint/CapSolver`);
735
+ const extPath = path.resolve(`./src/utility/browser-fingerprint/CapSolver`);
705
736
  args.push(`--load-extension=${extPath}`);
706
737
  }
707
738
 
@@ -5,9 +5,9 @@ import { Browser, BrowserContext, Page } from "playwright";
5
5
  // ============================================================================
6
6
 
7
7
  /**
8
- * Options for the gotRoute function.
8
+ * Options for the pwRoute function.
9
9
  */
10
- export interface GotRouteOptions {
10
+ export interface PwRouteOptions {
11
11
  /** Playwright Context (provide either context or page) */
12
12
  context?: BrowserContext | null;
13
13
 
@@ -57,11 +57,11 @@ export interface GotRouteOptions {
57
57
  /**
58
58
  * Sets up request interception, caching, and ad-blocking on a Playwright page or context.
59
59
  */
60
- export function gotRoute(options: GotRouteOptions): Promise<void>;
60
+ export function pwRoute(options: PwRouteOptions): Promise<void>;
61
61
 
62
62
  /**
63
63
  * Starts logging cache statistics to the console at a set interval.
64
64
  * @param log_cache Optional NodeCache instance (uses global by default)
65
65
  * @param interval Interval in seconds (default: 10)
66
66
  */
67
- export function showCacheLogs(log_cache?: any, interval?: number): void;
67
+ export function pwCacheLogs(log_cache?: any, interval?: number): void;
@@ -20,7 +20,7 @@ const globalCache = new NodeCache({
20
20
  * @param {Object} log_cache - The cache instance to monitor
21
21
  * @param {number} interval - The interval in seconds between log outputs
22
22
  */
23
- export function showCacheLogs(log_cache = globalCache, interval = 10) {
23
+ export function pwCacheLogs(log_cache = globalCache, interval = 10) {
24
24
  if (interval > 0) {
25
25
  setInterval(() => {
26
26
  const stats = log_cache.stats;
@@ -109,7 +109,7 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
109
109
  * @param {Array<string>} options.allowImagePatterns - Array of strings/patterns. If a URL contains any of these, it will NOT be blocked even if blockImage is true.
110
110
  * @param {Array<string>} options.skipGotPatterns - Array of strings/patterns. If a URL contains any of these, it will skip the custom Superagent fetch.
111
111
  */
112
- export async function gotRoute({
112
+ export async function pwRoute({
113
113
  context = null,
114
114
  page = null,
115
115
  successLogs = false,
@@ -217,9 +217,10 @@ export async function startProxyServer({
217
217
  fetchProxyDetails(upstreamProxies.p2, ip2LocationKey),
218
218
  ]);
219
219
 
220
- // Warn only if proxy was configured (URL exists) but details came back null (Connection failed)
221
- if (upstreamProxies.p1 && !p1Details) console.warn("░░ Warning: PROXY_1 configured but unreachable.");
222
- if (upstreamProxies.p2 && !p2Details) console.warn("░░ Warning: PROXY_2 configured but unreachable.");
220
+ // Return null if any configured proxy is unreachable
221
+ if (upstreamProxies.default && !defaultDetails) { console.warn("░░ Warning: DEFAULT_PROXY configured but unreachable."); return null; }
222
+ if (upstreamProxies.p1 && !p1Details) { console.warn("░░ Warning: PROXY_1 configured but unreachable."); return null; }
223
+ if (upstreamProxies.p2 && !p2Details) { console.warn("░░ Warning: PROXY_2 configured but unreachable."); return null; }
223
224
 
224
225
  // 5. Stats
225
226
  const stats = {
@@ -1,6 +1,6 @@
1
1
  import { setTimeout as sleep } from "timers/promises";
2
2
  import randomstring from "randomstring";
3
- import { getMultiloginToken } from "../multilogin_token_manager.js";
3
+ import { getMultiloginToken } from "../mlx_token.js";
4
4
  import { getActiveProxyWithStartStop as fetchAwsProxy } from "./custom-proxy.js";
5
5
  import { arn, query } from "arn-knexjs";
6
6
 
@@ -0,0 +1,199 @@
1
+ import { Browser, Page } from "puppeteer-core";
2
+ import type { ProxyConfig } from "../pwLaunch";
3
+
4
+ /**
5
+ * Configuration options specific to Multilogin (Puppeteer CDP).
6
+ */
7
+ export interface PpMultiloginOptions {
8
+ /**
9
+ * Multilogin Profile ID. If provided, launches an existing profile.
10
+ */
11
+ profileId?: string | null;
12
+
13
+ /**
14
+ * OS Type for Multilogin profile creation.
15
+ * Default: detected OS
16
+ */
17
+ os_type?: "windows" | "macos" | "linux" | "android";
18
+
19
+ /**
20
+ * Multilogin flag: Canvas noise masking.
21
+ * Default: true
22
+ */
23
+ canvas_noise?: boolean;
24
+
25
+ /**
26
+ * Multilogin flag: Media devices masking.
27
+ * Default: true
28
+ */
29
+ media_masking?: boolean;
30
+
31
+ /**
32
+ * Multilogin flag: Audio masking.
33
+ * Default: true
34
+ */
35
+ audio_masking?: boolean;
36
+ }
37
+
38
+ /**
39
+ * Options for launching a browser via Puppeteer CDP.
40
+ */
41
+ export interface PpLaunchOptions {
42
+ // ========================================================================
43
+ // 1. BROWSER SELECTION
44
+ // ========================================================================
45
+
46
+ /**
47
+ * Which browser to launch.
48
+ *
49
+ * - `"chrome"`: Chromium browser (locally installed)
50
+ * - `"chromium"`: Alias for Chrome
51
+ * - `"brave"`: Brave Browser (requires local binary)
52
+ * - `"multilogin"`: Multilogin anti-detect browser (via API)
53
+ *
54
+ * Default: `"chrome"`
55
+ */
56
+ which_browser?: "chrome" | "chromium" | "brave" | "multilogin";
57
+
58
+ // ========================================================================
59
+ // 2. STORAGE & PROFILES
60
+ // ========================================================================
61
+
62
+ /**
63
+ * Path to a persistent profile.
64
+ * - If absolute path: Uses that path exactly (no prefix added).
65
+ * - If folder name: Creates inside `~/.arn-browser/pp/persistent/` with a browser prefix (e.g., `brave_myProfile`).
66
+ * - If null: Creates a temporary, random profile in `~/.arn-browser/pp/temp/`.
67
+ */
68
+ profile_path?: string | null;
69
+
70
+ /**
71
+ * Auto-cleanup profiles after X minutes since last launch.
72
+ *
73
+ * **Persistent profiles:** Cleaned after X minutes since last launch. Default: 0 (never clean).
74
+ * **Temp profiles:** Default: 15 minutes if not specified.
75
+ *
76
+ * Default: 0
77
+ */
78
+ cleanupMinutes?: number;
79
+
80
+ // ========================================================================
81
+ // 3. NETWORK
82
+ // ========================================================================
83
+
84
+ /**
85
+ * Proxy settings (URL string or config object).
86
+ * Passed as `--proxy-server` flag to the browser.
87
+ */
88
+ proxy?: ProxyConfig | string | null;
89
+
90
+ // ========================================================================
91
+ // 4. BROWSER ARGS
92
+ // ========================================================================
93
+
94
+ /**
95
+ * Additional CLI arguments to pass to the browser process.
96
+ * These are appended after the default args.
97
+ *
98
+ * @example ["--disable-gpu", "--window-size=1920,1080"]
99
+ */
100
+ extraArgs?: string[];
101
+
102
+ // ========================================================================
103
+ // 5. ENGINE SPECIFIC
104
+ // ========================================================================
105
+
106
+ /**
107
+ * Options specific to the Multilogin engine.
108
+ */
109
+ multilogin_options?: PpMultiloginOptions;
110
+
111
+ // ========================================================================
112
+ // 6. FINGERPRINT SPOOFING
113
+ // ========================================================================
114
+
115
+ /**
116
+ * Configuration for browser fingerprint spoofing (per-page via fingerprint-injector).
117
+ *
118
+ * - `false`: No fingerprint spoofing (default)
119
+ * - `true`: Spoof fingerprint with default screen dimensions
120
+ * - `{ minWidth?, maxWidth?, minHeight?, maxHeight? }`: Spoof fingerprint with screen constraints
121
+ *
122
+ * Default: false
123
+ */
124
+ spoof_fingerprint?: boolean | {
125
+ minWidth?: number;
126
+ maxWidth?: number;
127
+ minHeight?: number;
128
+ maxHeight?: number;
129
+ };
130
+
131
+ // ========================================================================
132
+ // 7. LOGGING
133
+ // ========================================================================
134
+
135
+ /**
136
+ * Enable launch-related console logs.
137
+ * Default: false
138
+ */
139
+ launch_logs?: boolean;
140
+
141
+ /**
142
+ * Enable cleanup-related console logs.
143
+ * Default: false
144
+ */
145
+ cleanup_logs?: boolean;
146
+ }
147
+
148
+ /**
149
+ * Successful Puppeteer browser launch result.
150
+ * When launchError is null, browser/context/page are guaranteed to be valid.
151
+ */
152
+ export interface PpBrowserControllerSuccess {
153
+ /** The Puppeteer Browser instance. */
154
+ browser: Browser;
155
+ /** The browser instance (alias for browser in Puppeteer, since there's no separate BrowserContext). */
156
+ context: Browser;
157
+ /** The initial Page object. */
158
+ page: Page;
159
+ /** Returns true if the browser is still connected. */
160
+ isBrowserRunning: () => boolean;
161
+ /** Safely closes the browser, kills the process, and cleans up temporary directories. */
162
+ closeBrowser: () => Promise<boolean>;
163
+ /** No error occurred during launch. */
164
+ launchError: null;
165
+ }
166
+
167
+ /**
168
+ * Failed Puppeteer browser launch result.
169
+ * When launchError is set, browser/context/page are null.
170
+ */
171
+ export interface PpBrowserControllerError {
172
+ /** Null on launch failure. */
173
+ browser: null;
174
+ /** Null on launch failure. */
175
+ context: null;
176
+ /** Null on launch failure. */
177
+ page: null;
178
+ /** Returns false since the browser failed to launch. */
179
+ isBrowserRunning: () => boolean;
180
+ /** No-op cleanup function. */
181
+ closeBrowser: () => Promise<boolean>;
182
+ /** The error that occurred during launch. */
183
+ launchError: Error;
184
+ }
185
+
186
+ /**
187
+ * The object returned by launchPuppeteer.
188
+ * Check launchError to discriminate between success and failure states.
189
+ */
190
+ export type PpBrowserController = PpBrowserControllerSuccess | PpBrowserControllerError;
191
+
192
+ /**
193
+ * Launches a browser via Puppeteer CDP based on the provided options.
194
+ * Spawns the browser process, connects via Chrome DevTools Protocol.
195
+ *
196
+ * Supported browsers: Chrome, Brave, Multilogin.
197
+ * Profile directory: ~/.arn-browser/pp/
198
+ */
199
+ export function ppLaunch(options?: PpLaunchOptions): Promise<PpBrowserController>;