import type { IpcResult, FileResult, FileEntry, PdfOptions, DocxOptions, HtmlOptions, ExportResult, BatchItem, BatchOptions, BatchResult, } from '@/types/ipc'; type ChannelMissing = { code: 'CHANNEL_MISSING'; message: string }; function wrap(fn: () => Promise): Promise> { if (typeof window === 'undefined' || !window.electronAPI) { return Promise.resolve({ ok: false, error: { code: 'NO_BRIDGE', message: 'window.electronAPI is unavailable' }, }); } return fn().then( (data) => ({ ok: true as const, data }), (err: Error) => ({ ok: false as const, error: { code: err.name || 'IPC_ERROR', message: err.message || String(err) }, }), ); } function safeCall Promise>( channel: string, method: string, ...args: Parameters ): Promise> | ChannelMissing>> { if (typeof window === 'undefined' || !window.electronAPI) { return Promise.resolve({ ok: false, error: { code: 'NO_BRIDGE', message: 'window.electronAPI is unavailable' }, }); } const target = (window.electronAPI as any)[channel]?.[method]; if (!target) { return Promise.resolve({ ok: false, error: { code: 'CHANNEL_MISSING', message: `Missing channel: ${channel}.${method}` }, }); } if (typeof target !== 'function') { return Promise.resolve({ ok: false, error: { code: 'CHANNEL_MISSING', message: `Not a function: ${channel}.${method}` }, }); } return wrap(() => target(...args)); } export const ipc = { file: { open: (): Promise> => safeCall('file', 'open'), read: (path: string): Promise> => safeCall('file', 'read', path), write: (path: string, content: string): Promise> => safeCall('file', 'write', path, content), list: (dir: string): Promise> => safeCall('file', 'list', dir), onChange: (cb: (path: string) => void): (() => void) => { if (typeof window === 'undefined' || !window.electronAPI?.file?.onChange) { return () => {}; } return window.electronAPI.file.onChange(cb); }, }, export: { pdf: (opts: PdfOptions): Promise> => safeCall('export', 'pdf', opts), docx: (opts: DocxOptions): Promise> => safeCall('export', 'docx', opts), html: (opts: HtmlOptions): Promise> => safeCall('export', 'html', opts), batch: (items: BatchItem[], opts: BatchOptions): Promise> => safeCall('export', 'batch', items, opts), }, app: { getVersion: (): Promise> => safeCall('app', 'getVersion'), openExternal: (url: string): Promise> => safeCall('app', 'openExternal', url), showItemInFolder: (path: string): Promise> => safeCall('app', 'showItemInFolder', path), }, };