import { contextBridge, ipcRenderer } from 'electron'; import { Command, Query } from './cqrs/types'; const LINUX_SCREEN_SHARE_MONITOR_AUDIO_CHUNK_CHANNEL = 'linux-screen-share-monitor-audio-chunk'; const LINUX_SCREEN_SHARE_MONITOR_AUDIO_ENDED_CHANNEL = 'linux-screen-share-monitor-audio-ended'; export interface LinuxScreenShareAudioRoutingInfo { available: boolean; active: boolean; monitorCaptureSupported: boolean; screenShareSinkName: string; screenShareMonitorSourceName: string; voiceSinkName: string; reason?: string; } export interface LinuxScreenShareMonitorCaptureInfo { bitsPerSample: number; captureId: string; channelCount: number; sampleRate: number; sourceName: string; } export interface LinuxScreenShareMonitorAudioChunkPayload { captureId: string; chunk: Uint8Array; } export interface LinuxScreenShareMonitorAudioEndedPayload { captureId: string; reason?: string; } export interface ElectronAPI { minimizeWindow: () => void; maximizeWindow: () => void; closeWindow: () => void; openExternal: (url: string) => Promise; getSources: () => Promise<{ id: string; name: string; thumbnail: string }[]>; prepareLinuxScreenShareAudioRouting: () => Promise; activateLinuxScreenShareAudioRouting: () => Promise; deactivateLinuxScreenShareAudioRouting: () => Promise; startLinuxScreenShareMonitorCapture: () => Promise; stopLinuxScreenShareMonitorCapture: (captureId?: string) => Promise; onLinuxScreenShareMonitorAudioChunk: (listener: (payload: LinuxScreenShareMonitorAudioChunkPayload) => void) => () => void; onLinuxScreenShareMonitorAudioEnded: (listener: (payload: LinuxScreenShareMonitorAudioEndedPayload) => void) => () => void; getAppDataPath: () => Promise; getDesktopSettings: () => Promise<{ hardwareAcceleration: boolean; runtimeHardwareAcceleration: boolean; restartRequired: boolean; }>; setDesktopSettings: (patch: { hardwareAcceleration?: boolean }) => Promise<{ hardwareAcceleration: boolean; runtimeHardwareAcceleration: boolean; restartRequired: boolean; }>; relaunchApp: () => Promise; readFile: (filePath: string) => Promise; writeFile: (filePath: string, data: string) => Promise; saveFileAs: (defaultFileName: string, data: string) => Promise<{ saved: boolean; cancelled: boolean }>; fileExists: (filePath: string) => Promise; deleteFile: (filePath: string) => Promise; ensureDir: (dirPath: string) => Promise; command: (command: Command) => Promise; query: (query: Query) => Promise; } const electronAPI: ElectronAPI = { minimizeWindow: () => ipcRenderer.send('window-minimize'), maximizeWindow: () => ipcRenderer.send('window-maximize'), closeWindow: () => ipcRenderer.send('window-close'), openExternal: (url) => ipcRenderer.invoke('open-external', url), getSources: () => ipcRenderer.invoke('get-sources'), prepareLinuxScreenShareAudioRouting: () => ipcRenderer.invoke('prepare-linux-screen-share-audio-routing'), activateLinuxScreenShareAudioRouting: () => ipcRenderer.invoke('activate-linux-screen-share-audio-routing'), deactivateLinuxScreenShareAudioRouting: () => ipcRenderer.invoke('deactivate-linux-screen-share-audio-routing'), startLinuxScreenShareMonitorCapture: () => ipcRenderer.invoke('start-linux-screen-share-monitor-capture'), stopLinuxScreenShareMonitorCapture: (captureId) => ipcRenderer.invoke('stop-linux-screen-share-monitor-capture', captureId), onLinuxScreenShareMonitorAudioChunk: (listener) => { const wrappedListener = (_event: Electron.IpcRendererEvent, payload: LinuxScreenShareMonitorAudioChunkPayload) => { const chunk = payload.chunk instanceof Uint8Array ? payload.chunk : Uint8Array.from((payload as { chunk?: Iterable }).chunk || []); listener({ ...payload, chunk }); }; ipcRenderer.on(LINUX_SCREEN_SHARE_MONITOR_AUDIO_CHUNK_CHANNEL, wrappedListener); return () => { ipcRenderer.removeListener(LINUX_SCREEN_SHARE_MONITOR_AUDIO_CHUNK_CHANNEL, wrappedListener); }; }, onLinuxScreenShareMonitorAudioEnded: (listener) => { const wrappedListener = (_event: Electron.IpcRendererEvent, payload: LinuxScreenShareMonitorAudioEndedPayload) => { listener(payload); }; ipcRenderer.on(LINUX_SCREEN_SHARE_MONITOR_AUDIO_ENDED_CHANNEL, wrappedListener); return () => { ipcRenderer.removeListener(LINUX_SCREEN_SHARE_MONITOR_AUDIO_ENDED_CHANNEL, wrappedListener); }; }, getAppDataPath: () => ipcRenderer.invoke('get-app-data-path'), getDesktopSettings: () => ipcRenderer.invoke('get-desktop-settings'), setDesktopSettings: (patch) => ipcRenderer.invoke('set-desktop-settings', patch), relaunchApp: () => ipcRenderer.invoke('relaunch-app'), readFile: (filePath) => ipcRenderer.invoke('read-file', filePath), writeFile: (filePath, data) => ipcRenderer.invoke('write-file', filePath, data), saveFileAs: (defaultFileName, data) => ipcRenderer.invoke('save-file-as', defaultFileName, data), fileExists: (filePath) => ipcRenderer.invoke('file-exists', filePath), deleteFile: (filePath) => ipcRenderer.invoke('delete-file', filePath), ensureDir: (dirPath) => ipcRenderer.invoke('ensure-dir', dirPath), command: (command) => ipcRenderer.invoke('cqrs:command', command), query: (query) => ipcRenderer.invoke('cqrs:query', query) }; contextBridge.exposeInMainWorld('electronAPI', electronAPI); declare global { interface Window { electronAPI: ElectronAPI; } }