Buckets:
| import process from 'node:process'; | |
| import {Buffer} from 'node:buffer'; | |
| import path from 'node:path'; | |
| import {fileURLToPath} from 'node:url'; | |
| import {promisify} from 'node:util'; | |
| import childProcess from 'node:child_process'; | |
| import fs, {constants as fsConstants} from 'node:fs/promises'; | |
| import {isWsl, powerShellPath} from 'wsl-utils'; | |
| import defineLazyProperty from 'define-lazy-prop'; | |
| import defaultBrowser from 'default-browser'; | |
| import isInsideContainer from 'is-inside-container'; | |
| const execFile = promisify(childProcess.execFile); | |
| // Path to included `xdg-open`. | |
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | |
| const localXdgOpenPath = path.join(__dirname, 'xdg-open'); | |
| const {platform, arch} = process; | |
| /** | |
| Get the default browser name in Windows from WSL. | |
| @returns {Promise<string>} Browser name. | |
| */ | |
| async function getWindowsDefaultBrowserFromWsl() { | |
| const powershellPath = await powerShellPath(); | |
| const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`; | |
| const encodedCommand = Buffer.from(rawCommand, 'utf16le').toString('base64'); | |
| const {stdout} = await execFile( | |
| powershellPath, | |
| [ | |
| '-NoProfile', | |
| '-NonInteractive', | |
| '-ExecutionPolicy', | |
| 'Bypass', | |
| '-EncodedCommand', | |
| encodedCommand, | |
| ], | |
| {encoding: 'utf8'}, | |
| ); | |
| const progId = stdout.trim(); | |
| // Map ProgId to browser IDs | |
| const browserMap = { | |
| ChromeHTML: 'com.google.chrome', | |
| BraveHTML: 'com.brave.Browser', | |
| MSEdgeHTM: 'com.microsoft.edge', | |
| FirefoxURL: 'org.mozilla.firefox', | |
| }; | |
| return browserMap[progId] ? {id: browserMap[progId]} : {}; | |
| } | |
| const pTryEach = async (array, mapper) => { | |
| let latestError; | |
| for (const item of array) { | |
| try { | |
| return await mapper(item); // eslint-disable-line no-await-in-loop | |
| } catch (error) { | |
| latestError = error; | |
| } | |
| } | |
| throw latestError; | |
| }; | |
| // eslint-disable-next-line complexity | |
| const baseOpen = async options => { | |
| options = { | |
| wait: false, | |
| background: false, | |
| newInstance: false, | |
| allowNonzeroExitCode: false, | |
| ...options, | |
| }; | |
| if (Array.isArray(options.app)) { | |
| return pTryEach(options.app, singleApp => baseOpen({ | |
| ...options, | |
| app: singleApp, | |
| })); | |
| } | |
| let {name: app, arguments: appArguments = []} = options.app ?? {}; | |
| appArguments = [...appArguments]; | |
| if (Array.isArray(app)) { | |
| return pTryEach(app, appName => baseOpen({ | |
| ...options, | |
| app: { | |
| name: appName, | |
| arguments: appArguments, | |
| }, | |
| })); | |
| } | |
| if (app === 'browser' || app === 'browserPrivate') { | |
| // IDs from default-browser for macOS and windows are the same | |
| const ids = { | |
| 'com.google.chrome': 'chrome', | |
| 'google-chrome.desktop': 'chrome', | |
| 'com.brave.Browser': 'brave', | |
| 'org.mozilla.firefox': 'firefox', | |
| 'firefox.desktop': 'firefox', | |
| 'com.microsoft.msedge': 'edge', | |
| 'com.microsoft.edge': 'edge', | |
| 'com.microsoft.edgemac': 'edge', | |
| 'microsoft-edge.desktop': 'edge', | |
| }; | |
| // Incognito flags for each browser in `apps`. | |
| const flags = { | |
| chrome: '--incognito', | |
| brave: '--incognito', | |
| firefox: '--private-window', | |
| edge: '--inPrivate', | |
| }; | |
| const browser = isWsl ? await getWindowsDefaultBrowserFromWsl() : await defaultBrowser(); | |
| if (browser.id in ids) { | |
| const browserName = ids[browser.id]; | |
| if (app === 'browserPrivate') { | |
| appArguments.push(flags[browserName]); | |
| } | |
| return baseOpen({ | |
| ...options, | |
| app: { | |
| name: apps[browserName], | |
| arguments: appArguments, | |
| }, | |
| }); | |
| } | |
| throw new Error(`${browser.name} is not supported as a default browser`); | |
| } | |
| let command; | |
| const cliArguments = []; | |
| const childProcessOptions = {}; | |
| if (platform === 'darwin') { | |
| command = 'open'; | |
| if (options.wait) { | |
| cliArguments.push('--wait-apps'); | |
| } | |
| if (options.background) { | |
| cliArguments.push('--background'); | |
| } | |
| if (options.newInstance) { | |
| cliArguments.push('--new'); | |
| } | |
| if (app) { | |
| cliArguments.push('-a', app); | |
| } | |
| } else if (platform === 'win32' || (isWsl && !isInsideContainer() && !app)) { | |
| command = await powerShellPath(); | |
| cliArguments.push( | |
| '-NoProfile', | |
| '-NonInteractive', | |
| '-ExecutionPolicy', | |
| 'Bypass', | |
| '-EncodedCommand', | |
| ); | |
| if (!isWsl) { | |
| childProcessOptions.windowsVerbatimArguments = true; | |
| } | |
| const encodedArguments = ['Start']; | |
| if (options.wait) { | |
| encodedArguments.push('-Wait'); | |
| } | |
| if (app) { | |
| // Double quote with double quotes to ensure the inner quotes are passed through. | |
| // Inner quotes are delimited for PowerShell interpretation with backticks. | |
| encodedArguments.push(`"\`"${app}\`""`); | |
| if (options.target) { | |
| appArguments.push(options.target); | |
| } | |
| } else if (options.target) { | |
| encodedArguments.push(`"${options.target}"`); | |
| } | |
| if (appArguments.length > 0) { | |
| appArguments = appArguments.map(argument => `"\`"${argument}\`""`); | |
| encodedArguments.push('-ArgumentList', appArguments.join(',')); | |
| } | |
| // Using Base64-encoded command, accepted by PowerShell, to allow special characters. | |
| options.target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64'); | |
| } else { | |
| if (app) { | |
| command = app; | |
| } else { | |
| // When bundled by Webpack, there's no actual package file path and no local `xdg-open`. | |
| const isBundled = !__dirname || __dirname === '/'; | |
| // Check if local `xdg-open` exists and is executable. | |
| let exeLocalXdgOpen = false; | |
| try { | |
| await fs.access(localXdgOpenPath, fsConstants.X_OK); | |
| exeLocalXdgOpen = true; | |
| } catch {} | |
| const useSystemXdgOpen = process.versions.electron | |
| ?? (platform === 'android' || isBundled || !exeLocalXdgOpen); | |
| command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath; | |
| } | |
| if (appArguments.length > 0) { | |
| cliArguments.push(...appArguments); | |
| } | |
| if (!options.wait) { | |
| // `xdg-open` will block the process unless stdio is ignored | |
| // and it's detached from the parent even if it's unref'd. | |
| childProcessOptions.stdio = 'ignore'; | |
| childProcessOptions.detached = true; | |
| } | |
| } | |
| if (platform === 'darwin' && appArguments.length > 0) { | |
| cliArguments.push('--args', ...appArguments); | |
| } | |
| // This has to come after `--args`. | |
| if (options.target) { | |
| cliArguments.push(options.target); | |
| } | |
| const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions); | |
| if (options.wait) { | |
| return new Promise((resolve, reject) => { | |
| subprocess.once('error', reject); | |
| subprocess.once('close', exitCode => { | |
| if (!options.allowNonzeroExitCode && exitCode > 0) { | |
| reject(new Error(`Exited with code ${exitCode}`)); | |
| return; | |
| } | |
| resolve(subprocess); | |
| }); | |
| }); | |
| } | |
| subprocess.unref(); | |
| return subprocess; | |
| }; | |
| const open = (target, options) => { | |
| if (typeof target !== 'string') { | |
| throw new TypeError('Expected a `target`'); | |
| } | |
| return baseOpen({ | |
| ...options, | |
| target, | |
| }); | |
| }; | |
| export const openApp = (name, options) => { | |
| if (typeof name !== 'string' && !Array.isArray(name)) { | |
| throw new TypeError('Expected a valid `name`'); | |
| } | |
| const {arguments: appArguments = []} = options ?? {}; | |
| if (appArguments !== undefined && appArguments !== null && !Array.isArray(appArguments)) { | |
| throw new TypeError('Expected `appArguments` as Array type'); | |
| } | |
| return baseOpen({ | |
| ...options, | |
| app: { | |
| name, | |
| arguments: appArguments, | |
| }, | |
| }); | |
| }; | |
| function detectArchBinary(binary) { | |
| if (typeof binary === 'string' || Array.isArray(binary)) { | |
| return binary; | |
| } | |
| const {[arch]: archBinary} = binary; | |
| if (!archBinary) { | |
| throw new Error(`${arch} is not supported`); | |
| } | |
| return archBinary; | |
| } | |
| function detectPlatformBinary({[platform]: platformBinary}, {wsl}) { | |
| if (wsl && isWsl) { | |
| return detectArchBinary(wsl); | |
| } | |
| if (!platformBinary) { | |
| throw new Error(`${platform} is not supported`); | |
| } | |
| return detectArchBinary(platformBinary); | |
| } | |
| export const apps = {}; | |
| defineLazyProperty(apps, 'chrome', () => detectPlatformBinary({ | |
| darwin: 'google chrome', | |
| win32: 'chrome', | |
| linux: ['google-chrome', 'google-chrome-stable', 'chromium'], | |
| }, { | |
| wsl: { | |
| ia32: '/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe', | |
| x64: ['/mnt/c/Program Files/Google/Chrome/Application/chrome.exe', '/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe'], | |
| }, | |
| })); | |
| defineLazyProperty(apps, 'brave', () => detectPlatformBinary({ | |
| darwin: 'brave browser', | |
| win32: 'brave', | |
| linux: ['brave-browser', 'brave'], | |
| }, { | |
| wsl: { | |
| ia32: '/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe', | |
| x64: ['/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe', '/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe'], | |
| }, | |
| })); | |
| defineLazyProperty(apps, 'firefox', () => detectPlatformBinary({ | |
| darwin: 'firefox', | |
| win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`, | |
| linux: 'firefox', | |
| }, { | |
| wsl: '/mnt/c/Program Files/Mozilla Firefox/firefox.exe', | |
| })); | |
| defineLazyProperty(apps, 'edge', () => detectPlatformBinary({ | |
| darwin: 'microsoft edge', | |
| win32: 'msedge', | |
| linux: ['microsoft-edge', 'microsoft-edge-dev'], | |
| }, { | |
| wsl: '/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe', | |
| })); | |
| defineLazyProperty(apps, 'browser', () => 'browser'); | |
| defineLazyProperty(apps, 'browserPrivate', () => 'browserPrivate'); | |
| export default open; | |
Xet Storage Details
- Size:
- 9.28 kB
- Xet hash:
- 5d3ab6f59370154f1a81f910660b501239a8cadfd7bbe3e6c125bf63ee865ed6
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.