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.
- package/bin/cli.js +7 -3
- package/bin/install.js +65 -191
- package/package.json +4 -3
- package/src/utility/playwright/findBrowserPath.js +211 -0
- package/src/utility/playwright/pwLaunch.d.ts +18 -1
- package/src/utility/playwright/pwLaunch.js +51 -73
- package/src/utility/puppeteer/deleteDirectory.js +104 -0
- package/src/utility/puppeteer/findBrowserPath.js +211 -0
- package/src/utility/puppeteer/ppLaunch.d.ts +18 -1
- package/src/utility/puppeteer/ppLaunch.js +62 -40
- /package/src/utility/{deleteDirectory.js → playwright/deleteDirectory.js} +0 -0
|
@@ -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 "
|
|
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("
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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",
|
|
File without changes
|