@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
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-interface */
|
|
2
|
+
import type { DispatchInvoke } from './types/dispatch';
|
|
3
|
+
import type { ProxyTRPCRequestParams } from './types/proxyTRPCRequest';
|
|
4
|
+
|
|
5
|
+
interface StreamerCallbacks {
|
|
6
|
+
onData: (chunk: Uint8Array) => void;
|
|
7
|
+
onEnd: () => void;
|
|
8
|
+
onError: (error: Error) => void;
|
|
9
|
+
onResponse: (response: {
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
status: number;
|
|
12
|
+
statusText: string;
|
|
13
|
+
}) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DesktopIpcServicesMap {}
|
|
17
|
+
export type DesktopIpcServices = DesktopIpcServicesMap;
|
|
18
|
+
export type ElectronDesktopIpc = DesktopIpcServices | null;
|
|
19
|
+
|
|
20
|
+
const createInvokeProxy = <IpcServices>(invoke: DispatchInvoke): IpcServices =>
|
|
21
|
+
new Proxy(
|
|
22
|
+
{},
|
|
23
|
+
{
|
|
24
|
+
get(_target, groupKey) {
|
|
25
|
+
if (typeof groupKey !== 'string') return undefined;
|
|
26
|
+
|
|
27
|
+
return new Proxy(
|
|
28
|
+
{},
|
|
29
|
+
{
|
|
30
|
+
get(_methodTarget, methodKey) {
|
|
31
|
+
if (typeof methodKey !== 'string') return undefined;
|
|
32
|
+
|
|
33
|
+
const channel = `${groupKey}.${methodKey}`;
|
|
34
|
+
return (payload?: unknown) =>
|
|
35
|
+
payload === undefined ? invoke(channel) : invoke(channel, payload);
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
) as IpcServices;
|
|
42
|
+
|
|
43
|
+
let cachedProxy: DesktopIpcServices | null = null;
|
|
44
|
+
|
|
45
|
+
declare global {
|
|
46
|
+
interface Window {
|
|
47
|
+
electronAPI?: {
|
|
48
|
+
invoke?: DispatchInvoke;
|
|
49
|
+
onStreamInvoke: (params: ProxyTRPCRequestParams, callbacks: StreamerCallbacks) => () => void;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const getElectronIpc = (): DesktopIpcServices | null => {
|
|
55
|
+
if (typeof window === 'undefined') return null;
|
|
56
|
+
if (cachedProxy) return cachedProxy;
|
|
57
|
+
|
|
58
|
+
const invoke = window.electronAPI?.invoke;
|
|
59
|
+
if (!invoke) return null;
|
|
60
|
+
|
|
61
|
+
cachedProxy = createInvokeProxy<DesktopIpcServices>(invoke);
|
|
62
|
+
return cachedProxy;
|
|
63
|
+
};
|
|
@@ -34,7 +34,13 @@ export const streamInvoke = async (input: RequestInfo | URL, init?: RequestInit)
|
|
|
34
34
|
},
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
const
|
|
37
|
+
const electronAPI = window.electronAPI;
|
|
38
|
+
if (!electronAPI || !electronAPI.onStreamInvoke) {
|
|
39
|
+
reject(new Error('[streamInvoke] window.electronAPI.onStreamInvoke is not available'));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const cleanup = electronAPI.onStreamInvoke(params, {
|
|
38
44
|
onData: (chunk) => {
|
|
39
45
|
if (streamController) streamController.enqueue(chunk);
|
|
40
46
|
},
|
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
ClientDispatchEventKey,
|
|
3
|
-
ClientDispatchEvents,
|
|
4
|
-
ClientEventReturnType,
|
|
5
|
-
} from '../events';
|
|
6
|
-
|
|
7
|
-
export type DispatchInvoke = <T extends ClientDispatchEventKey>(
|
|
8
|
-
event: T,
|
|
9
|
-
...data: Parameters<ClientDispatchEvents[T]>
|
|
10
|
-
) => Promise<ClientEventReturnType<T>>;
|
|
1
|
+
export type DispatchInvoke = <T = unknown>(event: string, ...data: any[]) => Promise<T>;
|
|
@@ -5,7 +5,6 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
7
|
import { SOCK_FILE, SOCK_INFO_FILE, WINDOW_PIPE_FILE } from './const';
|
|
8
|
-
import { ServerDispatchEventKey } from './events';
|
|
9
8
|
|
|
10
9
|
const log = debug('electron-server-ipc:client');
|
|
11
10
|
|
|
@@ -178,7 +177,7 @@ export class ElectronIpcClient {
|
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
// Send request to Electron IPC server
|
|
181
|
-
public async sendRequest<T>(method:
|
|
180
|
+
public async sendRequest<T>(method: string, params: any = {}): Promise<T> {
|
|
182
181
|
if (!this.socketPath) {
|
|
183
182
|
console.error('Cannot send request: Electron IPC connection not available');
|
|
184
183
|
throw new Error('Electron IPC connection not available');
|
|
@@ -5,7 +5,6 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
7
|
import { SOCK_FILE, SOCK_INFO_FILE, WINDOW_PIPE_FILE } from './const';
|
|
8
|
-
import { ServerDispatchEventKey } from './events';
|
|
9
8
|
import { ElectronIPCEventHandler } from './types';
|
|
10
9
|
|
|
11
10
|
const log = debug('electron-server-ipc:server');
|
|
@@ -107,7 +106,7 @@ export class ElectronIPCServer {
|
|
|
107
106
|
log('Handling request: %s (ID: %s)', method, id);
|
|
108
107
|
|
|
109
108
|
// Execute corresponding operation based on request method
|
|
110
|
-
const eventHandler = this.eventHandler[method
|
|
109
|
+
const eventHandler = this.eventHandler[method];
|
|
111
110
|
if (!eventHandler) {
|
|
112
111
|
console.error('No handler found for method: %s', method);
|
|
113
112
|
return;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import net from 'node:net';
|
|
2
2
|
|
|
3
|
-
import { ServerDispatchEventKey } from '../events';
|
|
4
|
-
|
|
5
3
|
export type IPCEventMethod = (
|
|
6
4
|
params: any,
|
|
7
5
|
context: { id: string; method: string; socket: net.Socket },
|
|
8
6
|
) => Promise<any>;
|
|
9
7
|
|
|
10
|
-
export type ElectronIPCEventHandler =
|
|
11
|
-
[key in ServerDispatchEventKey]: IPCEventMethod;
|
|
12
|
-
};
|
|
8
|
+
export type ElectronIPCEventHandler = Record<string, IPCEventMethod>;
|
|
13
9
|
|
|
14
10
|
export * from './file';
|
package/pnpm-workspace.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readdirSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
|
|
4
|
-
import i18nConfig from '
|
|
4
|
+
import i18nConfig from './i18nConfig';
|
|
5
5
|
|
|
6
6
|
export const root = resolve(__dirname, '../..');
|
|
7
7
|
export const localesDir = resolve(root, i18nConfig.output);
|
|
@@ -15,4 +15,4 @@ export const outputLocaleJsonFilepath = (locale: string, file: string) =>
|
|
|
15
15
|
resolve(localesDir, locale, file);
|
|
16
16
|
export const srcDefaultLocales = resolve(root, srcLocalesDir, 'default');
|
|
17
17
|
|
|
18
|
-
export { default as i18nConfig } from '
|
|
18
|
+
export { default as i18nConfig } from './i18nConfig';
|
|
@@ -3,7 +3,7 @@ import { colors } from 'consola/utils';
|
|
|
3
3
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
5
|
import prettier from "@prettier/sync";
|
|
6
|
-
import i18nConfig from '
|
|
6
|
+
import i18nConfig from './i18nConfig';
|
|
7
7
|
|
|
8
8
|
let prettierOptions = prettier.resolveConfig(
|
|
9
9
|
resolve(__dirname, '../../.prettierrc.js')
|
|
@@ -30,8 +30,8 @@ const ProviderConfig = memo(() => {
|
|
|
30
30
|
const tab = 'provider';
|
|
31
31
|
|
|
32
32
|
if (isDesktop) {
|
|
33
|
-
const {
|
|
34
|
-
await
|
|
33
|
+
const { ensureElectronIpc } = await import('@/utils/electron/ipc');
|
|
34
|
+
await ensureElectronIpc().windows.openSettingsWindow({
|
|
35
35
|
searchParams,
|
|
36
36
|
tab,
|
|
37
37
|
});
|
|
@@ -1,46 +1,92 @@
|
|
|
1
1
|
import { CreateFileParams, ElectronIpcClient, FileMetadata } from '@lobechat/electron-server-ipc';
|
|
2
|
+
import type { DesktopServerIpcServices } from '@lobehub/desktop-ipc-typings';
|
|
2
3
|
|
|
3
4
|
import packageJSON from '@/../apps/desktop/package.json';
|
|
4
5
|
|
|
6
|
+
const createServerInvokeProxy = <IpcServices>(
|
|
7
|
+
invoke: (channel: string, payload?: unknown) => Promise<unknown>,
|
|
8
|
+
): IpcServices =>
|
|
9
|
+
new Proxy(
|
|
10
|
+
{},
|
|
11
|
+
{
|
|
12
|
+
get(_target, groupKey) {
|
|
13
|
+
if (typeof groupKey !== 'string') return undefined;
|
|
14
|
+
|
|
15
|
+
return new Proxy(
|
|
16
|
+
{},
|
|
17
|
+
{
|
|
18
|
+
get(_methodTarget, methodKey) {
|
|
19
|
+
if (typeof methodKey !== 'string') return undefined;
|
|
20
|
+
|
|
21
|
+
const channel = `${groupKey}.${methodKey}`;
|
|
22
|
+
return (payload?: unknown) =>
|
|
23
|
+
payload === undefined ? invoke(channel) : invoke(channel, payload);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
) as IpcServices;
|
|
30
|
+
|
|
5
31
|
class LobeHubElectronIpcClient extends ElectronIpcClient {
|
|
6
|
-
|
|
32
|
+
private _services: DesktopServerIpcServices | null = null;
|
|
33
|
+
|
|
34
|
+
private ensureServices(): DesktopServerIpcServices {
|
|
35
|
+
if (this._services) return this._services;
|
|
36
|
+
|
|
37
|
+
this._services = createServerInvokeProxy<DesktopServerIpcServices>((channel, payload) =>
|
|
38
|
+
payload === undefined ? this.sendRequest(channel) : this.sendRequest(channel, payload),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return this.services;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private get ipc() {
|
|
45
|
+
return this.ensureServices();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public get services(): DesktopServerIpcServices {
|
|
49
|
+
return this.ipc;
|
|
50
|
+
}
|
|
51
|
+
|
|
7
52
|
getDatabasePath = async (): Promise<string> => {
|
|
8
|
-
return this.
|
|
53
|
+
return this.ipc.system.getDatabasePath();
|
|
9
54
|
};
|
|
10
55
|
|
|
11
|
-
// 获取用户数据路径
|
|
12
56
|
getUserDataPath = async (): Promise<string> => {
|
|
13
|
-
return this.
|
|
57
|
+
return this.ipc.system.getUserDataPath();
|
|
14
58
|
};
|
|
15
59
|
|
|
16
60
|
getDatabaseSchemaHash = async () => {
|
|
17
|
-
return this.
|
|
61
|
+
return this.ipc.system.getDatabaseSchemaHash();
|
|
18
62
|
};
|
|
19
63
|
|
|
20
64
|
setDatabaseSchemaHash = async (hash: string | undefined) => {
|
|
21
65
|
if (!hash) return;
|
|
22
66
|
|
|
23
|
-
return this.
|
|
67
|
+
return this.ipc.system.setDatabaseSchemaHash(hash);
|
|
24
68
|
};
|
|
25
69
|
|
|
26
70
|
getFilePathById = async (id: string) => {
|
|
27
|
-
return this.
|
|
71
|
+
return this.ipc.upload.getFileUrlById(id);
|
|
28
72
|
};
|
|
29
73
|
|
|
30
74
|
getFileHTTPURL = async (path: string) => {
|
|
31
|
-
return this.
|
|
75
|
+
return this.ipc.upload.getFileHTTPURL(path);
|
|
32
76
|
};
|
|
33
77
|
|
|
34
78
|
deleteFiles = async (paths: string[]) => {
|
|
35
|
-
return this.
|
|
36
|
-
'deleteFiles',
|
|
37
|
-
paths,
|
|
38
|
-
);
|
|
79
|
+
return this.ipc.upload.deleteFiles(paths);
|
|
39
80
|
};
|
|
40
81
|
|
|
41
82
|
createFile = async (params: CreateFileParams) => {
|
|
42
|
-
return this.
|
|
83
|
+
return this.ipc.upload.createFile(params) as Promise<{
|
|
84
|
+
metadata: FileMetadata;
|
|
85
|
+
success: boolean;
|
|
86
|
+
}>;
|
|
43
87
|
};
|
|
44
88
|
}
|
|
45
89
|
|
|
46
90
|
export const electronIpcClient = new LobeHubElectronIpcClient(packageJSON.name);
|
|
91
|
+
|
|
92
|
+
export const ensureElectronServerIpc = (): DesktopServerIpcServices => electronIpcClient.services;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { dispatch } from '@lobechat/electron-client-ipc';
|
|
2
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
2
|
|
|
4
3
|
import { electronDevtoolsService } from '../devtools';
|
|
5
4
|
|
|
6
|
-
vi.
|
|
7
|
-
|
|
5
|
+
const openDevtoolsMock = vi.fn();
|
|
6
|
+
vi.mock('@/utils/electron/ipc', () => ({
|
|
7
|
+
ensureElectronIpc: vi.fn(() => ({
|
|
8
|
+
devtools: { openDevtools: openDevtoolsMock },
|
|
9
|
+
})),
|
|
8
10
|
}));
|
|
11
|
+
const { ensureElectronIpc } = await import('@/utils/electron/ipc');
|
|
9
12
|
|
|
10
13
|
describe('DevtoolsService', () => {
|
|
11
14
|
beforeEach(() => {
|
|
@@ -15,18 +18,19 @@ describe('DevtoolsService', () => {
|
|
|
15
18
|
describe('openDevtools', () => {
|
|
16
19
|
it('should call dispatch with openDevtools', async () => {
|
|
17
20
|
await electronDevtoolsService.openDevtools();
|
|
18
|
-
expect(
|
|
21
|
+
expect(ensureElectronIpc).toHaveBeenCalled();
|
|
22
|
+
expect(openDevtoolsMock).toHaveBeenCalled();
|
|
19
23
|
});
|
|
20
24
|
|
|
21
25
|
it('should return void when dispatch succeeds', async () => {
|
|
22
|
-
|
|
26
|
+
openDevtoolsMock.mockResolvedValueOnce(undefined);
|
|
23
27
|
const result = await electronDevtoolsService.openDevtools();
|
|
24
28
|
expect(result).toBeUndefined();
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
it('should throw error when dispatch fails', async () => {
|
|
28
32
|
const error = new Error('Failed to open devtools');
|
|
29
|
-
|
|
33
|
+
openDevtoolsMock.mockRejectedValueOnce(error);
|
|
30
34
|
|
|
31
35
|
await expect(electronDevtoolsService.openDevtools()).rejects.toThrow(error);
|
|
32
36
|
});
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
2
2
|
|
|
3
3
|
class AutoUpdateService {
|
|
4
4
|
checkUpdate = async () => {
|
|
5
|
-
return
|
|
5
|
+
return ensureElectronIpc().autoUpdate.checkForUpdates();
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
installNow = async () => {
|
|
9
|
-
return
|
|
9
|
+
return ensureElectronIpc().autoUpdate.quitAndInstallUpdate();
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
installLater = async () => {
|
|
13
|
-
return
|
|
13
|
+
return ensureElectronIpc().autoUpdate.installLater();
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
downloadUpdate() {
|
|
17
|
-
return
|
|
17
|
+
return ensureElectronIpc().autoUpdate.downloadUpdate();
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
ShowDesktopNotificationParams,
|
|
4
|
-
dispatch,
|
|
5
|
-
} from '@lobechat/electron-client-ipc';
|
|
1
|
+
import { DesktopNotificationResult, ShowDesktopNotificationParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
6
3
|
|
|
7
4
|
/**
|
|
8
5
|
* Desktop notification service
|
|
@@ -16,7 +13,7 @@ export class DesktopNotificationService {
|
|
|
16
13
|
async showNotification(
|
|
17
14
|
params: ShowDesktopNotificationParams,
|
|
18
15
|
): Promise<DesktopNotificationResult> {
|
|
19
|
-
return
|
|
16
|
+
return ensureElectronIpc().notification.showDesktopNotification(params);
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
/**
|
|
@@ -24,7 +21,7 @@ export class DesktopNotificationService {
|
|
|
24
21
|
* @returns Whether it is hidden
|
|
25
22
|
*/
|
|
26
23
|
async isMainWindowHidden(): Promise<boolean> {
|
|
27
|
-
return
|
|
24
|
+
return ensureElectronIpc().notification.isMainWindowHidden();
|
|
28
25
|
}
|
|
29
26
|
}
|
|
30
27
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
2
2
|
|
|
3
3
|
class DevtoolsService {
|
|
4
4
|
async openDevtools(): Promise<void> {
|
|
5
|
-
return
|
|
5
|
+
return ensureElectronIpc().devtools.openDevtools();
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { dispatch } from '@lobechat/electron-client-ipc';
|
|
2
1
|
import { FileMetadata } from '@lobechat/types';
|
|
3
2
|
|
|
3
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
4
|
+
|
|
4
5
|
/**
|
|
5
6
|
* Desktop application file API client service
|
|
6
7
|
*/
|
|
@@ -19,7 +20,7 @@ class DesktopFileAPI {
|
|
|
19
20
|
): Promise<{ metadata: FileMetadata; success: boolean }> {
|
|
20
21
|
const arrayBuffer = await file.arrayBuffer();
|
|
21
22
|
|
|
22
|
-
return
|
|
23
|
+
return ensureElectronIpc().upload.uploadFile({
|
|
23
24
|
content: arrayBuffer,
|
|
24
25
|
filename: file.name,
|
|
25
26
|
hash,
|
|
@@ -23,71 +23,72 @@ import {
|
|
|
23
23
|
RunCommandParams,
|
|
24
24
|
RunCommandResult,
|
|
25
25
|
WriteLocalFileParams,
|
|
26
|
-
dispatch,
|
|
27
26
|
} from '@lobechat/electron-client-ipc';
|
|
28
27
|
|
|
28
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
29
|
+
|
|
29
30
|
class LocalFileService {
|
|
30
31
|
// File Operations
|
|
31
32
|
async listLocalFiles(params: ListLocalFileParams): Promise<LocalFileItem[]> {
|
|
32
|
-
return
|
|
33
|
+
return ensureElectronIpc().localSystem.listLocalFiles(params);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
async readLocalFile(params: LocalReadFileParams): Promise<LocalReadFileResult> {
|
|
36
|
-
return
|
|
37
|
+
return ensureElectronIpc().localSystem.readFile(params);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
async readLocalFiles(params: LocalReadFilesParams): Promise<LocalReadFileResult[]> {
|
|
40
|
-
return
|
|
41
|
+
return ensureElectronIpc().localSystem.readFiles(params);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
async searchLocalFiles(params: LocalSearchFilesParams): Promise<LocalFileItem[]> {
|
|
44
|
-
return
|
|
45
|
+
return ensureElectronIpc().localSystem.handleLocalFilesSearch(params);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
async openLocalFile(params: OpenLocalFileParams) {
|
|
48
|
-
return
|
|
49
|
+
return ensureElectronIpc().localSystem.handleOpenLocalFile(params);
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
async openLocalFolder(params: OpenLocalFolderParams) {
|
|
52
|
-
return
|
|
53
|
+
return ensureElectronIpc().localSystem.handleOpenLocalFile(params);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
async moveLocalFiles(params: MoveLocalFilesParams): Promise<LocalMoveFilesResultItem[]> {
|
|
56
|
-
return
|
|
57
|
+
return ensureElectronIpc().localSystem.handleMoveFiles(params);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
async renameLocalFile(params: RenameLocalFileParams) {
|
|
60
|
-
return
|
|
61
|
+
return ensureElectronIpc().localSystem.handleRenameFile(params);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
async writeFile(params: WriteLocalFileParams) {
|
|
64
|
-
return
|
|
65
|
+
return ensureElectronIpc().localSystem.handleWriteFile(params);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
async editLocalFile(params: EditLocalFileParams): Promise<EditLocalFileResult> {
|
|
68
|
-
return
|
|
69
|
+
return ensureElectronIpc().localSystem.handleEditFile(params);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
// Shell Commands
|
|
72
73
|
async runCommand(params: RunCommandParams): Promise<RunCommandResult> {
|
|
73
|
-
return
|
|
74
|
+
return ensureElectronIpc().shellCommand.handleRunCommand(params);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
async getCommandOutput(params: GetCommandOutputParams): Promise<GetCommandOutputResult> {
|
|
77
|
-
return
|
|
78
|
+
return ensureElectronIpc().shellCommand.handleGetCommandOutput(params);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
async killCommand(params: KillCommandParams): Promise<KillCommandResult> {
|
|
81
|
-
return
|
|
82
|
+
return ensureElectronIpc().shellCommand.handleKillCommand(params);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
// Search & Find
|
|
85
86
|
async grepContent(params: GrepContentParams): Promise<GrepContentResult> {
|
|
86
|
-
return
|
|
87
|
+
return ensureElectronIpc().localSystem.handleGrepContent(params);
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
async globFiles(params: GlobFilesParams): Promise<GlobFilesResult> {
|
|
90
|
-
return
|
|
91
|
+
return ensureElectronIpc().localSystem.handleGlobFiles(params);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
// Helper methods
|
|
@@ -1,39 +1,40 @@
|
|
|
1
|
-
import { DataSyncConfig, MarketAuthorizationParams
|
|
1
|
+
import { DataSyncConfig, MarketAuthorizationParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
2
3
|
|
|
3
4
|
class RemoteServerService {
|
|
4
5
|
/**
|
|
5
6
|
* Get remote server configuration
|
|
6
7
|
*/
|
|
7
8
|
getRemoteServerConfig = async () => {
|
|
8
|
-
return
|
|
9
|
+
return ensureElectronIpc().remoteServer.getRemoteServerConfig();
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Set remote server configuration
|
|
13
14
|
*/
|
|
14
15
|
setRemoteServerConfig = async (config: DataSyncConfig) => {
|
|
15
|
-
return
|
|
16
|
+
return ensureElectronIpc().remoteServer.setRemoteServerConfig(config);
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Clear remote server configuration
|
|
20
21
|
*/
|
|
21
22
|
clearRemoteServerConfig = async () => {
|
|
22
|
-
return
|
|
23
|
+
return ensureElectronIpc().remoteServer.clearRemoteServerConfig();
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Request authorization
|
|
27
28
|
*/
|
|
28
29
|
requestAuthorization = async (config: DataSyncConfig) => {
|
|
29
|
-
return
|
|
30
|
+
return ensureElectronIpc().auth.requestAuthorization(config);
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Request Market authorization
|
|
34
35
|
*/
|
|
35
36
|
requestMarketAuthorization = async (params: MarketAuthorizationParams) => {
|
|
36
|
-
return
|
|
37
|
+
return ensureElectronIpc().auth.requestMarketAuthorization(params);
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -1,50 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
dispatch,
|
|
5
|
-
} from '@lobechat/electron-client-ipc';
|
|
1
|
+
import { NetworkProxySettings, ShortcutUpdateResult } from '@lobechat/electron-client-ipc';
|
|
2
|
+
|
|
3
|
+
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
6
4
|
|
|
7
5
|
class DesktopSettingsService {
|
|
8
6
|
/**
|
|
9
7
|
* Get proxy settings
|
|
10
8
|
*/
|
|
11
9
|
getProxySettings = async () => {
|
|
12
|
-
return
|
|
10
|
+
return ensureElectronIpc().networkProxy.getDesktopSettings();
|
|
13
11
|
};
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
14
|
* Set proxy settings
|
|
17
15
|
*/
|
|
18
16
|
setSettings = async (data: Partial<NetworkProxySettings>) => {
|
|
19
|
-
return
|
|
17
|
+
return ensureElectronIpc().networkProxy.setProxySettings(data);
|
|
20
18
|
};
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
21
|
* Get desktop hotkey configuration
|
|
24
22
|
*/
|
|
25
23
|
getDesktopHotkeys = async () => {
|
|
26
|
-
return
|
|
24
|
+
return ensureElectronIpc().shortcut.getShortcutsConfig();
|
|
27
25
|
};
|
|
28
26
|
|
|
29
27
|
/**
|
|
30
28
|
* Update desktop hotkey configuration
|
|
31
29
|
*/
|
|
32
30
|
updateDesktopHotkey = async (id: string, accelerator: string): Promise<ShortcutUpdateResult> => {
|
|
33
|
-
return
|
|
31
|
+
return ensureElectronIpc().shortcut.updateShortcutConfig({ accelerator, id });
|
|
34
32
|
};
|
|
35
33
|
|
|
36
34
|
/**
|
|
37
35
|
* Test proxy connection
|
|
38
36
|
*/
|
|
39
37
|
testProxyConnection = async (url: string) => {
|
|
40
|
-
return
|
|
38
|
+
return ensureElectronIpc().networkProxy.testProxyConnection(url);
|
|
41
39
|
};
|
|
42
40
|
|
|
43
41
|
/**
|
|
44
42
|
* Test specified proxy configuration
|
|
45
43
|
*/
|
|
46
44
|
testProxyConfig = async (config: NetworkProxySettings, testUrl?: string) => {
|
|
47
|
-
return
|
|
45
|
+
return ensureElectronIpc().networkProxy.testProxyConfig({ config, testUrl });
|
|
48
46
|
};
|
|
49
47
|
}
|
|
50
48
|
|