diff --git a/ui/desktop/forge.config.ts b/ui/desktop/forge.config.ts index 73e2d0745a..c7f9928ef3 100644 --- a/ui/desktop/forge.config.ts +++ b/ui/desktop/forge.config.ts @@ -65,7 +65,7 @@ module.exports = { target: 'main', }, { - entry: 'src/preload.js', + entry: 'src/preload.ts', config: 'vite.preload.config.ts', target: 'preload', }, diff --git a/ui/desktop/src/ChatWindow.tsx b/ui/desktop/src/ChatWindow.tsx index 3e6706326a..4820b88463 100644 --- a/ui/desktop/src/ChatWindow.tsx +++ b/ui/desktop/src/ChatWindow.tsx @@ -23,25 +23,6 @@ import { createSelectedModel } from './components/settings/models/utils'; import { getDefaultModel } from './components/settings/models/hardcoded_stuff'; import Splash from './components/Splash'; -declare global { - interface Window { - electron: { - stopPowerSaveBlocker: () => void; - startPowerSaveBlocker: () => void; - hideWindow: () => void; - createChatWindow: () => void; - getConfig: () => { GOOSE_PROVIDER: string }; - logInfo: (message: string) => void; - showNotification: (opts: { title: string; body: string }) => void; - getBinaryPath: (binary: string) => Promise<string>; - app: any; - }; - appConfig: { - get: (key: string) => any; - }; - } -} - export interface Chat { id: number; title: string; diff --git a/ui/desktop/src/LauncherWindow.tsx b/ui/desktop/src/LauncherWindow.tsx index a4723a6532..ab1ae24503 100644 --- a/ui/desktop/src/LauncherWindow.tsx +++ b/ui/desktop/src/LauncherWindow.tsx @@ -1,18 +1,5 @@ import React, { useRef, useState } from 'react'; -declare global { - interface Window { - electron: { - logInfo(msg: string): unknown; - on(channel: string, arg1: (event: any, message: any) => void): unknown; - stopPowerSaveBlocker(): unknown; - startPowerSaveBlocker(): unknown; - hideWindow: () => void; - createChatWindow: (query: string) => void; - }; - } -} - export default function SpotlightWindow() { const [query, setQuery] = useState(''); const inputRef = useRef<HTMLInputElement>(null); diff --git a/ui/desktop/src/components/Input.tsx b/ui/desktop/src/components/Input.tsx index adeb6764fa..24d00f7a85 100644 --- a/ui/desktop/src/components/Input.tsx +++ b/ui/desktop/src/components/Input.tsx @@ -10,14 +10,6 @@ interface InputProps { onStop?: () => void; } -declare global { - interface Window { - electron: { - selectFileOrDirectory: () => Promise<string | null>; - }; - } -} - export default function Input({ handleSubmit, disabled = false, diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 003e3f41d6..3ceaf762bf 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -98,7 +98,7 @@ const createLauncher = () => { frame: false, transparent: false, webPreferences: { - preload: path.join(__dirname, 'preload.js'), + preload: path.join(__dirname, 'preload.ts'), additionalArguments: [JSON.stringify(appConfig)], partition: 'persist:goose', }, diff --git a/ui/desktop/src/preload.js b/ui/desktop/src/preload.js deleted file mode 100644 index d78ae3bb67..0000000000 --- a/ui/desktop/src/preload.js +++ /dev/null @@ -1,28 +0,0 @@ -const { contextBridge, ipcRenderer } = require('electron') - -const config = JSON.parse(process.argv.find((arg) => arg.startsWith('{')) || '{}'); - -contextBridge.exposeInMainWorld('appConfig', { - get: (key) => config[key], - getAll: () => config, -}); - -contextBridge.exposeInMainWorld('electron', { - getConfig: () => config, - hideWindow: () => ipcRenderer.send('hide-window'), - directoryChooser: (replace) => ipcRenderer.send('directory-chooser', replace), - createChatWindow: (query, dir, version) => ipcRenderer.send('create-chat-window', query, dir, version), - logInfo: (txt) => ipcRenderer.send('logInfo', txt), - showNotification: (data) => ipcRenderer.send('notify', data), - createWingToWingWindow: (query) => ipcRenderer.send('create-wing-to-wing-window', query), - openInChrome: (url) => ipcRenderer.send('open-in-chrome', url), - fetchMetadata: (url) => ipcRenderer.invoke('fetch-metadata', url), - reloadApp: () => ipcRenderer.send('reload-app'), - checkForOllama: () => ipcRenderer.invoke('check-ollama'), - selectFileOrDirectory: () => ipcRenderer.invoke('select-file-or-directory'), - startPowerSaveBlocker: () => ipcRenderer.invoke('start-power-save-blocker'), - stopPowerSaveBlocker: () => ipcRenderer.invoke('stop-power-save-blocker'), - getBinaryPath: (binaryName) => ipcRenderer.invoke('get-binary-path', binaryName), - on: (channel, callback) => ipcRenderer.on(channel, callback), - off: (channel, callback) => ipcRenderer.off(channel, callback) -}); diff --git a/ui/desktop/src/preload.ts b/ui/desktop/src/preload.ts new file mode 100644 index 0000000000..51105a5788 --- /dev/null +++ b/ui/desktop/src/preload.ts @@ -0,0 +1,77 @@ +import Electron, { contextBridge, ipcRenderer } from 'electron'; + +const config = JSON.parse(process.argv.find((arg) => arg.startsWith('{')) || '{}'); + +// Define the API types in a single place +type ElectronAPI = { + getConfig: () => Record<string, any>; + hideWindow: () => void; + directoryChooser: (replace: string) => void; + createChatWindow: (query?: string, dir?: string, version?: string) => void; + logInfo: (txt: string) => void; + showNotification: (data: any) => void; + createWingToWingWindow: (query: string) => void; + openInChrome: (url: string) => void; + fetchMetadata: (url: string) => Promise<any>; + reloadApp: () => void; + checkForOllama: () => Promise<boolean>; + selectFileOrDirectory: () => Promise<string>; + startPowerSaveBlocker: () => Promise<number>; + stopPowerSaveBlocker: () => Promise<void>; + getBinaryPath: (binaryName: string) => Promise<string>; + on: ( + channel: string, + callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void + ) => void; + off: ( + channel: string, + callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void + ) => void; +}; + +type AppConfigAPI = { + get: (key: string) => any; + getAll: () => Record<string, any>; +}; + +const electronAPI: ElectronAPI = { + getConfig: () => config, + hideWindow: () => ipcRenderer.send('hide-window'), + directoryChooser: (replace: string) => ipcRenderer.send('directory-chooser', replace), + createChatWindow: (query?: string, dir?: string, version?: string) => + ipcRenderer.send('create-chat-window', query, dir, version), + logInfo: (txt: string) => ipcRenderer.send('logInfo', txt), + showNotification: (data: any) => ipcRenderer.send('notify', data), + createWingToWingWindow: (query: string) => ipcRenderer.send('create-wing-to-wing-window', query), + openInChrome: (url: string) => ipcRenderer.send('open-in-chrome', url), + fetchMetadata: (url: string) => ipcRenderer.invoke('fetch-metadata', url), + reloadApp: () => ipcRenderer.send('reload-app'), + checkForOllama: () => ipcRenderer.invoke('check-ollama'), + selectFileOrDirectory: () => ipcRenderer.invoke('select-file-or-directory'), + startPowerSaveBlocker: () => ipcRenderer.invoke('start-power-save-blocker'), + stopPowerSaveBlocker: () => ipcRenderer.invoke('stop-power-save-blocker'), + getBinaryPath: (binaryName: string) => ipcRenderer.invoke('get-binary-path', binaryName), + on: (channel: string, callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void) => { + ipcRenderer.on(channel, callback); + }, + off: (channel: string, callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void) => { + ipcRenderer.off(channel, callback); + }, +}; + +const appConfigAPI: AppConfigAPI = { + get: (key: string) => config[key], + getAll: () => config, +}; + +// Expose the APIs +contextBridge.exposeInMainWorld('electron', electronAPI); +contextBridge.exposeInMainWorld('appConfig', appConfigAPI); + +// Type declaration for TypeScript +declare global { + interface Window { + electron: ElectronAPI; + appConfig: AppConfigAPI; + } +} diff --git a/ui/desktop/src/types/electron.d.ts b/ui/desktop/src/types/electron.d.ts deleted file mode 100644 index ef2a79d6f2..0000000000 --- a/ui/desktop/src/types/electron.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -interface IElectronAPI { - hideWindow: () => void; - createChatWindow: (query?: string, dir?: string, version?: string) => void; - getConfig: () => { - GOOSE_SERVER__PORT: number; - GOOSE_API_HOST: string; - apiCredsMissing: boolean; - secretKey: string; - }; - directoryChooser: () => void; -} - -declare global { - interface Window { - electron: IElectronAPI; - } -}