1*edeec536SEvan Baconimport * as osascript from '@expo/osascript'; 2*edeec536SEvan Baconimport { spawn, type ChildProcess } from 'child_process'; 3*edeec536SEvan Baconimport { sync as globSync } from 'glob'; 4*edeec536SEvan Baconimport path from 'path'; 5*edeec536SEvan Bacon 6*edeec536SEvan Baconimport { 7*edeec536SEvan Bacon LaunchBrowserTypes, 8*edeec536SEvan Bacon type LaunchBrowserImpl, 9*edeec536SEvan Bacon type LaunchBrowserInstance, 10*edeec536SEvan Bacon} from './LaunchBrowser.types'; 11*edeec536SEvan Bacon 12*edeec536SEvan Bacon/** 13*edeec536SEvan Bacon * Browser implementation for macOS 14*edeec536SEvan Bacon */ 15*edeec536SEvan Baconexport default class LaunchBrowserImplMacOS implements LaunchBrowserImpl, LaunchBrowserInstance { 16*edeec536SEvan Bacon private _process: ChildProcess | undefined; 17*edeec536SEvan Bacon 18*edeec536SEvan Bacon MAP = { 19*edeec536SEvan Bacon [LaunchBrowserTypes.CHROME]: 'google chrome', 20*edeec536SEvan Bacon [LaunchBrowserTypes.EDGE]: 'microsoft edge', 21*edeec536SEvan Bacon }; 22*edeec536SEvan Bacon 23*edeec536SEvan Bacon async isSupportedBrowser(browserType: LaunchBrowserTypes): Promise<boolean> { 24*edeec536SEvan Bacon let result = false; 25*edeec536SEvan Bacon try { 26*edeec536SEvan Bacon await osascript.execAsync(`id of application "${this.MAP[browserType]}"`); 27*edeec536SEvan Bacon result = true; 28*edeec536SEvan Bacon } catch { 29*edeec536SEvan Bacon result = false; 30*edeec536SEvan Bacon } 31*edeec536SEvan Bacon return result; 32*edeec536SEvan Bacon } 33*edeec536SEvan Bacon 34*edeec536SEvan Bacon async createTempBrowserDir(baseDirName: string) { 35*edeec536SEvan Bacon return path.join(require('temp-dir'), baseDirName); 36*edeec536SEvan Bacon } 37*edeec536SEvan Bacon 38*edeec536SEvan Bacon async launchAsync( 39*edeec536SEvan Bacon browserType: LaunchBrowserTypes, 40*edeec536SEvan Bacon args: string[] 41*edeec536SEvan Bacon ): Promise<LaunchBrowserInstance> { 42*edeec536SEvan Bacon const appDirectory = await osascript.execAsync( 43*edeec536SEvan Bacon `POSIX path of (path to application "${this.MAP[browserType]}")` 44*edeec536SEvan Bacon ); 45*edeec536SEvan Bacon const appPath = globSync('Contents/MacOS/*', { cwd: appDirectory.trim(), absolute: true })?.[0]; 46*edeec536SEvan Bacon if (!appPath) { 47*edeec536SEvan Bacon throw new Error(`Cannot find application path from ${appDirectory}Contents/MacOS`); 48*edeec536SEvan Bacon } 49*edeec536SEvan Bacon this._process = spawn(appPath, args, { stdio: 'ignore' }); 50*edeec536SEvan Bacon 51*edeec536SEvan Bacon return this; 52*edeec536SEvan Bacon } 53*edeec536SEvan Bacon 54*edeec536SEvan Bacon async close(): Promise<void> { 55*edeec536SEvan Bacon this._process?.kill(); 56*edeec536SEvan Bacon this._process = undefined; 57*edeec536SEvan Bacon } 58*edeec536SEvan Bacon} 59