import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Scope from "effect/Scope"; import * as Electron from "electron"; export interface ElectronAppMetadata { readonly appVersion: string; readonly appPath: string; readonly isPackaged: boolean; readonly resourcesPath: string; readonly runningUnderArm64Translation: boolean; } export interface ElectronAppShape { readonly metadata: Effect.Effect; readonly name: Effect.Effect; readonly whenReady: Effect.Effect; readonly quit: Effect.Effect; readonly exit: (code: number) => Effect.Effect; readonly relaunch: (options: Electron.RelaunchOptions) => Effect.Effect; readonly setPath: ( name: Parameters[0], path: string, ) => Effect.Effect; readonly setName: (name: string) => Effect.Effect; readonly setAboutPanelOptions: ( options: Electron.AboutPanelOptionsOptions, ) => Effect.Effect; readonly setAppUserModelId: (id: string) => Effect.Effect; readonly setDesktopName: (desktopName: string) => Effect.Effect; readonly setDockIcon: (iconPath: string) => Effect.Effect; readonly appendCommandLineSwitch: (switchName: string, value?: string) => Effect.Effect; readonly on: >( eventName: string, listener: (...args: Args) => void, ) => Effect.Effect; } export class ElectronApp extends Context.Service()( "@t3tools/desktop/electron/ElectronApp", ) {} const addScopedAppListener = >( eventName: string, listener: (...args: Args) => void, ): Effect.Effect => Effect.acquireRelease( Effect.sync(() => { Electron.app.on(eventName as any, listener as any); }), () => Effect.sync(() => { Electron.app.removeListener(eventName as any, listener as any); }), ).pipe(Effect.asVoid); const make = ElectronApp.of({ metadata: Effect.sync(() => ({ appVersion: Electron.app.getVersion(), appPath: Electron.app.getAppPath(), isPackaged: Electron.app.isPackaged, resourcesPath: process.resourcesPath, runningUnderArm64Translation: Electron.app.runningUnderARM64Translation === true, })), name: Effect.sync(() => Electron.app.name), whenReady: Effect.promise(() => Electron.app.whenReady()).pipe(Effect.asVoid), quit: Effect.sync(() => { Electron.app.quit(); }), exit: (code) => Effect.sync(() => { Electron.app.exit(code); }), relaunch: (options) => Effect.sync(() => { Electron.app.relaunch(options); }), setPath: (name, path) => Effect.sync(() => { Electron.app.setPath(name, path); }), setName: (name) => Effect.sync(() => { Electron.app.setName(name); }), setAboutPanelOptions: (options) => Effect.sync(() => { Electron.app.setAboutPanelOptions(options); }), setAppUserModelId: (id) => Effect.sync(() => { Electron.app.setAppUserModelId(id); }), setDesktopName: (desktopName) => Effect.sync(() => { const linuxApp = Electron.app as Electron.App & { setDesktopName?: (desktopName: string) => void; }; linuxApp.setDesktopName?.(desktopName); }), setDockIcon: (iconPath) => Effect.sync(() => { Electron.app.dock?.setIcon(iconPath); }), appendCommandLineSwitch: (switchName, value) => Effect.sync(() => { if (value === undefined) { Electron.app.commandLine.appendSwitch(switchName); return; } Electron.app.commandLine.appendSwitch(switchName, value); }), on: addScopedAppListener, }); export const layer = Layer.succeed(ElectronApp, make);