import { BrowserView } from 'electrobun/bun' import { checkForCompletedUpdate, getRunningAppVersion, startAppUpdate } from './appupdate.js' import { checkForDuplicateInstallations, removeDuplicateInstallations } from './check-duplicate-installations.js' import { setSidebarViewMenu } from './menu.js' import { sendToAllWindows, sendToRenderer, sendToWindow } from './notify.js' import { resizeSpotlightWindow } from './spotlight.js' import { clearAuthSession, getAppSettings, getAuthSession, setAppSettings, setAuthSession } from './store.js' import { createAppWindow, getMainWindow, getWindowSession, getWindowState, handleWindowControl, openExternalUrl, openInternalUrl, syncWindowTabs, beginTabDrag, completeTabDrop, cancelTabDrag } from './window.js' export function createAppRpc() { const requestHandlers = { getOsInfo: async () => ({ platform: process.platform }), getWindowState: async ({ windowId } = {}) => getWindowState(windowId), windowControl: async ({ action, windowId } = {}) => { handleWindowControl(action, windowId) return { ok: true } }, syncWindowTabs: async ({ windowId, activeTabId, tabs } = {}) => ({ ok: syncWindowTabs(windowId, { activeTabId, tabs }) }), getWindowSession: async ({ windowId } = {}) => getWindowSession(windowId), createAppWindow: async ({ tabs, activeTabId, windowId } = {}) => { await createAppWindow({ tabs, activeTabId, sourceWindowId: windowId }) return { ok: true } }, beginTabDrag: async ({ windowId, tab } = {}) => beginTabDrag({ windowId, tab }), completeTabDrop: async ({ windowId, beforeTabId, insertBefore } = {}) => completeTabDrop({ windowId, beforeTabId, insertBefore }), cancelTabDrag: async ({ windowId } = {}) => cancelTabDrag({ windowId }), openExternalUrl: async ({ url }) => { openExternalUrl(url) return { ok: true } }, openInternalUrl: async ({ url }) => ({ ok: openInternalUrl(url) }), getAuthSession: async () => getAuthSession(), setAuthSession: async ({ session }) => ({ ok: await setAuthSession(session) }), clearAuthSession: async () => ({ ok: await clearAuthSession() }), getAppSettings: async () => getAppSettings(), setAppSettings: async ({ settings }) => ({ ok: await setAppSettings(settings) }), startAppUpdate: async ({ update }) => { const mainWindow = getMainWindow() const sendProgress = (payload) => { sendToAllWindows('appUpdateProgress', { timestamp: new Date().toISOString(), ...payload }) } // Updates can take several minutes; return immediately and report // progress via appUpdateProgress messages instead of blocking RPC. void startAppUpdate(mainWindow, update, sendProgress).catch((error) => { console.error('App update failed:', error) }) return { ok: true } }, resizeSpotlightWindow: async ({ height }) => ({ ok: resizeSpotlightWindow(height) }), setSidebarViewMenu: async ({ sections }) => ({ ok: setSidebarViewMenu(sections) }), checkAppUpdateResult: async () => checkForCompletedUpdate(getMainWindow()), checkDuplicateInstallations: async () => checkForDuplicateInstallations(), removeDuplicateInstallations: async () => { // Removal waits on an admin/UAC prompt which can outlive the RPC // timeout; report the outcome via a push message instead. void removeDuplicateInstallations() .catch((error) => ({ ok: false, error: error?.message || 'Failed to remove the duplicate installation.' })) .then((result) => { sendToAllWindows('duplicateInstallationsRemoved', result) }) return { ok: true } }, getAppVersion: async () => getRunningAppVersion() || 'desktop', getAppEngine: async () => { const mainWindow = getMainWindow() const renderer = mainWindow?.renderer || 'native' return renderer === 'cef' ? 'chromium' : 'native' } } return BrowserView.defineRPC({ maxRequestTime: 30000, handlers: { requests: requestHandlers, messages: { rendererRequest: ({ id, method, params, windowId }) => { const requestParams = params || {} const requestWindowId = windowId || requestParams.windowId const respond = (payload) => { if (requestWindowId) { sendToWindow(requestWindowId, 'rpcResponse', payload) return } sendToRenderer('rpcResponse', payload) } const handler = requestHandlers[method] if (!handler) { respond({ id, success: false, error: `Unknown desktop RPC method: ${String(method)}` }) return } void Promise.resolve() .then(() => handler(requestParams)) .then((result) => { respond({ id, success: true, result }) }) .catch((error) => { respond({ id, success: false, error: error?.message || String(error) }) }) } } } }) }