// See the Electron documentation for details on how to use preload scripts: // https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts import { contextBridge, ipcRenderer } from "electron"; // Whitelist of valid channels const validInvokeChannels = [ "chat:add-dep", "chat:message", "chat:cancel", "chat:stream", "create-chat", "create-app", "get-chat", "get-chats", "list-apps", "get-app", "edit-app-file", "read-app-file", "run-app", "stop-app", "restart-app", "list-versions", "revert-version", "checkout-version", "delete-app", "rename-app", "get-user-settings", "set-user-settings", "get-env-vars", "open-external-url", "reset-all", "nodejs-status", "install-node", "github:start-flow", "github:is-repo-available", "github:create-repo", "github:push", "get-app-version", "reload-env-path", "get-proposal", ] as const; // Add valid receive channels const validReceiveChannels = [ "chat:response:chunk", "chat:response:end", "chat:response:error", "app:output", "github:flow-update", "github:flow-success", "github:flow-error", ] as const; type ValidInvokeChannel = (typeof validInvokeChannels)[number]; type ValidReceiveChannel = (typeof validReceiveChannels)[number]; // Expose protected methods that allow the renderer process to use // the ipcRenderer without exposing the entire object contextBridge.exposeInMainWorld("electron", { ipcRenderer: { invoke: (channel: ValidInvokeChannel, ...args: unknown[]) => { if (validInvokeChannels.includes(channel)) { return ipcRenderer.invoke(channel, ...args); } throw new Error(`Invalid channel: ${channel}`); }, on: ( channel: ValidReceiveChannel, listener: (...args: unknown[]) => void ) => { if (validReceiveChannels.includes(channel)) { const subscription = ( _event: Electron.IpcRendererEvent, ...args: unknown[] ) => listener(...args); ipcRenderer.on(channel, subscription); return () => { ipcRenderer.removeListener(channel, subscription); }; } throw new Error(`Invalid channel: ${channel}`); }, removeAllListeners: (channel: ValidReceiveChannel) => { if (validReceiveChannels.includes(channel)) { ipcRenderer.removeAllListeners(channel); } }, removeListener: ( channel: ValidReceiveChannel, listener: (...args: unknown[]) => void ) => { if (validReceiveChannels.includes(channel)) { ipcRenderer.removeListener(channel, listener); } }, }, });