// Preload — the thin bridge between renderer and main. // // Everything exposed here is visible in the renderer as `window.dchain`. // We explicitly pick which IPC channels to surface rather than exposing // `ipcRenderer` wholesale, so a compromised renderer can't spam // arbitrary channels. import { contextBridge, ipcRenderer } from 'electron'; interface OpenDialogOptions { title?: string; defaultPath?: string; filters?: { name: string; extensions: string[] }[]; properties?: ('openFile' | 'multiSelections')[]; } interface SaveDialogOptions { title?: string; defaultPath?: string; filters?: { name: string; extensions: string[] }[]; } const api = { keyfile: { load: (): Promise => ipcRenderer.invoke('keyfile:load'), save: (json: string): Promise => ipcRenderer.invoke('keyfile:save', json), delete: (): Promise => ipcRenderer.invoke('keyfile:delete'), encryptionAvailable: (): Promise => ipcRenderer.invoke('keyfile:encryption-available'), }, dialog: { openFile: (opts: OpenDialogOptions): Promise => ipcRenderer.invoke('dialog:open-file', opts), saveFile: (opts: SaveDialogOptions): Promise => ipcRenderer.invoke('dialog:save-file', opts), }, fs: { readText: (p: string): Promise => ipcRenderer.invoke('fs:read-text', p), writeText: (p: string, c: string): Promise => ipcRenderer.invoke('fs:write-text', p, c), }, app: { version: (): Promise => ipcRenderer.invoke('app:version'), platform: (): Promise => ipcRenderer.invoke('app:platform'), }, }; export type DChainAPI = typeof api; contextBridge.exposeInMainWorld('dchain', api);