import { contextBridge, ipcRenderer, shell } from 'electron' import { IPC_CHANNELS } from '../shared/ipc-channels' import type { ElectronAPI } from '../renderer/types/ipc' // C-02: 运行时实现受 ElectronAPI 类型约束,编译期保证 preload 与渲染进程契约一致 const api: ElectronAPI = { // File operations openFile: () => ipcRenderer.invoke(IPC_CHANNELS.DIALOG_OPEN_FILE), readFile: (filePath: string) => ipcRenderer.invoke(IPC_CHANNELS.FILE_READ, filePath), saveFile: (data) => ipcRenderer.invoke(IPC_CHANNELS.FILE_SAVE, data), saveFileAs: (data) => ipcRenderer.invoke(IPC_CHANNELS.FILE_SAVE_AS, data), getCurrentPath: () => ipcRenderer.invoke(IPC_CHANNELS.FILE_GET_CURRENT_PATH), getFileStats: (filePath: string) => ipcRenderer.invoke(IPC_CHANNELS.FILE_STATS, filePath), reloadFile: () => ipcRenderer.invoke(IPC_CHANNELS.FILE_RELOAD), // Tab management tabSwitched: (filePath: string | null) => ipcRenderer.invoke(IPC_CHANNELS.TAB_SWITCHED, filePath), // Window control forceClose: () => ipcRenderer.invoke(IPC_CHANNELS.WINDOW_FORCE_CLOSE), cancelClose: () => ipcRenderer.invoke(IPC_CHANNELS.WINDOW_CANCEL_CLOSE), // Shell — 仅允许 http/https 协议 openExternal: (url: string) => { try { const parsed = new URL(url) if (parsed.protocol === 'http:' || parsed.protocol === 'https:') { shell.openExternal(url) } } catch { // 无效 URL,忽略 } }, // File Tree (Sidebar) readDirTree: (dirPath: string) => ipcRenderer.invoke(IPC_CHANNELS.DIR_READ_TREE, dirPath), openFolderDialog: () => ipcRenderer.invoke(IPC_CHANNELS.DIR_OPEN_DIALOG), watchDir: (dirPath: string) => ipcRenderer.invoke(IPC_CHANNELS.DIR_WATCH, dirPath), unwatchDir: () => ipcRenderer.invoke(IPC_CHANNELS.DIR_UNWATCH), // Events from main process — 返回取消订阅函数 onFileOpenInTab: (callback) => { const handler = (_event: Electron.IpcRendererEvent, data: { filePath: string; content: string }) => callback(data) ipcRenderer.on(IPC_CHANNELS.FILE_OPEN_IN_TAB, handler) return () => { ipcRenderer.removeListener(IPC_CHANNELS.FILE_OPEN_IN_TAB, handler) } }, onExternalModification: (callback) => { const handler = (_event: Electron.IpcRendererEvent, filePath: string) => callback(filePath) ipcRenderer.on(IPC_CHANNELS.FILE_EXTERNALLY_MODIFIED, handler) return () => { ipcRenderer.removeListener(IPC_CHANNELS.FILE_EXTERNALLY_MODIFIED, handler) } }, onDirChanged: (callback) => { const handler = () => callback() ipcRenderer.on(IPC_CHANNELS.SIDEBAR_DIR_CHANGED, handler) return () => { ipcRenderer.removeListener(IPC_CHANNELS.SIDEBAR_DIR_CHANGED, handler) } }, onConfirmClose: (callback) => { const handler = () => callback() ipcRenderer.on(IPC_CHANNELS.WINDOW_CONFIRM_CLOSE, handler) return () => { ipcRenderer.removeListener(IPC_CHANNELS.WINDOW_CONFIRM_CLOSE, handler) } } } contextBridge.exposeInMainWorld('electronAPI', api)