/** * Electron Preload 脚本 * * 这是渲染进程和主进程之间的安全桥梁 * 通过 contextBridge 安全地暴露 API 给渲染进程 * * 安全说明: * - contextIsolation: true 确保渲染进程无法直接访问 Node.js API * - 所有暴露的方法都经过 IPC 通道与主进程通信 * - 不要在这里导入 electron-store 或其他 Node.js 模块 */ import { contextBridge, ipcRenderer } from 'electron' // IPC 通道名称(与 ipc.ts 保持一致) const IPC_CHANNELS = { SAVE_FILE: 'file:save', READ_FILE: 'file:read', GET_SETTINGS: 'settings:get', SAVE_SETTINGS: 'settings:save', // 缓存操作 CACHE_SET_JSON: 'cache:setJSON', CACHE_GET_JSON: 'cache:getJSON', CACHE_SET_BINARY: 'cache:setBinary', CACHE_GET_BINARY: 'cache:getBinary', CACHE_HAS: 'cache:has', CACHE_DELETE: 'cache:delete', CACHE_CLEAR_NAMESPACE: 'cache:clearNamespace', CACHE_CLEAR_ALL: 'cache:clearAll', CACHE_GET_STATS: 'cache:getStats', // 窗口操作 WINDOW_MINIMIZE: 'window:minimize', WINDOW_MAXIMIZE: 'window:maximize', WINDOW_CLOSE: 'window:close', // Git/System 操作 DIALOG_OPEN_DIRECTORY: 'dialog:openDirectory', GIT_CLONE: 'git:clone' } as const // API 响应类型定义 interface FileOperationResult { success: boolean message: string path?: string | null content?: string | null canceled?: boolean } interface GitOperationResult { success: boolean message: string stdout?: string } interface SettingsOperationResult { success: boolean message?: string data?: unknown } interface CacheOperationResult { success: boolean message?: string data?: any exists?: boolean } interface WindowOperationResult { success: boolean message?: string isMaximized?: boolean } // 暴露给渲染进程的 API 接口 interface ElectronAPI { // 文件操作 file: { save: (content: string, filename?: string) => Promise read: (filename?: string) => Promise openDirectory: () => Promise } // Git 操作 git: { clone: (repoUrl: string, targetDir: string) => Promise onProgress: (callback: (data: { repoUrl: string; raw: string }) => void) => void removeListener: () => void } // 设置操作 settings: { get: (key?: string) => Promise save: (key: string, value: unknown) => Promise } // 缓存操作 cache: { setJSON: (key: string, data: any, config?: { maxAge?: number; namespace?: string }) => Promise getJSON: (key: string, config?: { maxAge?: number; namespace?: string }) => Promise setBinary: (key: string, buffer: Buffer, type?: 'binary' | 'image', config?: { maxAge?: number; namespace?: string }) => Promise getBinary: (key: string, config?: { maxAge?: number; namespace?: string }) => Promise has: (key: string, config?: { namespace?: string }) => Promise delete: (key: string, namespace?: string) => Promise clearNamespace: (namespace: string) => Promise clearAll: () => Promise getStats: () => Promise } // 窗口操作 window: { minimize: () => Promise maximize: () => Promise close: () => Promise } } // 通过 contextBridge 安全地暴露 API const electronAPI: ElectronAPI = { // ============================================ // 文件操作 API // ============================================ file: { /** * 保存文件到桌面 * @param content - 文件内容 * @param filename - 文件名(可选,默认为 demo-note.txt) */ save: (content: string, filename?: string) => { return ipcRenderer.invoke(IPC_CHANNELS.SAVE_FILE, content, filename) }, /** * 从桌面读取文件 * @param filename - 文件名(可选,默认为 demo-note.txt) */ read: (filename?: string) => { return ipcRenderer.invoke(IPC_CHANNELS.READ_FILE, filename) }, /** * 打开目录选择对话框 */ openDirectory: () => { return ipcRenderer.invoke(IPC_CHANNELS.DIALOG_OPEN_DIRECTORY) } }, // ============================================ // Git 操作 API // ============================================ git: { /** * 克隆 Git 仓库 * @param repoUrl - 仓库地址 * @param targetDir - 目标目录 */ clone: (repoUrl: string, targetDir: string) => { return ipcRenderer.invoke(IPC_CHANNELS.GIT_CLONE, repoUrl, targetDir) }, /** * 监听 Git 进度 */ onProgress: (callback: (data: { repoUrl: string; raw: string }) => void) => { // 移除旧的监听器以防止重复 (简化处理,实际应该支持多监听器或由调用者管理) ipcRenderer.removeAllListeners('git:progress') ipcRenderer.on('git:progress', (_event, data) => { callback(data) }) }, /** * 移除监听器 */ removeListener: () => { ipcRenderer.removeAllListeners('git:progress') } }, // ============================================ // 设置操作 API // ============================================ settings: { /** * 获取用户设置 * @param key - 设置键名(可选,不传返回所有设置) */ get: (key?: string) => { return ipcRenderer.invoke(IPC_CHANNELS.GET_SETTINGS, key) }, /** * 保存用户设置 * @param key - 设置键名 * @param value - 设置值 */ save: (key: string, value: unknown) => { return ipcRenderer.invoke(IPC_CHANNELS.SAVE_SETTINGS, key, value) } }, // ============================================ // 缓存操作 API // ============================================ cache: { /** * 设置JSON缓存 */ setJSON: (key: string, data: any, config?: { maxAge?: number; namespace?: string }) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_SET_JSON, key, data, config) }, /** * 获取JSON缓存 */ getJSON: (key: string, config?: { maxAge?: number; namespace?: string }) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_GET_JSON, key, config) }, /** * 设置二进制缓存 */ setBinary: (key: string, buffer: Buffer, type?: 'binary' | 'image', config?: { maxAge?: number; namespace?: string }) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_SET_BINARY, key, buffer, type, config) }, /** * 获取二进制缓存 */ getBinary: (key: string, config?: { maxAge?: number; namespace?: string }) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_GET_BINARY, key, config) }, /** * 检查缓存是否存在 */ has: (key: string, config?: { namespace?: string }) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_HAS, key, config) }, /** * 删除单个缓存 */ delete: (key: string, namespace?: string) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_DELETE, key, namespace) }, /** * 清空命名空间缓存 */ clearNamespace: (namespace: string) => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_CLEAR_NAMESPACE, namespace) }, /** * 清空所有缓存 */ clearAll: () => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_CLEAR_ALL) }, /** * 获取缓存统计信息 */ getStats: () => { return ipcRenderer.invoke(IPC_CHANNELS.CACHE_GET_STATS) } }, // ============================================ // 窗口操作 API // ============================================ window: { /** * 最小化窗口 */ minimize: () => { return ipcRenderer.invoke(IPC_CHANNELS.WINDOW_MINIMIZE) }, /** * 最大化/还原窗口 */ maximize: () => { return ipcRenderer.invoke(IPC_CHANNELS.WINDOW_MAXIMIZE) }, /** * 关闭窗口 */ close: () => { return ipcRenderer.invoke(IPC_CHANNELS.WINDOW_CLOSE) } } } // 暴露 API 到 window.electronAPI contextBridge.exposeInMainWorld('electronAPI', electronAPI) // TypeScript 类型声明(供渲染进程使用) declare global { interface Window { electronAPI: ElectronAPI } }