@lobehub/lobehub 2.0.0-next.164 → 2.0.0-next.166
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/desktop-feature-implementation.mdc +31 -34
- package/.cursor/rules/desktop-local-tools-implement.mdc +3 -3
- package/.cursor/rules/desktop-window-management.mdc +56 -66
- package/CHANGELOG.md +50 -0
- package/Dockerfile +44 -52
- package/README.md +6 -6
- package/README.zh-CN.md +6 -6
- package/apps/desktop/Development.md +42 -46
- package/apps/desktop/README.md +37 -1
- package/apps/desktop/README.zh-CN.md +26 -1
- package/apps/desktop/electron.vite.config.ts +1 -0
- package/apps/desktop/src/main/controllers/AuthCtr.ts +4 -3
- package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +33 -20
- package/apps/desktop/src/main/controllers/DevtoolsCtr.ts +4 -2
- package/apps/desktop/src/main/controllers/LocalFileCtr.ts +14 -13
- package/apps/desktop/src/main/controllers/MenuCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/NetworkProxyCtr.ts +18 -19
- package/apps/desktop/src/main/controllers/NotificationCtr.ts +4 -3
- package/apps/desktop/src/main/controllers/RemoteServerConfigCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/RemoteServerSyncCtr.ts +3 -2
- package/apps/desktop/src/main/controllers/ShellCommandCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/ShortcutCtr.ts +4 -3
- package/apps/desktop/src/main/controllers/SystemCtr.ts +7 -37
- package/apps/desktop/src/main/controllers/SystemServerCtr.ts +38 -0
- package/apps/desktop/src/main/controllers/TrayMenuCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/UpdaterCtr.ts +6 -5
- package/apps/desktop/src/main/controllers/UploadFileCtr.ts +3 -25
- package/apps/desktop/src/main/controllers/UploadFileServerCtr.ts +33 -0
- package/apps/desktop/src/main/controllers/__tests__/AuthCtr.test.ts +9 -1
- package/apps/desktop/src/main/controllers/__tests__/BrowserWindowsCtr.test.ts +29 -9
- package/apps/desktop/src/main/controllers/__tests__/DevtoolsCtr.test.ts +12 -3
- package/apps/desktop/src/main/controllers/__tests__/LocalFileCtr.test.ts +7 -0
- package/apps/desktop/src/main/controllers/__tests__/MenuCtr.test.ts +10 -0
- package/apps/desktop/src/main/controllers/__tests__/NetworkProxyCtr.test.ts +10 -0
- package/apps/desktop/src/main/controllers/__tests__/NotificationCtr.test.ts +8 -0
- package/apps/desktop/src/main/controllers/__tests__/RemoteServerConfigCtr.test.ts +8 -0
- package/apps/desktop/src/main/controllers/__tests__/RemoteServerSyncCtr.test.ts +1 -0
- package/apps/desktop/src/main/controllers/__tests__/ShellCommandCtr.test.ts +10 -0
- package/apps/desktop/src/main/controllers/__tests__/ShortcutCtr.test.ts +11 -0
- package/apps/desktop/src/main/controllers/__tests__/SystemCtr.test.ts +43 -73
- package/apps/desktop/src/main/controllers/__tests__/SystemServerCtr.test.ts +75 -0
- package/apps/desktop/src/main/controllers/__tests__/TrayMenuCtr.test.ts +24 -13
- package/apps/desktop/src/main/controllers/__tests__/UpdaterCtr.test.ts +13 -2
- package/apps/desktop/src/main/controllers/__tests__/UploadFileCtr.test.ts +29 -108
- package/apps/desktop/src/main/controllers/__tests__/UploadFileServerCtr.test.ts +55 -0
- package/apps/desktop/src/main/controllers/_template.ts +2 -2
- package/apps/desktop/src/main/controllers/index.ts +5 -29
- package/apps/desktop/src/main/controllers/registry.ts +52 -0
- package/apps/desktop/src/main/core/App.ts +15 -47
- package/apps/desktop/src/main/core/__tests__/App.test.ts +5 -4
- package/apps/desktop/src/main/core/infrastructure/IoCContainer.ts +0 -5
- package/apps/desktop/src/main/core/infrastructure/__tests__/IoCContainer.test.ts +0 -50
- package/apps/desktop/src/main/exports.d.ts +8 -0
- package/apps/desktop/src/main/exports.ts +2 -0
- package/apps/desktop/src/main/global.d.ts +3 -0
- package/apps/desktop/src/main/modules/fileSearch/__tests__/macOS.integration.test.ts +17 -8
- package/apps/desktop/src/main/package.json +10 -0
- package/apps/desktop/src/main/services/fileSrv.ts +1 -1
- package/apps/desktop/src/main/utils/ipc/__tests__/base.test.ts +91 -0
- package/apps/desktop/src/main/utils/ipc/base.ts +170 -0
- package/apps/desktop/src/main/utils/ipc/index.ts +11 -0
- package/apps/desktop/src/main/utils/ipc/utility.ts +20 -0
- package/apps/desktop/src/preload/electronApi.ts +4 -1
- package/apps/desktop/src/preload/invoke.test.ts +13 -16
- package/apps/desktop/src/preload/invoke.ts +2 -5
- package/apps/desktop/src/preload/routeInterceptor.test.ts +13 -13
- package/apps/desktop/src/preload/routeInterceptor.ts +4 -4
- package/apps/desktop/tsconfig.json +15 -5
- package/changelog/v1.json +10 -0
- package/package.json +4 -3
- package/packages/electron-client-ipc/src/index.ts +1 -1
- package/packages/electron-client-ipc/src/ipc.test.ts +62 -0
- package/packages/electron-client-ipc/src/ipc.ts +63 -0
- package/packages/electron-client-ipc/src/streamInvoke.ts +7 -1
- package/packages/electron-client-ipc/src/types/dispatch.ts +1 -10
- package/packages/electron-client-ipc/vitest.config.mts +10 -0
- package/packages/electron-server-ipc/src/ipcClient.ts +1 -2
- package/packages/electron-server-ipc/src/ipcServer.ts +1 -2
- package/packages/electron-server-ipc/src/types/index.ts +1 -5
- package/pnpm-workspace.yaml +1 -1
- package/scripts/i18nWorkflow/const.ts +2 -2
- package/scripts/i18nWorkflow/i18nConfig.ts +7 -0
- package/scripts/i18nWorkflow/utils.ts +1 -1
- package/src/app/[variants]/(main)/discover/(detail)/provider/features/Sidebar/ActionButton/ProviderConfig.tsx +2 -2
- package/src/locales/default/setting.ts +1 -0
- package/src/server/modules/ElectronIPCClient/index.ts +59 -13
- package/src/services/electron/__tests__/devtools.test.ts +10 -6
- package/src/services/electron/autoUpdate.ts +5 -5
- package/src/services/electron/desktopNotification.ts +4 -7
- package/src/services/electron/devtools.ts +2 -2
- package/src/services/electron/file.ts +3 -2
- package/src/services/electron/localFileService.ts +17 -16
- package/src/services/electron/remoteServer.ts +7 -6
- package/src/services/electron/settings.ts +9 -11
- package/src/services/electron/system.ts +8 -6
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +1 -1
- package/src/store/global/actions/general.ts +8 -10
- package/src/utils/electron/desktopRemoteRPCFetch.ts +3 -2
- package/src/utils/electron/ipc.ts +12 -0
- package/tsconfig.json +5 -0
- package/apps/desktop/src/main/types/ipcClientEvent.ts +0 -3
- package/packages/electron-client-ipc/src/dispatch.ts +0 -41
|
@@ -36,13 +36,13 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
36
36
|
1. **创建控制器 (Controller)**
|
|
37
37
|
- 位置:`apps/desktop/src/main/controllers/`
|
|
38
38
|
- 示例:创建 `NewFeatureCtr.ts`
|
|
39
|
-
-
|
|
40
|
-
-
|
|
39
|
+
- 需继承 `ControllerModule`,并设置 `static readonly groupName`(例如 `static override readonly groupName = 'newFeature';`)
|
|
40
|
+
- 按 `_template.ts` 模板格式实现,并在 `apps/desktop/src/main/controllers/registry.ts` 的 `controllerIpcConstructors`(或 `controllerServerIpcConstructors`)中注册,保证类型推导与自动装配
|
|
41
41
|
|
|
42
42
|
2. **定义 IPC 事件处理器**
|
|
43
|
-
- 使用 `@
|
|
44
|
-
-
|
|
45
|
-
-
|
|
43
|
+
- 使用 `@IpcMethod()` 装饰器暴露渲染进程可访问的通道,或使用 `@IpcServerMethod()` 声明仅供 Next.js 服务器调用的 IPC
|
|
44
|
+
- 通道名称基于 `groupName.methodName` 自动生成,不再手动拼接字符串
|
|
45
|
+
- 处理函数可通过 `getIpcContext()` 获取 `sender`、`event` 等上下文信息,并按照需要返回结构化结果
|
|
46
46
|
|
|
47
47
|
3. **实现业务逻辑**
|
|
48
48
|
- 可能需要调用 Electron API 或 Node.js 原生模块
|
|
@@ -60,15 +60,17 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
60
60
|
1. **创建服务层**
|
|
61
61
|
- 位置:`src/services/electron/`
|
|
62
62
|
- 添加服务方法调用 IPC
|
|
63
|
-
- 使用 `
|
|
63
|
+
- 使用 `ensureElectronIpc()` 生成的类型安全代理,避免手动拼通道名称
|
|
64
64
|
|
|
65
65
|
```typescript
|
|
66
66
|
// src/services/electron/newFeatureService.ts
|
|
67
|
-
import {
|
|
68
|
-
import { NewFeatureParams } from '
|
|
67
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
68
|
+
import type { NewFeatureParams } from '@lobechat/electron-client-ipc';
|
|
69
|
+
|
|
70
|
+
const ipc = ensureElectronIpc();
|
|
69
71
|
|
|
70
72
|
export const newFeatureService = async (params: NewFeatureParams) => {
|
|
71
|
-
return
|
|
73
|
+
return ipc.newFeature.doSomething(params);
|
|
72
74
|
};
|
|
73
75
|
```
|
|
74
76
|
|
|
@@ -118,36 +120,31 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
|
|
|
118
120
|
|
|
119
121
|
```typescript
|
|
120
122
|
// apps/desktop/src/main/controllers/NotificationCtr.ts
|
|
121
|
-
import {
|
|
122
|
-
import {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
import { Notification } from 'electron';
|
|
124
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
125
|
+
import type {
|
|
126
|
+
DesktopNotificationResult,
|
|
127
|
+
ShowDesktopNotificationParams,
|
|
128
|
+
} from '@lobechat/electron-client-ipc';
|
|
129
|
+
|
|
130
|
+
export default class NotificationCtr extends ControllerModule {
|
|
131
|
+
static override readonly groupName = 'notification';
|
|
132
|
+
|
|
133
|
+
@IpcMethod()
|
|
134
|
+
async showDesktopNotification(
|
|
135
|
+
params: ShowDesktopNotificationParams,
|
|
136
|
+
): Promise<DesktopNotificationResult> {
|
|
137
|
+
if (!Notification.isSupported()) {
|
|
138
|
+
return { error: 'Notifications not supported', success: false };
|
|
139
|
+
}
|
|
128
140
|
|
|
129
|
-
export class NotificationCtr {
|
|
130
|
-
@ipcClientEvent('showNotification')
|
|
131
|
-
async handleShowNotification({ title, body }: ShowNotificationParams) {
|
|
132
141
|
try {
|
|
133
|
-
|
|
134
|
-
return { success: false, error: 'Notifications not supported' };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const notification = new Notification({
|
|
138
|
-
title,
|
|
139
|
-
body,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
+
const notification = new Notification({ body: params.body, title: params.title });
|
|
142
143
|
notification.show();
|
|
143
|
-
|
|
144
144
|
return { success: true };
|
|
145
145
|
} catch (error) {
|
|
146
|
-
console.error('Failed to show notification:', error);
|
|
147
|
-
return {
|
|
148
|
-
success: false,
|
|
149
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
150
|
-
};
|
|
146
|
+
console.error('[NotificationCtr] Failed to show notification:', error);
|
|
147
|
+
return { error: error instanceof Error ? error.message : 'Unknown error', success: false };
|
|
151
148
|
}
|
|
152
149
|
}
|
|
153
150
|
}
|
|
@@ -51,15 +51,15 @@ alwaysApply: false
|
|
|
51
51
|
* 导入在步骤 2 中定义的 IPC 参数类型。
|
|
52
52
|
* 添加一个新的 `async` 方法,方法名通常与 Action 名称对应 (例如: `renameLocalFile`)。
|
|
53
53
|
* 方法接收 `params` (符合 IPC 参数类型)。
|
|
54
|
-
*
|
|
54
|
+
* 通过 `ensureElectronIpc()` 获取 IPC 代理 (`const ipc = ensureElectronIpc();`),调用与 Manifest 中 `name` 字段匹配的链式方法,并将 `params` 传递过去。
|
|
55
55
|
* 定义方法的返回类型,通常是 `Promise<{ success: boolean; error?: string }>`,与后端 Controller 返回的结构一致。
|
|
56
56
|
|
|
57
57
|
5. **实现后端逻辑 (Controller / IPC Handler):**
|
|
58
58
|
* **文件:** `apps/desktop/src/main/controllers/[ToolName]Ctr.ts` (例如: `apps/desktop/src/main/controllers/LocalFileCtr.ts`)
|
|
59
59
|
* **操作:**
|
|
60
|
-
* 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`
|
|
60
|
+
* 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`ControllerModule`, `IpcMethod`/`IpcServerMethod`、参数类型等)。
|
|
61
61
|
* 添加一个新的 `async` 方法,方法名通常以 `handle` 开头 (例如: `handleRenameFile`)。
|
|
62
|
-
* 使用 `@
|
|
62
|
+
* 使用 `@IpcMethod()` 或 `@IpcServerMethod()` 装饰器将此方法注册为对应 IPC 事件的处理器,确保方法名与 Manifest 中的 `name` 以及 Service 层的链式调用一致。
|
|
63
63
|
* 方法的参数应解构自 Service 层传递过来的对象,类型与步骤 2 中定义的 IPC 参数类型匹配。
|
|
64
64
|
* 实现核心业务逻辑:
|
|
65
65
|
* 进行必要的输入验证。
|
|
@@ -149,50 +149,52 @@ export const createMainWindow = () => {
|
|
|
149
149
|
|
|
150
150
|
1. **在主进程中注册 IPC 处理器**
|
|
151
151
|
```typescript
|
|
152
|
-
// BrowserWindowsCtr.ts
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
|
|
153
|
+
import { BrowserWindow } from 'electron';
|
|
154
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
155
|
+
|
|
156
|
+
export default class BrowserWindowsCtr extends ControllerModule {
|
|
157
|
+
static override readonly groupName = 'windows';
|
|
158
|
+
|
|
159
|
+
@IpcMethod()
|
|
160
|
+
minimizeWindow() {
|
|
161
|
+
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
162
|
+
focusedWindow?.minimize();
|
|
163
|
+
return { success: true };
|
|
158
164
|
}
|
|
159
|
-
return { success: true };
|
|
160
|
-
}
|
|
161
165
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
} else {
|
|
169
|
-
focusedWindow.maximize();
|
|
170
|
-
}
|
|
166
|
+
@IpcMethod()
|
|
167
|
+
maximizeWindow() {
|
|
168
|
+
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
169
|
+
if (focusedWindow?.isMaximized()) focusedWindow.restore();
|
|
170
|
+
else focusedWindow?.maximize();
|
|
171
|
+
return { success: true };
|
|
171
172
|
}
|
|
172
|
-
return { success: true };
|
|
173
|
-
}
|
|
174
173
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
focusedWindow.close();
|
|
174
|
+
@IpcMethod()
|
|
175
|
+
closeWindow() {
|
|
176
|
+
BrowserWindow.getFocusedWindow()?.close();
|
|
177
|
+
return { success: true };
|
|
180
178
|
}
|
|
181
|
-
return { success: true };
|
|
182
179
|
}
|
|
183
180
|
```
|
|
181
|
+
- `@IpcMethod()` 根据控制器的 `groupName` 自动将方法映射为 `windows.minimizeWindow` 形式的通道名称。
|
|
182
|
+
- 控制器需继承 `ControllerModule`,并在 `controllers/registry.ts` 中通过 `controllerIpcConstructors` 注册,便于类型生成。
|
|
184
183
|
|
|
185
184
|
2. **在渲染进程中调用**
|
|
186
185
|
```typescript
|
|
187
186
|
// src/services/electron/windowService.ts
|
|
188
|
-
import {
|
|
187
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
188
|
+
|
|
189
|
+
const ipc = ensureElectronIpc();
|
|
189
190
|
|
|
190
191
|
export const windowService = {
|
|
191
|
-
minimize: () =>
|
|
192
|
-
maximize: () =>
|
|
193
|
-
close: () =>
|
|
192
|
+
minimize: () => ipc.windows.minimizeWindow(),
|
|
193
|
+
maximize: () => ipc.windows.maximizeWindow(),
|
|
194
|
+
close: () => ipc.windows.closeWindow(),
|
|
194
195
|
};
|
|
195
196
|
```
|
|
197
|
+
- `ensureElectronIpc()` 会基于 `DesktopIpcServices` 运行时生成 Proxy,并通过 `window.electronAPI.invoke` 与主进程通信;不再直接使用 `dispatch`。
|
|
196
198
|
|
|
197
199
|
### 5. 自定义窗口控制 (无边框窗口)
|
|
198
200
|
|
|
@@ -252,45 +254,33 @@ export const createMainWindow = () => {
|
|
|
252
254
|
|
|
253
255
|
```typescript
|
|
254
256
|
// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
|
|
257
|
+
import type { OpenSettingsWindowOptions } from '@lobechat/electron-client-ipc';
|
|
258
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
259
|
+
|
|
260
|
+
export default class BrowserWindowsCtr extends ControllerModule {
|
|
261
|
+
static override readonly groupName = 'windows';
|
|
262
|
+
|
|
263
|
+
@IpcMethod()
|
|
264
|
+
async openSettingsWindow(options?: string | OpenSettingsWindowOptions) {
|
|
265
|
+
const normalizedOptions =
|
|
266
|
+
typeof options === 'string' || options === undefined
|
|
267
|
+
? { tab: typeof options === 'string' ? options : undefined }
|
|
268
|
+
: options;
|
|
269
|
+
|
|
270
|
+
const mainWindow = this.app.browserManager.getMainWindow();
|
|
271
|
+
const query = new URLSearchParams();
|
|
272
|
+
if (normalizedOptions.tab) query.set('active', normalizedOptions.tab);
|
|
273
|
+
if (normalizedOptions.searchParams) {
|
|
274
|
+
for (const [key, value] of Object.entries(normalizedOptions.searchParams)) {
|
|
275
|
+
if (value) query.set(key, value);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const fullPath = `/settings${query.size ? `?${query.toString()}` : ''}`;
|
|
280
|
+
await mainWindow.loadUrl(fullPath);
|
|
281
|
+
mainWindow.show();
|
|
255
282
|
|
|
256
|
-
@ipcClientEvent('openSettings')
|
|
257
|
-
handleOpenSettings() {
|
|
258
|
-
// 检查设置窗口是否已经存在
|
|
259
|
-
if (this.settingsWindow && !this.settingsWindow.isDestroyed()) {
|
|
260
|
-
// 如果窗口已存在,将其置于前台
|
|
261
|
-
this.settingsWindow.focus();
|
|
262
283
|
return { success: true };
|
|
263
284
|
}
|
|
264
|
-
|
|
265
|
-
// 创建新窗口
|
|
266
|
-
this.settingsWindow = new BrowserWindow({
|
|
267
|
-
width: 800,
|
|
268
|
-
height: 600,
|
|
269
|
-
title: 'Settings',
|
|
270
|
-
parent: this.mainWindow, // 设置父窗口,使其成为模态窗口
|
|
271
|
-
modal: true,
|
|
272
|
-
webPreferences: {
|
|
273
|
-
preload: path.join(__dirname, '../preload/index.js'),
|
|
274
|
-
contextIsolation: true,
|
|
275
|
-
nodeIntegration: false,
|
|
276
|
-
},
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
// 加载设置页面
|
|
280
|
-
if (isDev) {
|
|
281
|
-
this.settingsWindow.loadURL('http://localhost:3000/settings');
|
|
282
|
-
} else {
|
|
283
|
-
this.settingsWindow.loadFile(
|
|
284
|
-
path.join(__dirname, '../../renderer/index.html'),
|
|
285
|
-
{ hash: 'settings' }
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// 监听窗口关闭事件
|
|
290
|
-
this.settingsWindow.on('closed', () => {
|
|
291
|
-
this.settingsWindow = null;
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
return { success: true };
|
|
295
285
|
}
|
|
296
286
|
```
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.166](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.165...v2.0.0-next.166)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-12-09**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **Dockerfile**: Electron main typing pkg.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **Dockerfile**: Electron main typing pkg, closes [#10693](https://github.com/lobehub/lobe-chat/issues/10693) ([f3357b0](https://github.com/lobehub/lobe-chat/commit/f3357b0))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 2.0.0-next.165](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.164...v2.0.0-next.165)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2025-12-09**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **electron-main**: Client ipc decorate.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **electron-main**: Client ipc decorate, closes [#10679](https://github.com/lobehub/lobe-chat/issues/10679) ([f74befa](https://github.com/lobehub/lobe-chat/commit/f74befa))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 2.0.0-next.164](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.163...v2.0.0-next.164)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2025-12-08**</sup>
|
package/Dockerfile
CHANGED
|
@@ -8,29 +8,24 @@ ARG USE_CN_MIRROR
|
|
|
8
8
|
|
|
9
9
|
ENV DEBIAN_FRONTEND="noninteractive"
|
|
10
10
|
|
|
11
|
-
RUN
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
&& cp /usr/local/bin/node /distroless/bin/node \
|
|
30
|
-
# Copy CA certificates to distroless
|
|
31
|
-
&& cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt \
|
|
32
|
-
# Cleanup temp files
|
|
33
|
-
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
|
11
|
+
RUN <<'EOF'
|
|
12
|
+
set -e
|
|
13
|
+
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then
|
|
14
|
+
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"
|
|
15
|
+
fi
|
|
16
|
+
apt update
|
|
17
|
+
apt install ca-certificates proxychains-ng -qy
|
|
18
|
+
mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib
|
|
19
|
+
cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4
|
|
20
|
+
cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2
|
|
21
|
+
cp /usr/bin/proxychains4 /distroless/bin/proxychains
|
|
22
|
+
cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf
|
|
23
|
+
cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6
|
|
24
|
+
cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1
|
|
25
|
+
cp /usr/local/bin/node /distroless/bin/node
|
|
26
|
+
cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt
|
|
27
|
+
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
|
28
|
+
EOF
|
|
34
29
|
|
|
35
30
|
## Builder image, install all the dependencies and build the app
|
|
36
31
|
FROM base AS builder
|
|
@@ -86,29 +81,26 @@ WORKDIR /app
|
|
|
86
81
|
COPY package.json pnpm-workspace.yaml ./
|
|
87
82
|
COPY .npmrc ./
|
|
88
83
|
COPY packages ./packages
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
&& cd /deps \
|
|
110
|
-
&& pnpm init \
|
|
111
|
-
&& pnpm add pg drizzle-orm
|
|
84
|
+
# bring in desktop workspace manifest so pnpm can resolve it
|
|
85
|
+
COPY apps/desktop/src/main/package.json ./apps/desktop/src/main/package.json
|
|
86
|
+
|
|
87
|
+
RUN <<'EOF'
|
|
88
|
+
set -e
|
|
89
|
+
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then
|
|
90
|
+
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"
|
|
91
|
+
npm config set registry "https://registry.npmmirror.com/"
|
|
92
|
+
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc
|
|
93
|
+
fi
|
|
94
|
+
export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//')
|
|
95
|
+
npm i -g corepack@latest
|
|
96
|
+
corepack enable
|
|
97
|
+
corepack use $(sed -n 's/.*"packageManager": "\(.*\)".*/\1/p' package.json)
|
|
98
|
+
pnpm i
|
|
99
|
+
mkdir -p /deps
|
|
100
|
+
cd /deps
|
|
101
|
+
pnpm init
|
|
102
|
+
pnpm add pg drizzle-orm
|
|
103
|
+
EOF
|
|
112
104
|
|
|
113
105
|
COPY . .
|
|
114
106
|
|
|
@@ -137,12 +129,12 @@ COPY --from=builder /deps/node_modules/drizzle-orm /app/node_modules/drizzle-orm
|
|
|
137
129
|
# Copy server launcher
|
|
138
130
|
COPY --from=builder /app/scripts/serverLauncher/startServer.js /app/startServer.js
|
|
139
131
|
|
|
140
|
-
RUN
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
132
|
+
RUN <<'EOF'
|
|
133
|
+
set -e
|
|
134
|
+
addgroup -S -g 1001 nodejs
|
|
135
|
+
adduser -D -G nodejs -H -S -h /app -u 1001 nextjs
|
|
136
|
+
chown -R nextjs:nodejs /app /etc/proxychains4.conf
|
|
137
|
+
EOF
|
|
146
138
|
|
|
147
139
|
## Production image, copy all the files and run next
|
|
148
140
|
FROM scratch
|
package/README.md
CHANGED
|
@@ -345,12 +345,12 @@ In addition, these plugins are not limited to news aggregation, but can also ext
|
|
|
345
345
|
|
|
346
346
|
<!-- PLUGIN LIST -->
|
|
347
347
|
|
|
348
|
-
| Recent Submits
|
|
349
|
-
|
|
|
350
|
-
| [
|
|
351
|
-
| [
|
|
352
|
-
| [
|
|
353
|
-
| [
|
|
348
|
+
| Recent Submits | Description |
|
|
349
|
+
| --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
350
|
+
| [AladinBooks](https://lobechat.com/discover/plugin/AladinSearchBooks)<br/><sup>By **azurewebsites** on **2025-12-08**</sup> | Search for books on Aladin.<br/>`book` `search` |
|
|
351
|
+
| [PortfolioMeta](https://lobechat.com/discover/plugin/StockData)<br/><sup>By **portfoliometa** on **2025-11-28**</sup> | Analyze stocks and get comprehensive real-time investment data and analytics.<br/>`stock` |
|
|
352
|
+
| [SEO](https://lobechat.com/discover/plugin/SEO)<br/><sup>By **orrenprunckun** on **2025-11-14**</sup> | Enter any URL and keyword and get an On-Page SEO analysis & insights!<br/>`seo` |
|
|
353
|
+
| [Shopping tools](https://lobechat.com/discover/plugin/ShoppingTools)<br/><sup>By **shoppingtools** on **2025-10-27**</sup> | Search for products on eBay & AliExpress, find eBay events & coupons. Get prompt examples.<br/>`shopping` `e-bay` `ali-express` `coupons` |
|
|
354
354
|
|
|
355
355
|
> 📊 Total plugins: [<kbd>**41**</kbd>](https://lobechat.com/discover/plugins)
|
|
356
356
|
|
package/README.zh-CN.md
CHANGED
|
@@ -338,12 +338,12 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
338
338
|
|
|
339
339
|
<!-- PLUGIN LIST -->
|
|
340
340
|
|
|
341
|
-
| 最近新增
|
|
342
|
-
|
|
|
343
|
-
| [
|
|
344
|
-
| [
|
|
345
|
-
| [
|
|
346
|
-
| [
|
|
341
|
+
| 最近新增 | 描述 |
|
|
342
|
+
| --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
343
|
+
| [AladinBooks](https://lobechat.com/discover/plugin/AladinSearchBooks)<br/><sup>By **azurewebsites** on **2025-12-08**</sup> | 在阿拉丁上搜索书籍。<br/>`书籍` `搜索` |
|
|
344
|
+
| [PortfolioMeta](https://lobechat.com/discover/plugin/StockData)<br/><sup>By **portfoliometa** on **2025-11-28**</sup> | 分析股票并获取全面的实时投资数据和分析。<br/>`股票` |
|
|
345
|
+
| [SEO](https://lobechat.com/discover/plugin/SEO)<br/><sup>By **orrenprunckun** on **2025-11-14**</sup> | 输入任何 URL 和关键词,获取页面 SEO 分析和见解!<br/>`seo` |
|
|
346
|
+
| [购物工具](https://lobechat.com/discover/plugin/ShoppingTools)<br/><sup>By **shoppingtools** on **2025-10-27**</sup> | 在 eBay 和 AliExpress 上搜索产品,查找 eBay 活动和优惠券。获取快速示例。<br/>`购物` `e-bay` `ali-express` `优惠券` |
|
|
347
347
|
|
|
348
348
|
> 📊 Total plugins: [<kbd>**41**</kbd>](https://lobechat.com/discover/plugins)
|
|
349
349
|
|
|
@@ -156,24 +156,26 @@ apps/desktop/src/main/
|
|
|
156
156
|
- 事件广播:向渲染进程通知授权状态变化
|
|
157
157
|
|
|
158
158
|
```typescript
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
159
|
+
import { ControllerModule, IpcMethod } from '@/controllers';
|
|
160
|
+
|
|
161
|
+
export default class AuthCtr extends ControllerModule {
|
|
162
|
+
static override groupName = 'auth';
|
|
163
|
+
|
|
164
|
+
@IpcMethod()
|
|
165
|
+
async requestAuthorization(config: DataSyncConfig) {
|
|
166
|
+
this.authRequestState = crypto.randomBytes(16).toString('hex');
|
|
167
|
+
|
|
168
|
+
const authUrl = new URL('/oidc/auth', remoteUrl);
|
|
169
|
+
authUrl.search = querystring.stringify({
|
|
170
|
+
client_id: 'lobe-chat',
|
|
171
|
+
redirect_uri: `${protocolPrefix}://auth/callback`,
|
|
172
|
+
response_type: 'code',
|
|
173
|
+
scope: 'openid profile',
|
|
174
|
+
state: this.authRequestState,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await shell.openExternal(authUrl.toString());
|
|
178
|
+
}
|
|
177
179
|
}
|
|
178
180
|
```
|
|
179
181
|
|
|
@@ -267,20 +269,27 @@ export class ShortcutManager {
|
|
|
267
269
|
- 注入 App 实例
|
|
268
270
|
|
|
269
271
|
```typescript
|
|
270
|
-
|
|
272
|
+
import { ControllerModule, IpcMethod, IpcServerMethod } from '@/controllers'
|
|
273
|
+
|
|
271
274
|
export class ControllerModule implements IControllerModule {
|
|
272
275
|
constructor(public app: App) {
|
|
273
|
-
this.app = app
|
|
276
|
+
this.app = app
|
|
274
277
|
}
|
|
275
278
|
}
|
|
276
279
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
+
export class BrowserWindowsCtr extends ControllerModule {
|
|
281
|
+
static override readonly groupName = 'windows' // must be readonly
|
|
282
|
+
|
|
283
|
+
@IpcMethod()
|
|
284
|
+
openSettingsWindow(params?: OpenSettingsWindowOptions) {
|
|
285
|
+
// ...
|
|
286
|
+
}
|
|
280
287
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
288
|
+
@IpcServerMethod()
|
|
289
|
+
handleServerCommand(payload: any) {
|
|
290
|
+
// ...
|
|
291
|
+
}
|
|
292
|
+
}
|
|
284
293
|
```
|
|
285
294
|
|
|
286
295
|
2. **IoC 容器**:
|
|
@@ -346,26 +355,13 @@ makeSureDirExist(storagePath);
|
|
|
346
355
|
- 自动映射控制器方法到 IPC 事件
|
|
347
356
|
|
|
348
357
|
```typescript
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
// 注册服务器事件处理程序
|
|
359
|
-
const ipcServerEvents = {} as ElectronIPCEventHandler;
|
|
360
|
-
this.ipcServerEventMap.forEach((eventInfo, key) => {
|
|
361
|
-
ipcServerEvents[key] = async (payload) => {
|
|
362
|
-
return await eventInfo.controller[eventInfo.methodName](payload);
|
|
363
|
-
};
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// 创建 IPC 服务器
|
|
367
|
-
this.ipcServer = new ElectronIPCServer(name, ipcServerEvents);
|
|
368
|
-
}
|
|
358
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
359
|
+
|
|
360
|
+
// 渲染进程中使用 type-safe proxy 调用主进程方法
|
|
361
|
+
const ipc = ensureElectronIpc();
|
|
362
|
+
|
|
363
|
+
await ipc.localSystem.readLocalFile({ path });
|
|
364
|
+
await ipc.system.updateLocale('en-US');
|
|
369
365
|
```
|
|
370
366
|
|
|
371
367
|
2. **事件广播**:
|