From fe96e197d3bcb4f6108ec0fdaf751fa85753b1d0 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 7 Sep 2026 07:49:30 +0800 Subject: [PATCH] =?UTF-8?q?pi-ele=20Phase=202:=20token/API=20=E5=9F=BA?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E6=B3=A8=E5=85=A5=20=E2=80=94=E2=80=94=20web?= =?UTF-8?q?/src=20=E9=9B=B6=E6=94=B9=E5=8A=A8=E6=88=90=E4=B8=BA=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=E6=A1=8C=E9=9D=A2=E5=AE=A2=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - main.cjs: 从 env 读 AGENTMAIL_GATEWAY_URL / AGENTMAIL_TOKEN(USER_KEY), 通过 additionalArguments 传给 preload;API_BASE = /api/v1 - preload.cjs: 从 process.argv 读注入参数,contextBridge 暴露 window.__AGENTMAIL_API_BASE__ / __AGENTMAIL_TOKEN__ → web/src 的 config.ts 自动读取,client.ts/sse.ts 零改动 - 效果:Electron 启动后 api.me() 带 Bearer 返回用户,直接进入主界面 (无登录页),收件箱等功能立即可用 验证(xvfb headless): - 注入链路:渲染进程拿到 apiBase=192.168.2.60:8180 + token ✅ - 端到端:gui-lab key 注入 → 界面呈现 收件/授权/发件/日历/联系 导航 + 空收件箱, 无登录表单(inputCount=0, hasLogin=false)✅ --- web/electron/main.cjs | 20 ++++++++++++++++---- web/electron/preload.cjs | 12 ++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/web/electron/main.cjs b/web/electron/main.cjs index 64a1021..a934bc9 100644 --- a/web/electron/main.cjs +++ b/web/electron/main.cjs @@ -2,9 +2,10 @@ * AgentMail Electron 主进程。 * * 职责: - * - 创建 BrowserWindow 加载前端(dev=http://localhost:5173,prod=../dist/index.html) - * - 系统托盘(Phase 4 完整实现,这里先预留) - * - SSE 长连接由主进程维持(Phase 2),这里先只做窗口生命周期 + * - 创建 BrowserWindow 加载前端(dev=<ELECTRON_START_URL>,prod=../dist/index.html) + * - 系统托盘(Phase 4 完整实现) + * - 离线缓存(Phase 4) + * - 把 Gateway 地址与用户密钥注入渲染进程(Phase 2:让 web/src 以独立客户端身份连任意 Gateway) * * 设计约束: * - 渲染进程复用 web/src 的 React 代码,零改动 @@ -18,11 +19,21 @@ const path = require('node:path'); const DEV_URL = process.env.ELECTRON_START_URL || 'http://localhost:5173'; const isDev = !!process.env.ELECTRON_START_URL || !app.isPackaged; +// Gateway 地址与用户密钥:环境变量注入(桌面客户端用 user_key 认证) +const GATEWAY_URL = (process.env.AGENTMAIL_GATEWAY_URL || 'http://127.0.0.1:8180').replace(/\/+$/, ''); +const API_BASE = `${GATEWAY_URL}/api/v1`; +const TOKEN = process.env.AGENTMAIL_TOKEN || process.env.AGENTMAIL_USER_KEY || ''; + let mainWindow = null; let tray = null; /** 创建主窗口 */ function createMainWindow() { + // 通过 additionalArguments 把 API 基地址与 token 传给 preload(preload 从 renderer 的 process.argv 末尾读) + // 传入的是透传 arg,用户页面不能直接改,preload 能读到 + const injectArgs = [`--agentmail-api-base=${API_BASE}`]; + if (TOKEN) injectArgs.push(`--agentmail-token=${TOKEN}`); + mainWindow = new BrowserWindow({ width: 1280, height: 800, @@ -31,10 +42,11 @@ function createMainWindow() { title: 'AgentMail', icon: path.join(__dirname, '..', 'src', 'icons', 'tray-icon.png'), webPreferences: { - preload: path.join(__dirname, 'preload.js'), + preload: path.join(__dirname, 'preload.cjs'), contextIsolation: true, nodeIntegration: false, sandbox: true, + additionalArguments: injectArgs, }, }); diff --git a/web/electron/preload.cjs b/web/electron/preload.cjs index d245a20..d9967b3 100644 --- a/web/electron/preload.cjs +++ b/web/electron/preload.cjs @@ -9,6 +9,18 @@ const { contextBridge, ipcRenderer } = require('electron'); +// 注入 API 基地址与 token:渲染进程的 config.ts 在读 window.__AGENTMAIL_API_BASE__ +// 与 __AGENTMAIL_TOKEN__ 时拿到它们,于是现有 client.ts/sse.ts **零改动**复用。 +// 这两个值由主进程在创建窗口时通过附加参数传进来(见 main.cjs 的 additionalArguments)。 +function getInjected(name) { + const prefix = `--agentmail-${name}=`; + const arg = process.argv.find(a => a.startsWith(prefix)); + return arg ? arg.slice(prefix.length) : undefined; +} + +contextBridge.exposeInMainWorld('__AGENTMAIL_API_BASE__', getInjected('api-base') || 'http://127.0.0.1:8180/api/v1'); +contextBridge.exposeInMainWorld('__AGENTMAIL_TOKEN__', getInjected('token') || undefined); + contextBridge.exposeInMainWorld('agentmail', { /** Gateway 基础地址(主进程 env 或默认 127.0.0.1:8180) */ gatewayUrl: () => ipcRenderer.invoke('get-gateway-url'),