brave-real-launcher 1.2.32 → 1.2.34

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.
@@ -3,8 +3,8 @@ name: Chrome Launcher Sync & Publish
3
3
  on:
4
4
  # Automatic triggers
5
5
  schedule:
6
- # Weekly trigger - Every Monday at 6 AM UTC (11:30 AM IST)
7
- - cron: '0 6 * * 1'
6
+ # Daily trigger - Every day at 6 AM UTC (11:30 AM IST)
7
+ - cron: '0 6 * * *'
8
8
 
9
9
  # Manual trigger
10
10
  workflow_dispatch:
package/README.md CHANGED
@@ -2,14 +2,17 @@
2
2
 
3
3
  Launch Brave Browser with ease from Node.js. Based on [chrome-launcher](https://github.com/GoogleChrome/chrome-launcher) but specifically adapted for Brave Browser with additional features.
4
4
 
5
- ## Features
5
+ ## Features
6
6
 
7
7
  - 🦁 **Brave Browser Detection**: Automatically detects Brave Browser installations across all platforms
8
8
  - 🖥️ **Multi-Platform Support**: Linux (x64/ARM64), macOS (Intel/Apple Silicon), Windows (x64/ARM64)
9
9
  - 🐧 **Xvfb Support**: Built-in Xvfb support for headless operation on Linux
10
10
  - 🎯 **Launch Modes**: Headless mode, GUI mode, or automatic detection
11
11
  - 🔄 **Auto-Sync**: Automatically syncs with chrome-launcher updates while preserving Brave-specific features
12
- - 🛠️ **Full API Compatibility**: Drop-in replacement for chrome-launcher but for Brave
12
+ - 📦 **uBlock Origin**: Automatic download and loading of uBlock Origin ad blocker
13
+ - 🛡️ **Stealth Mode**: Anti-bot-detection capabilities for automation
14
+ - ⬇️ **Auto-Install**: Automatically install Brave if not present (Windows/Linux/macOS)
15
+ - 🔇 **P3A Disabled**: Private analytics notifications disabled by default
13
16
 
14
17
  ## Installation
15
18
 
@@ -17,23 +20,6 @@ Launch Brave Browser with ease from Node.js. Based on [chrome-launcher](https://
17
20
  npm install brave-real-launcher
18
21
  ```
19
22
 
20
- ## Quick Start
21
-
22
- ```javascript
23
- const { launch } = require('brave-real-launcher');
24
-
25
- // Launch Brave in headless mode
26
- const brave = await launch({
27
- braveFlags: ['--headless', '--disable-gpu'],
28
- logLevel: 'info'
29
- });
30
-
31
- console.log('Brave is running on port', brave.port);
32
-
33
- // Kill Brave
34
- brave.kill();
35
- ```
36
-
37
23
  ## API
38
24
 
39
25
  ### `launch(options)`
@@ -41,116 +27,105 @@ brave.kill();
41
27
  Launches Brave Browser with the specified options.
42
28
 
43
29
  **Options:**
44
- - `bravePath?: string` - Path to Brave executable (auto-detected if not provided)
45
- - `braveFlags?: string[]` - Array of Brave flags to pass
46
- - `launchMode?: 'auto' | 'headless' | 'gui'` - Launch mode (default: 'auto')
47
- - `enableXvfb?: boolean` - Enable Xvfb on Linux (default: false)
48
- - `xvfbOptions?: XvfbOptions` - Xvfb configuration options
49
- - `port?: number` - Debug port (default: random)
50
- - `userDataDir?: string | boolean` - User data directory
51
- - `startingUrl?: string` - URL to navigate to on start
52
- - And more options compatible with chrome-launcher
30
+
31
+ | Option | Type | Default | Description |
32
+ |--------|------|---------|-------------|
33
+ | `bravePath` | `string` | auto-detected | Path to Brave executable |
34
+ | `braveFlags` | `string[]` | `[]` | Array of Brave flags to pass |
35
+ | `startingUrl` | `string` | `about:blank` | URL to navigate to on start |
36
+ | `port` | `number` | random | Debug port |
37
+ | `userDataDir` | `string\|boolean` | temp dir | User data directory |
38
+ | `launchMode` | `'auto'\|'headless'\|'gui'` | `'auto'` | Launch mode |
39
+ | `enableXvfb` | `boolean` | `false` | Enable Xvfb on Linux |
40
+ | `autoLoadUBlock` | `boolean` | `false` | Auto-load uBlock Origin |
41
+ | `enableStealth` | `boolean` | `false` | Enable stealth mode |
42
+ | `autoInstall` | `boolean` | `false` | Auto-install Brave if not found |
43
+ | `userAgent` | `string` | default | Custom user agent |
44
+ | `logLevel` | `'verbose'\|'info'\|'error'\|'silent'` | `'silent'` | Log level |
45
+
46
+ **Returns:** `LaunchedBrave` object with:
47
+ - `pid`: Process ID
48
+ - `port`: Debug port
49
+ - `process`: Child process
50
+ - `extensions`: Loaded extensions info
51
+ - `kill()`: Function to kill browser
53
52
 
54
53
  ### `getBravePath()`
55
54
 
56
55
  Returns the path to the Brave Browser executable.
57
56
 
58
- ### `XvfbManager`
59
-
60
- Manages Xvfb virtual display for headless environments.
61
-
62
- ```javascript
63
- const { XvfbManager } = require('brave-real-launcher');
57
+ ## Platform Support
64
58
 
65
- const xvfb = new XvfbManager({
66
- display: ':99',
67
- width: 1920,
68
- height: 1080
69
- });
59
+ ### Auto-Install Behavior
70
60
 
71
- await xvfb.start();
72
- // ... use Brave
73
- await xvfb.stop();
74
- ```
61
+ | Platform | Method | Skip if Installed |
62
+ |----------|--------|-------------------|
63
+ | **Windows** | Downloads installer, runs silently | ✅ Yes |
64
+ | **Linux** | apt/dnf/yum/pacman | ✅ Yes |
65
+ | **macOS** | Downloads DMG, mounts & copies | ✅ Yes |
75
66
 
76
- ## Platform Support
67
+ ### Path Detection
77
68
 
78
- ### Linux
79
- - x64 and ARM64 architectures
80
- - Detects installations in standard paths: `/opt/brave.com/brave/`, `/usr/bin/brave-browser`, etc.
81
- - Supports Flatpak and Snap installations
82
- - Built-in Xvfb support for headless environments
69
+ | Platform | Detection Paths |
70
+ |----------|-----------------|
71
+ | **Windows** | `%LOCALAPPDATA%\BraveSoftware\...`, `%PROGRAMFILES%\...` |
72
+ | **Linux** | `/usr/bin/brave-browser`, `/opt/brave.com/brave/...`, Flatpak, Snap |
73
+ | **macOS** | `/Applications/Brave Browser.app/...` |
83
74
 
84
- ### macOS
85
- - Intel and Apple Silicon (M1/M2) support
86
- - Detects Brave Browser, Brave Browser Beta, Nightly, and Dev versions
87
- - Standard installation paths in `/Applications/`
75
+ ## Testing
88
76
 
89
- ### Windows
90
- - x64 and ARM64 support
91
- - Registry-based detection
92
- - Standard installation paths in Program Files and Local AppData
77
+ ```bash
78
+ # Install dependencies
79
+ npm install
93
80
 
94
- ## Environment Variables
81
+ # Build project
82
+ npm run build
95
83
 
96
- - `BRAVE_PATH`: Path to Brave executable
97
- - `HEADLESS`: Force headless mode when set
98
- - `DISPLAY`: X11 display (Linux)
84
+ # Run tests
85
+ npm test
99
86
 
100
- ## Examples
87
+ # Test Brave detection
88
+ npm run test:detection
101
89
 
102
- ### Headless Mode with Xvfb
103
- ```javascript
104
- const brave = await launch({
105
- launchMode: 'headless',
106
- enableXvfb: true,
107
- xvfbOptions: { width: 1920, height: 1080 }
108
- });
90
+ # Test with uBlock Origin
91
+ node -e "const {launch} = require('./dist'); launch({autoLoadUBlock:true, startingUrl:'https://example.com', logLevel:'info'}).then(b => setTimeout(() => b.kill(), 5000))"
109
92
  ```
110
93
 
111
- ### Custom Flags
112
- ```javascript
113
- const brave = await launch({
114
- braveFlags: [
115
- '--no-sandbox',
116
- '--disable-dev-shm-usage',
117
- '--disable-gpu'
118
- ]
119
- });
120
- ```
94
+ ## Environment Variables
121
95
 
122
- ### Auto-Detection
123
- ```javascript
124
- const brave = await launch({
125
- launchMode: 'auto', // Automatically detects headless vs GUI environment
126
- logLevel: 'verbose'
127
- });
128
- ```
96
+ | Variable | Description |
97
+ |----------|-------------|
98
+ | `BRAVE_PATH` | Path to Brave executable |
99
+ | `HEADLESS` | Force headless mode when set |
100
+ | `DISPLAY` | X11 display (Linux) |
129
101
 
130
102
  ## Development
131
103
 
132
- ### Building
133
-
134
104
  ```bash
135
- npm run build
136
- ```
105
+ # Clone repository
106
+ git clone https://github.com/user/brave-real-launcher.git
107
+ cd brave-real-launcher
137
108
 
138
- ### Testing
109
+ # Install dependencies
110
+ npm install
139
111
 
140
- ```bash
141
- npm test
112
+ # Build
113
+ npm run build
114
+
115
+ # Run CI tests
116
+ npm run test:ci
142
117
  ```
143
118
 
144
119
  ## Auto-Sync with chrome-launcher
145
120
 
146
- This project automatically syncs with chrome-launcher updates while preserving Brave-specific functionality. The GitHub Action workflow:
121
+ This project automatically syncs with chrome-launcher updates while preserving Brave-specific functionality:
147
122
 
148
- - Checks for chrome-launcher updates daily
149
- - Automatically integrates compatible changes
150
- - Preserves Brave-specific browser detection and features
151
- - Runs comprehensive tests across all supported platforms
152
- - Publishes updated versions to npm
123
+ - Checks for chrome-launcher updates **daily**
124
+ - Automatically integrates compatible changes
125
+ - Preserves Brave-specific browser detection
126
+ - Runs comprehensive tests
127
+ - Publishes to npm automatically
153
128
 
154
129
  ## License
155
130
 
156
- Apache-2.0 - Based on chrome-launcher by The Chromium Authors
131
+ Apache-2.0 - Based on chrome-launcher by The Chromium Authors
@@ -0,0 +1,57 @@
1
+ export interface InstallerOptions {
2
+ silent?: boolean;
3
+ downloadDir?: string;
4
+ channel?: 'release' | 'beta' | 'nightly';
5
+ }
6
+ export interface InstallResult {
7
+ success: boolean;
8
+ bravePath?: string;
9
+ error?: string;
10
+ }
11
+ export declare class BraveInstaller {
12
+ private silent;
13
+ private downloadDir;
14
+ private channel;
15
+ constructor(options?: InstallerOptions);
16
+ /**
17
+ * Install Brave browser on the current platform
18
+ */
19
+ install(): Promise<InstallResult>;
20
+ /**
21
+ * Install Brave on Windows
22
+ */
23
+ private installWindows;
24
+ /**
25
+ * Install Brave on Linux
26
+ */
27
+ private installLinux;
28
+ /**
29
+ * Install Brave on macOS
30
+ */
31
+ private installMacOS;
32
+ /**
33
+ * Download file from URL
34
+ */
35
+ private downloadFile;
36
+ /**
37
+ * Detect Linux package manager
38
+ */
39
+ private detectLinuxPackageManager;
40
+ /**
41
+ * Find Brave on Windows
42
+ */
43
+ private findBraveWindows;
44
+ /**
45
+ * Find Brave on Linux
46
+ */
47
+ private findBraveLinux;
48
+ /**
49
+ * Delay helper
50
+ */
51
+ private delay;
52
+ /**
53
+ * Check if Brave is installed
54
+ */
55
+ static isInstalled(): boolean;
56
+ }
57
+ export default BraveInstaller;
@@ -0,0 +1,352 @@
1
+ /**
2
+ * @license Copyright 2024 Brave Real Launcher Contributors.
3
+ * Licensed under the Apache License, Version 2.0
4
+ *
5
+ * Brave Browser Installer
6
+ * Auto-installs Brave browser on Windows, Linux, and macOS
7
+ */
8
+ 'use strict';
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || function (mod) {
26
+ if (mod && mod.__esModule) return mod;
27
+ var result = {};
28
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
29
+ __setModuleDefault(result, mod);
30
+ return result;
31
+ };
32
+ var __importDefault = (this && this.__importDefault) || function (mod) {
33
+ return (mod && mod.__esModule) ? mod : { "default": mod };
34
+ };
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BraveInstaller = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const https = __importStar(require("https"));
40
+ const http = __importStar(require("http"));
41
+ const child_process_1 = require("child_process");
42
+ const os_1 = require("os");
43
+ const logger_js_1 = __importDefault(require("./logger.js"));
44
+ const utils_js_1 = require("./utils.js");
45
+ const BRAVE_DOWNLOAD_URLS = {
46
+ win32: {
47
+ release: 'https://laptop-updates.brave.com/latest/winx64',
48
+ beta: 'https://laptop-updates.brave.com/latest/winx64-beta',
49
+ nightly: 'https://laptop-updates.brave.com/latest/winx64-nightly'
50
+ },
51
+ darwin: {
52
+ release: 'https://laptop-updates.brave.com/latest/osx',
53
+ beta: 'https://laptop-updates.brave.com/latest/osx-beta',
54
+ nightly: 'https://laptop-updates.brave.com/latest/osx-nightly'
55
+ }
56
+ };
57
+ class BraveInstaller {
58
+ constructor(options = {}) {
59
+ this.silent = options.silent || false;
60
+ this.downloadDir = options.downloadDir || path.join((0, os_1.homedir)(), '.brave-real-launcher', 'downloads');
61
+ this.channel = options.channel || 'release';
62
+ if (!fs.existsSync(this.downloadDir)) {
63
+ fs.mkdirSync(this.downloadDir, { recursive: true });
64
+ }
65
+ }
66
+ /**
67
+ * Install Brave browser on the current platform
68
+ */
69
+ async install() {
70
+ const platform = (0, utils_js_1.getPlatform)();
71
+ if (!this.silent) {
72
+ logger_js_1.default.log('BraveInstaller', `Installing Brave Browser on ${platform}...`);
73
+ }
74
+ try {
75
+ switch (platform) {
76
+ case 'win32':
77
+ return await this.installWindows();
78
+ case 'linux':
79
+ return await this.installLinux();
80
+ case 'darwin':
81
+ return await this.installMacOS();
82
+ default:
83
+ return { success: false, error: `Unsupported platform: ${platform}` };
84
+ }
85
+ }
86
+ catch (error) {
87
+ return { success: false, error: error.message };
88
+ }
89
+ }
90
+ /**
91
+ * Install Brave on Windows
92
+ */
93
+ async installWindows() {
94
+ const installerPath = path.join(this.downloadDir, 'BraveBrowserSetup.exe');
95
+ const downloadUrl = BRAVE_DOWNLOAD_URLS.win32[this.channel];
96
+ if (!this.silent) {
97
+ logger_js_1.default.log('BraveInstaller', 'Downloading Brave installer for Windows...');
98
+ }
99
+ // Download installer
100
+ await this.downloadFile(downloadUrl, installerPath);
101
+ if (!this.silent) {
102
+ logger_js_1.default.log('BraveInstaller', 'Running Brave installer (silent mode)...');
103
+ }
104
+ // Run installer silently
105
+ try {
106
+ (0, child_process_1.execSync)(`"${installerPath}" /silent /install`, {
107
+ stdio: 'ignore',
108
+ timeout: 300000 // 5 minutes timeout
109
+ });
110
+ }
111
+ catch (error) {
112
+ // Try alternative silent flags
113
+ try {
114
+ (0, child_process_1.execSync)(`"${installerPath}" --system-level --do-not-launch-chrome`, {
115
+ stdio: 'ignore',
116
+ timeout: 300000
117
+ });
118
+ }
119
+ catch (e) {
120
+ // Installation might still succeed, continue checking
121
+ }
122
+ }
123
+ // Wait for installation to complete
124
+ await this.delay(5000);
125
+ // Find Brave installation
126
+ const bravePath = this.findBraveWindows();
127
+ if (bravePath) {
128
+ if (!this.silent) {
129
+ logger_js_1.default.log('BraveInstaller', `Brave installed successfully at: ${bravePath}`);
130
+ }
131
+ // Cleanup installer
132
+ try {
133
+ fs.unlinkSync(installerPath);
134
+ }
135
+ catch (e) { }
136
+ return { success: true, bravePath };
137
+ }
138
+ return { success: false, error: 'Installation completed but Brave not found' };
139
+ }
140
+ /**
141
+ * Install Brave on Linux
142
+ */
143
+ async installLinux() {
144
+ if (!this.silent) {
145
+ logger_js_1.default.log('BraveInstaller', 'Installing Brave on Linux...');
146
+ }
147
+ // Detect package manager
148
+ const packageManager = this.detectLinuxPackageManager();
149
+ try {
150
+ if (packageManager === 'apt') {
151
+ // Debian/Ubuntu based
152
+ (0, child_process_1.execSync)('sudo apt install -y curl', { stdio: 'ignore' });
153
+ (0, child_process_1.execSync)('sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg', { stdio: 'ignore' });
154
+ (0, child_process_1.execSync)('echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main" | sudo tee /etc/apt/sources.list.d/brave-browser-release.list', { stdio: 'ignore' });
155
+ (0, child_process_1.execSync)('sudo apt update', { stdio: 'ignore' });
156
+ (0, child_process_1.execSync)('sudo apt install -y brave-browser', { stdio: 'ignore' });
157
+ }
158
+ else if (packageManager === 'dnf' || packageManager === 'yum') {
159
+ // Fedora/RHEL based
160
+ (0, child_process_1.execSync)('sudo dnf install -y dnf-plugins-core', { stdio: 'ignore' });
161
+ (0, child_process_1.execSync)('sudo dnf config-manager --add-repo https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo', { stdio: 'ignore' });
162
+ (0, child_process_1.execSync)('sudo rpm --import https://brave-browser-rpm-release.s3.brave.com/brave-core.asc', { stdio: 'ignore' });
163
+ (0, child_process_1.execSync)('sudo dnf install -y brave-browser', { stdio: 'ignore' });
164
+ }
165
+ else if (packageManager === 'pacman') {
166
+ // Arch based
167
+ (0, child_process_1.execSync)('yay -S --noconfirm brave-bin', { stdio: 'ignore' });
168
+ }
169
+ else {
170
+ return { success: false, error: `Unsupported package manager. Please install Brave manually.` };
171
+ }
172
+ // Find Brave installation
173
+ const bravePath = this.findBraveLinux();
174
+ if (bravePath) {
175
+ if (!this.silent) {
176
+ logger_js_1.default.log('BraveInstaller', `Brave installed successfully at: ${bravePath}`);
177
+ }
178
+ return { success: true, bravePath };
179
+ }
180
+ return { success: false, error: 'Installation completed but Brave not found' };
181
+ }
182
+ catch (error) {
183
+ return { success: false, error: `Linux installation failed: ${error.message}` };
184
+ }
185
+ }
186
+ /**
187
+ * Install Brave on macOS
188
+ */
189
+ async installMacOS() {
190
+ var _a;
191
+ const dmgPath = path.join(this.downloadDir, 'Brave-Browser.dmg');
192
+ const downloadUrl = BRAVE_DOWNLOAD_URLS.darwin[this.channel];
193
+ if (!this.silent) {
194
+ logger_js_1.default.log('BraveInstaller', 'Downloading Brave for macOS...');
195
+ }
196
+ // Download DMG
197
+ await this.downloadFile(downloadUrl, dmgPath);
198
+ if (!this.silent) {
199
+ logger_js_1.default.log('BraveInstaller', 'Installing Brave...');
200
+ }
201
+ try {
202
+ // Mount DMG
203
+ const mountOutput = (0, child_process_1.execSync)(`hdiutil attach "${dmgPath}" -nobrowse`, { encoding: 'utf-8' });
204
+ const mountPoint = ((_a = mountOutput.split('\t').pop()) === null || _a === void 0 ? void 0 : _a.trim()) || '/Volumes/Brave Browser';
205
+ // Copy to Applications
206
+ (0, child_process_1.execSync)(`cp -R "${mountPoint}/Brave Browser.app" /Applications/`, { stdio: 'ignore' });
207
+ // Unmount DMG
208
+ (0, child_process_1.execSync)(`hdiutil detach "${mountPoint}"`, { stdio: 'ignore' });
209
+ // Cleanup
210
+ try {
211
+ fs.unlinkSync(dmgPath);
212
+ }
213
+ catch (e) { }
214
+ const bravePath = '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser';
215
+ if (fs.existsSync(bravePath)) {
216
+ if (!this.silent) {
217
+ logger_js_1.default.log('BraveInstaller', `Brave installed successfully at: ${bravePath}`);
218
+ }
219
+ return { success: true, bravePath };
220
+ }
221
+ return { success: false, error: 'Installation completed but Brave not found' };
222
+ }
223
+ catch (error) {
224
+ return { success: false, error: `macOS installation failed: ${error.message}` };
225
+ }
226
+ }
227
+ /**
228
+ * Download file from URL
229
+ */
230
+ downloadFile(url, destPath) {
231
+ return new Promise((resolve, reject) => {
232
+ const followRedirect = (url, redirectCount = 0) => {
233
+ if (redirectCount > 10) {
234
+ reject(new Error('Too many redirects'));
235
+ return;
236
+ }
237
+ const protocol = url.startsWith('https') ? https : http;
238
+ protocol.get(url, {
239
+ headers: { 'User-Agent': 'brave-real-launcher' }
240
+ }, (response) => {
241
+ if (response.statusCode === 301 || response.statusCode === 302 || response.statusCode === 307 || response.statusCode === 308) {
242
+ const redirectUrl = response.headers.location;
243
+ if (redirectUrl) {
244
+ followRedirect(redirectUrl, redirectCount + 1);
245
+ return;
246
+ }
247
+ }
248
+ if (response.statusCode !== 200) {
249
+ reject(new Error(`Download failed: ${response.statusCode}`));
250
+ return;
251
+ }
252
+ const file = fs.createWriteStream(destPath);
253
+ response.pipe(file);
254
+ file.on('finish', () => {
255
+ file.close();
256
+ resolve();
257
+ });
258
+ file.on('error', (err) => {
259
+ fs.unlinkSync(destPath);
260
+ reject(err);
261
+ });
262
+ }).on('error', reject);
263
+ };
264
+ followRedirect(url);
265
+ });
266
+ }
267
+ /**
268
+ * Detect Linux package manager
269
+ */
270
+ detectLinuxPackageManager() {
271
+ try {
272
+ (0, child_process_1.execSync)('which apt', { stdio: 'ignore' });
273
+ return 'apt';
274
+ }
275
+ catch (e) { }
276
+ try {
277
+ (0, child_process_1.execSync)('which dnf', { stdio: 'ignore' });
278
+ return 'dnf';
279
+ }
280
+ catch (e) { }
281
+ try {
282
+ (0, child_process_1.execSync)('which yum', { stdio: 'ignore' });
283
+ return 'yum';
284
+ }
285
+ catch (e) { }
286
+ try {
287
+ (0, child_process_1.execSync)('which pacman', { stdio: 'ignore' });
288
+ return 'pacman';
289
+ }
290
+ catch (e) { }
291
+ return 'unknown';
292
+ }
293
+ /**
294
+ * Find Brave on Windows
295
+ */
296
+ findBraveWindows() {
297
+ const paths = [
298
+ `${process.env.LOCALAPPDATA}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
299
+ `${process.env.PROGRAMFILES}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
300
+ `${process.env['PROGRAMFILES(X86)']}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
301
+ ];
302
+ for (const p of paths) {
303
+ if (p && fs.existsSync(p)) {
304
+ return p;
305
+ }
306
+ }
307
+ return null;
308
+ }
309
+ /**
310
+ * Find Brave on Linux
311
+ */
312
+ findBraveLinux() {
313
+ const paths = [
314
+ '/usr/bin/brave-browser',
315
+ '/usr/bin/brave-browser-stable',
316
+ '/opt/brave.com/brave/brave',
317
+ '/snap/bin/brave'
318
+ ];
319
+ for (const p of paths) {
320
+ if (fs.existsSync(p)) {
321
+ return p;
322
+ }
323
+ }
324
+ return null;
325
+ }
326
+ /**
327
+ * Delay helper
328
+ */
329
+ delay(ms) {
330
+ return new Promise(resolve => setTimeout(resolve, ms));
331
+ }
332
+ /**
333
+ * Check if Brave is installed
334
+ */
335
+ static isInstalled() {
336
+ const platform = (0, utils_js_1.getPlatform)();
337
+ const installer = new BraveInstaller({ silent: true });
338
+ switch (platform) {
339
+ case 'win32':
340
+ return installer.findBraveWindows() !== null;
341
+ case 'linux':
342
+ return installer.findBraveLinux() !== null;
343
+ case 'darwin':
344
+ return fs.existsSync('/Applications/Brave Browser.app/Contents/MacOS/Brave Browser');
345
+ default:
346
+ return false;
347
+ }
348
+ }
349
+ }
350
+ exports.BraveInstaller = BraveInstaller;
351
+ exports.default = BraveInstaller;
352
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJhdmUtaW5zdGFsbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2JyYXZlLWluc3RhbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxZQUFZLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRWIsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUM3Qiw2Q0FBK0I7QUFDL0IsMkNBQTZCO0FBQzdCLGlEQUFnRDtBQUNoRCwyQkFBNkI7QUFDN0IsNERBQThCO0FBQzlCLHlDQUF5QztBQWN6QyxNQUFNLG1CQUFtQixHQUFHO0lBQ3hCLEtBQUssRUFBRTtRQUNILE9BQU8sRUFBRSxnREFBZ0Q7UUFDekQsSUFBSSxFQUFFLHFEQUFxRDtRQUMzRCxPQUFPLEVBQUUsd0RBQXdEO0tBQ3BFO0lBQ0QsTUFBTSxFQUFFO1FBQ0osT0FBTyxFQUFFLDZDQUE2QztRQUN0RCxJQUFJLEVBQUUsa0RBQWtEO1FBQ3hELE9BQU8sRUFBRSxxREFBcUQ7S0FDakU7Q0FDSixDQUFDO0FBRUYsTUFBYSxjQUFjO0lBS3ZCLFlBQVksVUFBNEIsRUFBRTtRQUN0QyxJQUFJLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDO1FBQ3RDLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUEsWUFBTyxHQUFFLEVBQUUsc0JBQXNCLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEcsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLFNBQVMsQ0FBQztRQUU1QyxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUU7WUFDbEMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7U0FD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