const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electronAPI', { // Platform info (synchronous — available immediately without IPC) platform: process.platform, arch: process.arch, // Persistent config (server URL, session token) config: { get: (key) => ipcRenderer.invoke('config:get', key), set: (key, value) => ipcRenderer.invoke('config:set', key, value), delete: (key) => ipcRenderer.invoke('config:delete', key), }, // Text-to-speech via Piper tts: { speak: (text) => ipcRenderer.invoke('tts:speak', text), stop: () => ipcRenderer.invoke('tts:stop'), }, // Speech-to-text via whisper.cpp stt: { transcribe: (audioBase64) => ipcRenderer.invoke('stt:transcribe', audioBase64), }, // Model downloads download: { start: (type) => ipcRenderer.invoke('download:start', type), check: (type) => ipcRenderer.invoke('download:check', type), status: () => ipcRenderer.invoke('download:status'), onProgress: (callback) => { const listener = (_, data) => callback(data); ipcRenderer.on('download:progress', listener); // Returns a cleanup function so callers can remove the listener return () => ipcRenderer.removeListener('download:progress', listener); }, }, });