// src/preload.js const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { // Platform information for renderer processes platform: { isLinux: process.platform === 'linux', isMacOS: process.platform === 'darwin', isWindows: process.platform === 'win32', platform: process.platform }, // Common utilities used across multiple components common: { // User & Auth getCurrentUser: () => ipcRenderer.invoke('get-current-user'), startFirebaseAuth: () => ipcRenderer.invoke('start-firebase-auth'), firebaseLogout: () => ipcRenderer.invoke('firebase-logout'), // App Control quitApplication: () => ipcRenderer.invoke('quit-application'), openExternal: (url) => ipcRenderer.invoke('open-external', url), // User state listener (used by multiple components) onUserStateChanged: (callback) => ipcRenderer.on('user-state-changed', callback), removeOnUserStateChanged: (callback) => ipcRenderer.removeListener('user-state-changed', callback), }, // UI Component specific namespaces // src/ui/app/ApiKeyHeader.js apiKeyHeader: { // Model & Provider Management getProviderConfig: () => ipcRenderer.invoke('model:get-provider-config'), // LocalAI 통합 API getLocalAIStatus: (service) => ipcRenderer.invoke('localai:get-status', service), installLocalAI: (service, options) => ipcRenderer.invoke('localai:install', { service, options }), startLocalAIService: (service) => ipcRenderer.invoke('localai:start-service', service), stopLocalAIService: (service) => ipcRenderer.invoke('localai:stop-service', service), installLocalAIModel: (service, modelId, options) => ipcRenderer.invoke('localai:install-model', { service, modelId, options }), getInstalledModels: (service) => ipcRenderer.invoke('localai:get-installed-models', service), // Legacy support (호환성 위해 유지) getOllamaStatus: () => ipcRenderer.invoke('localai:get-status', 'ollama'), getModelSuggestions: () => ipcRenderer.invoke('ollama:get-model-suggestions'), ensureOllamaReady: () => ipcRenderer.invoke('ollama:ensure-ready'), installOllama: () => ipcRenderer.invoke('localai:install', { service: 'ollama' }), startOllamaService: () => ipcRenderer.invoke('localai:start-service', 'ollama'), pullOllamaModel: (modelName) => ipcRenderer.invoke('ollama:pull-model', modelName), downloadWhisperModel: (modelId) => ipcRenderer.invoke('whisper:download-model', modelId), validateKey: (data) => ipcRenderer.invoke('model:validate-key', data), setSelectedModel: (data) => ipcRenderer.invoke('model:set-selected-model', data), areProvidersConfigured: () => ipcRenderer.invoke('model:are-providers-configured'), // Window Management getHeaderPosition: () => ipcRenderer.invoke('get-header-position'), moveHeaderTo: (x, y) => ipcRenderer.invoke('move-header-to', x, y), // Listeners // LocalAI 통합 이벤트 리스너 onLocalAIProgress: (callback) => ipcRenderer.on('localai:install-progress', callback), removeOnLocalAIProgress: (callback) => ipcRenderer.removeListener('localai:install-progress', callback), onLocalAIComplete: (callback) => ipcRenderer.on('localai:installation-complete', callback), removeOnLocalAIComplete: (callback) => ipcRenderer.removeListener('localai:installation-complete', callback), onLocalAIError: (callback) => ipcRenderer.on('localai:error-notification', callback), removeOnLocalAIError: (callback) => ipcRenderer.removeListener('localai:error-notification', callback), onLocalAIModelReady: (callback) => ipcRenderer.on('localai:model-ready', callback), removeOnLocalAIModelReady: (callback) => ipcRenderer.removeListener('localai:model-ready', callback), // Remove all listeners (for cleanup) removeAllListeners: () => { // LocalAI 통합 이벤트 ipcRenderer.removeAllListeners('localai:install-progress'); ipcRenderer.removeAllListeners('localai:installation-complete'); ipcRenderer.removeAllListeners('localai:error-notification'); ipcRenderer.removeAllListeners('localai:model-ready'); ipcRenderer.removeAllListeners('localai:service-status-changed'); } }, // src/ui/app/HeaderController.js headerController: { // State Management sendHeaderStateChanged: (state) => ipcRenderer.send('header-state-changed', state), // Window Management resizeHeaderWindow: (dimensions) => ipcRenderer.invoke('resize-header-window', dimensions), // Permissions checkSystemPermissions: () => ipcRenderer.invoke('check-system-permissions'), checkPermissionsCompleted: () => ipcRenderer.invoke('check-permissions-completed'), // Listeners onUserStateChanged: (callback) => ipcRenderer.on('user-state-changed', callback), removeOnUserStateChanged: (callback) => ipcRenderer.removeListener('user-state-changed', callback), onAuthFailed: (callback) => ipcRenderer.on('auth-failed', callback), removeOnAuthFailed: (callback) => ipcRenderer.removeListener('auth-failed', callback), onForceShowApiKeyHeader: (callback) => ipcRenderer.on('force-show-apikey-header', callback), removeOnForceShowApiKeyHeader: (callback) => ipcRenderer.removeListener('force-show-apikey-header', callback) }, // src/ui/app/MainHeader.js mainHeader: { // Window Management getHeaderPosition: () => ipcRenderer.invoke('get-header-position'), moveHeaderTo: (x, y) => ipcRenderer.invoke('move-header-to', x, y), sendHeaderAnimationFinished: (state) => ipcRenderer.send('header-animation-finished', state), // Settings Window Management cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), showSettingsWindow: () => ipcRenderer.send('show-settings-window'), hideSettingsWindow: () => ipcRenderer.send('hide-settings-window'), // Generic invoke (for dynamic channel names) // invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args), sendListenButtonClick: (listenButtonText) => ipcRenderer.invoke('listen:changeSession', listenButtonText), sendAskButtonClick: () => ipcRenderer.invoke('ask:toggleAskButton'), sendToggleAllWindowsVisibility: () => ipcRenderer.invoke('shortcut:toggleAllWindowsVisibility'), // Listeners onListenChangeSessionResult: (callback) => ipcRenderer.on('listen:changeSessionResult', callback), removeOnListenChangeSessionResult: (callback) => ipcRenderer.removeListener('listen:changeSessionResult', callback), onShortcutsUpdated: (callback) => ipcRenderer.on('shortcuts-updated', callback), removeOnShortcutsUpdated: (callback) => ipcRenderer.removeListener('shortcuts-updated', callback) }, // src/ui/app/PermissionHeader.js permissionHeader: { // Permission Management checkSystemPermissions: () => ipcRenderer.invoke('check-system-permissions'), requestMicrophonePermission: () => ipcRenderer.invoke('request-microphone-permission'), openSystemPreferences: (preference) => ipcRenderer.invoke('open-system-preferences', preference), markPermissionsCompleted: () => ipcRenderer.invoke('mark-permissions-completed') }, // src/ui/app/PickleGlassApp.js pickleGlassApp: { // Listeners onClickThroughToggled: (callback) => ipcRenderer.on('click-through-toggled', callback), removeOnClickThroughToggled: (callback) => ipcRenderer.removeListener('click-through-toggled', callback), removeAllClickThroughListeners: () => ipcRenderer.removeAllListeners('click-through-toggled') }, // src/ui/ask/AskView.js askView: { // Window Management closeAskWindow: () => ipcRenderer.invoke('ask:closeAskWindow'), adjustWindowHeight: (height) => ipcRenderer.invoke('adjust-window-height', height), // Message Handling sendMessage: (text) => ipcRenderer.invoke('ask:sendQuestionFromAsk', text), // Listeners onAskStateUpdate: (callback) => ipcRenderer.on('ask:stateUpdate', callback), removeOnAskStateUpdate: (callback) => ipcRenderer.removeListener('ask:stateUpdate', callback), onAskStreamError: (callback) => ipcRenderer.on('ask-response-stream-error', callback), removeOnAskStreamError: (callback) => ipcRenderer.removeListener('ask-response-stream-error', callback), // Listeners onShowTextInput: (callback) => ipcRenderer.on('ask:showTextInput', callback), removeOnShowTextInput: (callback) => ipcRenderer.removeListener('ask:showTextInput', callback), onScrollResponseUp: (callback) => ipcRenderer.on('aks:scrollResponseUp', callback), removeOnScrollResponseUp: (callback) => ipcRenderer.removeListener('aks:scrollResponseUp', callback), onScrollResponseDown: (callback) => ipcRenderer.on('aks:scrollResponseDown', callback), removeOnScrollResponseDown: (callback) => ipcRenderer.removeListener('aks:scrollResponseDown', callback) }, // src/ui/listen/ListenView.js listenView: { // Window Management adjustWindowHeight: (height) => ipcRenderer.invoke('adjust-window-height', height), // Listeners onSessionStateChanged: (callback) => ipcRenderer.on('session-state-changed', callback), removeOnSessionStateChanged: (callback) => ipcRenderer.removeListener('session-state-changed', callback) }, // src/ui/listen/stt/SttView.js sttView: { // Listeners onSttUpdate: (callback) => ipcRenderer.on('stt-update', callback), removeOnSttUpdate: (callback) => ipcRenderer.removeListener('stt-update', callback) }, // src/ui/listen/summary/SummaryView.js summaryView: { // Message Handling sendQuestionFromSummary: (text) => ipcRenderer.invoke('ask:sendQuestionFromSummary', text), // Listeners onSummaryUpdate: (callback) => ipcRenderer.on('summary-update', callback), removeOnSummaryUpdate: (callback) => ipcRenderer.removeListener('summary-update', callback), removeAllSummaryUpdateListeners: () => ipcRenderer.removeAllListeners('summary-update') }, // src/ui/settings/SettingsView.js settingsView: { // User & Auth getCurrentUser: () => ipcRenderer.invoke('get-current-user'), openPersonalizePage: () => ipcRenderer.invoke('open-personalize-page'), firebaseLogout: () => ipcRenderer.invoke('firebase-logout'), startFirebaseAuth: () => ipcRenderer.invoke('start-firebase-auth'), // Model & Provider Management getModelSettings: () => ipcRenderer.invoke('settings:get-model-settings'), // Facade call getProviderConfig: () => ipcRenderer.invoke('model:get-provider-config'), getAllKeys: () => ipcRenderer.invoke('model:get-all-keys'), getAvailableModels: (type) => ipcRenderer.invoke('model:get-available-models', type), getSelectedModels: () => ipcRenderer.invoke('model:get-selected-models'), validateKey: (data) => ipcRenderer.invoke('model:validate-key', data), saveApiKey: (key) => ipcRenderer.invoke('model:save-api-key', key), removeApiKey: (provider) => ipcRenderer.invoke('model:remove-api-key', provider), setSelectedModel: (data) => ipcRenderer.invoke('model:set-selected-model', data), // Ollama Management getOllamaStatus: () => ipcRenderer.invoke('ollama:get-status'), ensureOllamaReady: () => ipcRenderer.invoke('ollama:ensure-ready'), shutdownOllama: (graceful) => ipcRenderer.invoke('ollama:shutdown', graceful), // Whisper Management getWhisperInstalledModels: () => ipcRenderer.invoke('whisper:get-installed-models'), downloadWhisperModel: (modelId) => ipcRenderer.invoke('whisper:download-model', modelId), // Settings Management getPresets: () => ipcRenderer.invoke('settings:getPresets'), getAutoUpdate: () => ipcRenderer.invoke('settings:get-auto-update'), setAutoUpdate: (isEnabled) => ipcRenderer.invoke('settings:set-auto-update', isEnabled), getContentProtectionStatus: () => ipcRenderer.invoke('get-content-protection-status'), toggleContentProtection: () => ipcRenderer.invoke('toggle-content-protection'), getCurrentShortcuts: () => ipcRenderer.invoke('settings:getCurrentShortcuts'), openShortcutSettingsWindow: () => ipcRenderer.invoke('shortcut:openShortcutSettingsWindow'), // Window Management moveWindowStep: (direction) => ipcRenderer.invoke('move-window-step', direction), cancelHideSettingsWindow: () => ipcRenderer.send('cancel-hide-settings-window'), hideSettingsWindow: () => ipcRenderer.send('hide-settings-window'), // App Control quitApplication: () => ipcRenderer.invoke('quit-application'), // Progress Tracking pullOllamaModel: (modelName) => ipcRenderer.invoke('ollama:pull-model', modelName), // Listeners onUserStateChanged: (callback) => ipcRenderer.on('user-state-changed', callback), removeOnUserStateChanged: (callback) => ipcRenderer.removeListener('user-state-changed', callback), onSettingsUpdated: (callback) => ipcRenderer.on('settings-updated', callback), removeOnSettingsUpdated: (callback) => ipcRenderer.removeListener('settings-updated', callback), onPresetsUpdated: (callback) => ipcRenderer.on('presets-updated', callback), removeOnPresetsUpdated: (callback) => ipcRenderer.removeListener('presets-updated', callback), onShortcutsUpdated: (callback) => ipcRenderer.on('shortcuts-updated', callback), removeOnShortcutsUpdated: (callback) => ipcRenderer.removeListener('shortcuts-updated', callback), // 통합 LocalAI 이벤트 사용 onLocalAIInstallProgress: (callback) => ipcRenderer.on('localai:install-progress', callback), removeOnLocalAIInstallProgress: (callback) => ipcRenderer.removeListener('localai:install-progress', callback), onLocalAIInstallationComplete: (callback) => ipcRenderer.on('localai:installation-complete', callback), removeOnLocalAIInstallationComplete: (callback) => ipcRenderer.removeListener('localai:installation-complete', callback) }, // src/ui/settings/ShortCutSettingsView.js shortcutSettingsView: { // Shortcut Management saveShortcuts: (shortcuts) => ipcRenderer.invoke('shortcut:saveShortcuts', shortcuts), getDefaultShortcuts: () => ipcRenderer.invoke('shortcut:getDefaultShortcuts'), closeShortcutSettingsWindow: () => ipcRenderer.invoke('shortcut:closeShortcutSettingsWindow'), // Listeners onLoadShortcuts: (callback) => ipcRenderer.on('shortcut:loadShortcuts', callback), removeOnLoadShortcuts: (callback) => ipcRenderer.removeListener('shortcut:loadShortcuts', callback) }, // src/ui/app/content.html inline scripts content: { // Listeners onSettingsWindowHideAnimation: (callback) => ipcRenderer.on('settings-window-hide-animation', callback), removeOnSettingsWindowHideAnimation: (callback) => ipcRenderer.removeListener('settings-window-hide-animation', callback), }, // src/ui/listen/audioCore/listenCapture.js listenCapture: { // Audio Management sendMicAudioContent: (data) => ipcRenderer.invoke('listen:sendMicAudio', data), sendSystemAudioContent: (data) => ipcRenderer.invoke('listen:sendSystemAudio', data), startMacosSystemAudio: () => ipcRenderer.invoke('listen:startMacosSystemAudio'), stopMacosSystemAudio: () => ipcRenderer.invoke('listen:stopMacosSystemAudio'), // Session Management isSessionActive: () => ipcRenderer.invoke('is-session-active'), // Listeners onSystemAudioData: (callback) => ipcRenderer.on('system-audio-data', callback), removeOnSystemAudioData: (callback) => ipcRenderer.removeListener('system-audio-data', callback) }, // src/ui/listen/audioCore/renderer.js renderer: { // Listeners onChangeListenCaptureState: (callback) => ipcRenderer.on('change-listen-capture-state', callback), removeOnChangeListenCaptureState: (callback) => ipcRenderer.removeListener('change-listen-capture-state', callback) } });