import { contextBridge, ipcRenderer } from 'electron' import type { ListDirResult, OpenFileResult, OpenFolderResult, OpenImageResult, SaveDialogResult } from './ipc-types.js' const bufferedOpenFiles: string[][] = [] let openFilesHandler: ((paths: string[]) => void) | null = null ipcRenderer.on('myreader:open-files', (_e, paths: string[]) => { if (openFilesHandler) { openFilesHandler(paths) } else { bufferedOpenFiles.push(paths) } }) export interface MyReaderApi { openFileDialog: () => Promise openFolderDialog: () => Promise openImageDialog: () => Promise saveFileDialog: (defaultPath?: string) => Promise readFile: (filePath: string) => Promise writeFile: (filePath: string, content: string) => Promise listDirectory: (dirPath: string) => Promise parentDirectory: (dirPath: string) => Promise resolveRelativePath: (baseFilePath: string, href: string) => Promise openExternal: (url: string) => Promise defaultDirectory: () => Promise deleteFile: (filePath: string) => Promise renamePath: (oldPath: string, newName: string) => Promise<{ newPath: string }> allowClose: () => void onRequestClose: (handler: () => void) => () => void onMenuAction: (handler: (action: string) => void) => () => void onOpenFiles: (handler: (paths: string[]) => void) => () => void getPendingFilesIPC: () => Promise } const api: MyReaderApi = { openFileDialog: () => ipcRenderer.invoke('myreader:open-file-dialog'), openFolderDialog: () => ipcRenderer.invoke('myreader:open-folder-dialog'), openImageDialog: () => ipcRenderer.invoke('myreader:open-image-dialog'), saveFileDialog: (defaultPath?: string) => ipcRenderer.invoke('myreader:save-dialog', defaultPath), readFile: (filePath: string) => ipcRenderer.invoke('myreader:read-file', filePath), writeFile: (filePath: string, content: string) => ipcRenderer.invoke('myreader:write-file', filePath, content), listDirectory: (dirPath: string) => ipcRenderer.invoke('myreader:list-directory', dirPath), parentDirectory: (dirPath: string) => ipcRenderer.invoke('myreader:parent-directory', dirPath), resolveRelativePath: (baseFilePath: string, href: string) => ipcRenderer.invoke('myreader:resolve-relative-path', baseFilePath, href), openExternal: (url: string) => ipcRenderer.invoke('myreader:open-external', url), defaultDirectory: () => ipcRenderer.invoke('myreader:default-directory'), deleteFile: (filePath: string) => ipcRenderer.invoke('myreader:delete-file', filePath), renamePath: (oldPath: string, newName: string) => ipcRenderer.invoke('myreader:rename-path', oldPath, newName), allowClose: () => { ipcRenderer.send('myreader:allow-close') }, onRequestClose: (handler: () => void) => { const listener = (): void => { handler() } ipcRenderer.on('myreader:request-close', listener) return () => { ipcRenderer.removeListener('myreader:request-close', listener) } }, onMenuAction: (handler: (action: string) => void) => { const listener = (_e: unknown, action: string): void => { handler(action) } ipcRenderer.on('myreader:menu', listener) return () => { ipcRenderer.removeListener('myreader:menu', listener) } }, onOpenFiles: (handler: (paths: string[]) => void) => { openFilesHandler = handler return () => { openFilesHandler = null } }, getPendingFilesIPC: async (): Promise => { const fromMain = await ipcRenderer.invoke('myreader:get-pending-files') const fromBuffer = bufferedOpenFiles.flat() bufferedOpenFiles.length = 0 const seen = new Set() const merged: string[] = [] for (const p of [...fromMain, ...fromBuffer]) { const key = p.replace(/\\/g, '/').toLowerCase() if (seen.has(key)) continue seen.add(key) merged.push(p) } return merged } } try { contextBridge.exposeInMainWorld('myreader', api) } catch (e) { console.error('[MyReader] preload contextBridge failed', e) }