arn-browser 0.1.31 → 0.1.33

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.
@@ -17,7 +17,8 @@ import { FingerprintGenerator } from "fingerprint-generator";
17
17
 
18
18
  // Internal Utilities
19
19
  import { getMultiloginToken } from "../mlx_token.js";
20
- import { deleteDirectoryWithRetries } from "../deleteDirectory.js";
20
+ import { deleteDirectoryWithRetries } from "./deleteDirectory.js";
21
+ import { findBrowserPath } from "./findBrowserPath.js";
21
22
 
22
23
  // ==========================================================================
23
24
  // 1. CONFIGURATION & CONSTANTS
@@ -127,43 +128,15 @@ function resolveProfilePath(nameOrPath, browserName) {
127
128
 
128
129
  let prefix = browserName.toLowerCase();
129
130
  if (prefix.includes("brave")) prefix = "brave";
130
- else if (prefix.includes("chrome") || prefix.includes("chromium")) prefix = "chrome";
131
+ else if (prefix.includes("chromium")) prefix = "chromium";
132
+ else if (prefix.includes("chrome")) prefix = "chrome";
131
133
 
132
134
  const folderName = `${prefix}_${nameOrPath}`;
133
135
  return path.join(PERSISTENT_DIR, folderName);
134
136
  }
135
137
 
136
- /**
137
- * Locates binaries for Chrome and Brave from the installed browsers.
138
- * Uses ~/.arn-browser/browsers/{browser}/{executable}
139
- */
140
- function getBinaryPath(browserName) {
141
- const isWindows = process.platform === "win32";
142
- const browsersDir = path.join(ARN_BROWSER_DIR, "browsers");
143
-
144
- const binaryMap = {
145
- brave: isWindows
146
- ? path.join(browsersDir, "brave", "brave.exe")
147
- : path.join(browsersDir, "brave", "brave"),
148
- chrome: isWindows
149
- ? path.join(browsersDir, "chromium", "chrome.exe")
150
- : path.join(browsersDir, "chromium", "chrome"),
151
- };
152
-
153
- const binaryPath = binaryMap[browserName];
154
- if (!binaryPath) {
155
- throw new Error(`░░░░░ [LaunchPuppeteer] Unknown browser: ${browserName}`);
156
- }
157
-
158
- if (!fs.existsSync(binaryPath)) {
159
- throw new Error(
160
- `░░░░░ [LaunchPuppeteer] ${browserName} binary not found at: ${binaryPath}\n` +
161
- ` Run "node bin/cli.js install" to install browsers.`
162
- );
163
- }
164
-
165
- return binaryPath;
166
- }
138
+ // Browser path resolution now uses OS-installed browsers via findBrowserPath.
139
+ // See src/utility/findBrowserPath.js for detection logic.
167
140
 
168
141
  /**
169
142
  * Writes or updates the profile metadata file.
@@ -191,6 +164,31 @@ function writeProfileMeta(dirPath, type, cleanupMinutes) {
191
164
  }
192
165
  }
193
166
 
167
+ /**
168
+ * Writes per-host notification permissions into the Chrome Preferences object.
169
+ * Accepts plain hostnames (e.g. "web.whatsapp.com") and converts them
170
+ * to Chrome's internal format: "https://host:443,*" with setting=1 (Allow).
171
+ * If hosts array is empty, does nothing (Chrome default "Ask" behavior).
172
+ */
173
+ function writeNotificationPermissions(prefs, hosts) {
174
+ if (!hosts || hosts.length === 0) return;
175
+
176
+ if (!prefs.profile) prefs.profile = {};
177
+ if (!prefs.profile.content_settings) prefs.profile.content_settings = {};
178
+ if (!prefs.profile.content_settings.exceptions) prefs.profile.content_settings.exceptions = {};
179
+ if (!prefs.profile.content_settings.exceptions.notifications) prefs.profile.content_settings.exceptions.notifications = {};
180
+
181
+ const now = String(Date.now());
182
+ for (const host of hosts) {
183
+ const origin = host.startsWith("http") ? host : `https://${host}:443`;
184
+ const key = `${origin},*`;
185
+ prefs.profile.content_settings.exceptions.notifications[key] = {
186
+ last_modified: now,
187
+ setting: 1, // 1 = Allow
188
+ };
189
+ }
190
+ }
191
+
194
192
  /**
195
193
  * Scans profile directories and deletes expired profiles.
196
194
  */
@@ -290,6 +288,10 @@ export async function ppLaunch({
290
288
  // Multilogin
291
289
  multilogin_options = {},
292
290
 
291
+ // Notifications — per-host allow list
292
+ // Pass plain hostnames: ["web.whatsapp.com", "messages.google.com"]
293
+ notification_hosts = [],
294
+
293
295
  // Logging
294
296
  launch_logs = false,
295
297
  cleanup_logs = false,
@@ -315,6 +317,17 @@ export async function ppLaunch({
315
317
 
316
318
  switch (which_browser) {
317
319
  case "chrome":
320
+ result = await chromeLauncher({
321
+ profilePath: fullPath,
322
+ proxy,
323
+ timezoneId,
324
+ extraArgs,
325
+ spoof_fingerprint,
326
+ cleanupMinutes: effectiveCleanupMinutes,
327
+ browserType: "chrome",
328
+ notification_hosts,
329
+ });
330
+ break;
318
331
  case "chromium":
319
332
  result = await chromeLauncher({
320
333
  profilePath: fullPath,
@@ -323,6 +336,8 @@ export async function ppLaunch({
323
336
  extraArgs,
324
337
  spoof_fingerprint,
325
338
  cleanupMinutes: effectiveCleanupMinutes,
339
+ browserType: "chromium",
340
+ notification_hosts,
326
341
  });
327
342
  break;
328
343
  case "brave":
@@ -333,6 +348,7 @@ export async function ppLaunch({
333
348
  extraArgs,
334
349
  spoof_fingerprint,
335
350
  cleanupMinutes: effectiveCleanupMinutes,
351
+ notification_hosts,
336
352
  });
337
353
  break;
338
354
  case "multilogin":
@@ -356,15 +372,15 @@ export async function ppLaunch({
356
372
  // 4. ENGINE: CHROME (CDP)
357
373
  // ==========================================================================
358
374
 
359
- async function chromeLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_fingerprint, cleanupMinutes }) {
375
+ async function chromeLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_fingerprint, cleanupMinutes, browserType = "chrome", notification_hosts = [] }) {
360
376
  const isPersistent = !!profilePath;
361
377
  const activePath = isPersistent ? profilePath : path.join(TEMP_DIR, crypto.randomUUID());
362
378
 
363
379
  fs.mkdirSync(activePath, { recursive: true });
364
380
  writeProfileMeta(activePath, isPersistent ? "persistent" : "temp", cleanupMinutes);
365
- if (_launchLogs) console.log(`░░░░░ Starting Chrome [${isPersistent ? "Persistent" : "Temp"}]: ${activePath}`);
381
+ if (_launchLogs) console.log(`░░░░░ Starting ${browserType === "chromium" ? "Chromium" : "Chrome"} [${isPersistent ? "Persistent" : "Temp"}]: ${activePath}`);
366
382
 
367
- const binaryPath = getBinaryPath("chrome");
383
+ const binaryPath = findBrowserPath(browserType);
368
384
  return await spawnAndConnect({
369
385
  binaryPath,
370
386
  profilePath: activePath,
@@ -373,7 +389,8 @@ async function chromeLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof
373
389
  timezoneId,
374
390
  extraArgs,
375
391
  spoof_fingerprint,
376
- browserLabel: "Chrome",
392
+ browserLabel: browserType === "chromium" ? "Chromium" : "Chrome",
393
+ notification_hosts,
377
394
  });
378
395
  }
379
396
 
@@ -381,7 +398,7 @@ async function chromeLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof
381
398
  // 5. ENGINE: BRAVE (CDP)
382
399
  // ==========================================================================
383
400
 
384
- async function braveLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_fingerprint, cleanupMinutes }) {
401
+ async function braveLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_fingerprint, cleanupMinutes, notification_hosts = [] }) {
385
402
  const isPersistent = !!profilePath;
386
403
  const activePath = isPersistent ? profilePath : path.join(TEMP_DIR, crypto.randomUUID());
387
404
 
@@ -408,6 +425,7 @@ async function braveLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_
408
425
  // Prevent tab restore (saves proxy bandwidth)
409
426
  if (!prefs.profile) prefs.profile = {};
410
427
  prefs.profile.exit_type = "Normal";
428
+ writeNotificationPermissions(prefs, notification_hosts);
411
429
 
412
430
  if (!prefs.session) prefs.session = {};
413
431
  prefs.session.restore_on_startup = 4;
@@ -439,7 +457,7 @@ async function braveLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_
439
457
  console.warn("░░░░░ Could not modify Brave Local State:", e.message);
440
458
  }
441
459
 
442
- const binaryPath = getBinaryPath("brave");
460
+ const binaryPath = findBrowserPath("brave");
443
461
  const braveArgs = [
444
462
  "--disable-features=Translate,BraveRewards,BraveWallet,BraveNews,Sidebar,SidePanel,BraveNTPBrandedWallpaper,NTPBackgroundImages",
445
463
  "--homepage=about:blank",
@@ -455,6 +473,7 @@ async function braveLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_
455
473
  extraArgs: [...braveArgs, ...extraArgs],
456
474
  spoof_fingerprint,
457
475
  browserLabel: "Brave",
476
+ notification_hosts,
458
477
  });
459
478
  }
460
479
 
@@ -462,7 +481,7 @@ async function braveLauncher({ profilePath, proxy, timezoneId, extraArgs, spoof_
462
481
  // 6. CDP SPAWN & CONNECT (Shared between Chrome & Brave)
463
482
  // ==========================================================================
464
483
 
465
- async function spawnAndConnect({ binaryPath, profilePath, isPersistent, proxy, timezoneId = null, extraArgs = [], spoof_fingerprint = false, browserLabel = "Browser" }) {
484
+ async function spawnAndConnect({ binaryPath, profilePath, isPersistent, proxy, timezoneId = null, extraArgs = [], spoof_fingerprint = false, browserLabel = "Browser", notification_hosts = [] }) {
466
485
  let browser;
467
486
  let closing = false;
468
487
  let signalHandler;
@@ -485,6 +504,7 @@ async function spawnAndConnect({ binaryPath, profilePath, isPersistent, proxy, t
485
504
  // Prevent "Restore pages?" prompt after crash
486
505
  if (!prefs.profile) prefs.profile = {};
487
506
  prefs.profile.exit_type = "Normal";
507
+ writeNotificationPermissions(prefs, notification_hosts);
488
508
 
489
509
  // Set startup to open about:blank instead of restoring tabs
490
510
  if (!prefs.session) prefs.session = {};
@@ -525,6 +545,8 @@ async function spawnAndConnect({ binaryPath, profilePath, isPersistent, proxy, t
525
545
  // --- Silence & Networking ---
526
546
  "--disable-background-networking",
527
547
  "--disable-background-timer-throttling",
548
+ "--disable-backgrounding-occluded-windows",
549
+ "--disable-renderer-backgrounding",
528
550
  "--disable-breakpad",
529
551
  "--disable-crash-reporter",
530
552
  "--disable-component-update",