@lobehub/chat 1.82.10 → 1.83.1
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/.env.desktop +1 -2
- package/.github/workflows/{release-desktop.yml → desktop-pr-build.yml} +59 -137
- package/.github/workflows/release-desktop-beta.yml +194 -0
- package/CHANGELOG.md +42 -0
- package/apps/desktop/.i18nrc.js +31 -0
- package/apps/desktop/Development.md +47 -0
- package/apps/desktop/README.md +6 -0
- package/apps/desktop/build/Icon-beta.icns +0 -0
- package/apps/desktop/build/Icon-nightly.icns +0 -0
- package/apps/desktop/build/Icon.icns +0 -0
- package/apps/desktop/build/entitlements.mac.plist +12 -0
- package/apps/desktop/build/favicon.ico +0 -0
- package/apps/desktop/build/icon-beta.png +0 -0
- package/apps/desktop/build/icon-dev.png +0 -0
- package/apps/desktop/build/icon-nightly.ico +0 -0
- package/apps/desktop/build/icon-nightly.png +0 -0
- package/apps/desktop/build/icon.ico +0 -0
- package/apps/desktop/build/icon.png +0 -0
- package/apps/desktop/dev-app-update.yml +6 -0
- package/apps/desktop/electron-builder.js +92 -0
- package/apps/desktop/electron.vite.config.ts +40 -0
- package/apps/desktop/package.json +72 -0
- package/apps/desktop/pnpm-workspace.yaml +5 -0
- package/apps/desktop/resources/error.html +136 -0
- package/apps/desktop/resources/locales/ar/common.json +32 -0
- package/apps/desktop/resources/locales/ar/dialog.json +31 -0
- package/apps/desktop/resources/locales/ar/menu.json +70 -0
- package/apps/desktop/resources/locales/bg-BG/common.json +32 -0
- package/apps/desktop/resources/locales/bg-BG/dialog.json +31 -0
- package/apps/desktop/resources/locales/bg-BG/menu.json +70 -0
- package/apps/desktop/resources/locales/de-DE/common.json +32 -0
- package/apps/desktop/resources/locales/de-DE/dialog.json +31 -0
- package/apps/desktop/resources/locales/de-DE/menu.json +70 -0
- package/apps/desktop/resources/locales/en-US/common.json +32 -0
- package/apps/desktop/resources/locales/en-US/dialog.json +31 -0
- package/apps/desktop/resources/locales/en-US/menu.json +70 -0
- package/apps/desktop/resources/locales/es-ES/common.json +32 -0
- package/apps/desktop/resources/locales/es-ES/dialog.json +31 -0
- package/apps/desktop/resources/locales/es-ES/menu.json +70 -0
- package/apps/desktop/resources/locales/fa-IR/common.json +32 -0
- package/apps/desktop/resources/locales/fa-IR/dialog.json +31 -0
- package/apps/desktop/resources/locales/fa-IR/menu.json +70 -0
- package/apps/desktop/resources/locales/fr-FR/common.json +32 -0
- package/apps/desktop/resources/locales/fr-FR/dialog.json +31 -0
- package/apps/desktop/resources/locales/fr-FR/menu.json +70 -0
- package/apps/desktop/resources/locales/it-IT/common.json +32 -0
- package/apps/desktop/resources/locales/it-IT/dialog.json +31 -0
- package/apps/desktop/resources/locales/it-IT/menu.json +70 -0
- package/apps/desktop/resources/locales/ja-JP/common.json +32 -0
- package/apps/desktop/resources/locales/ja-JP/dialog.json +31 -0
- package/apps/desktop/resources/locales/ja-JP/menu.json +70 -0
- package/apps/desktop/resources/locales/ko-KR/common.json +32 -0
- package/apps/desktop/resources/locales/ko-KR/dialog.json +31 -0
- package/apps/desktop/resources/locales/ko-KR/menu.json +70 -0
- package/apps/desktop/resources/locales/nl-NL/common.json +32 -0
- package/apps/desktop/resources/locales/nl-NL/dialog.json +31 -0
- package/apps/desktop/resources/locales/nl-NL/menu.json +70 -0
- package/apps/desktop/resources/locales/pl-PL/common.json +32 -0
- package/apps/desktop/resources/locales/pl-PL/dialog.json +31 -0
- package/apps/desktop/resources/locales/pl-PL/menu.json +70 -0
- package/apps/desktop/resources/locales/pt-BR/common.json +32 -0
- package/apps/desktop/resources/locales/pt-BR/dialog.json +31 -0
- package/apps/desktop/resources/locales/pt-BR/menu.json +70 -0
- package/apps/desktop/resources/locales/ru-RU/common.json +32 -0
- package/apps/desktop/resources/locales/ru-RU/dialog.json +31 -0
- package/apps/desktop/resources/locales/ru-RU/menu.json +70 -0
- package/apps/desktop/resources/locales/tr-TR/common.json +32 -0
- package/apps/desktop/resources/locales/tr-TR/dialog.json +31 -0
- package/apps/desktop/resources/locales/tr-TR/menu.json +70 -0
- package/apps/desktop/resources/locales/vi-VN/common.json +32 -0
- package/apps/desktop/resources/locales/vi-VN/dialog.json +31 -0
- package/apps/desktop/resources/locales/vi-VN/menu.json +70 -0
- package/apps/desktop/resources/locales/zh-CN/common.json +32 -0
- package/apps/desktop/resources/locales/zh-CN/dialog.json +31 -0
- package/apps/desktop/resources/locales/zh-CN/menu.json +70 -0
- package/apps/desktop/resources/locales/zh-TW/common.json +32 -0
- package/apps/desktop/resources/locales/zh-TW/dialog.json +31 -0
- package/apps/desktop/resources/locales/zh-TW/menu.json +70 -0
- package/apps/desktop/resources/splash.html +88 -0
- package/apps/desktop/scripts/i18nWorkflow/const.ts +18 -0
- package/apps/desktop/scripts/i18nWorkflow/genDefaultLocale.ts +35 -0
- package/apps/desktop/scripts/i18nWorkflow/genDiff.ts +57 -0
- package/apps/desktop/scripts/i18nWorkflow/index.ts +35 -0
- package/apps/desktop/scripts/i18nWorkflow/utils.ts +54 -0
- package/apps/desktop/scripts/pglite-server.ts +14 -0
- package/apps/desktop/src/common/routes.ts +78 -0
- package/apps/desktop/src/main/appBrowsers.ts +47 -0
- package/apps/desktop/src/main/const/dir.ts +29 -0
- package/apps/desktop/src/main/const/env.ts +3 -0
- package/apps/desktop/src/main/const/store.ts +22 -0
- package/apps/desktop/src/main/controllers/AuthCtr.ts +390 -0
- package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +95 -0
- package/apps/desktop/src/main/controllers/DevtoolsCtr.ts +9 -0
- package/apps/desktop/src/main/controllers/LocalFileCtr.ts +380 -0
- package/apps/desktop/src/main/controllers/MenuCtr.ts +29 -0
- package/apps/desktop/src/main/controllers/RemoteServerConfigCtr.ts +335 -0
- package/apps/desktop/src/main/controllers/RemoteServerSyncCtr.ts +321 -0
- package/apps/desktop/src/main/controllers/ShortcutCtr.ts +19 -0
- package/apps/desktop/src/main/controllers/SystemCtr.ts +93 -0
- package/apps/desktop/src/main/controllers/UpdaterCtr.ts +43 -0
- package/apps/desktop/src/main/controllers/UploadFileCtr.ts +34 -0
- package/apps/desktop/src/main/controllers/_template.ts +9 -0
- package/apps/desktop/src/main/controllers/index.ts +58 -0
- package/apps/desktop/src/main/core/App.ts +370 -0
- package/apps/desktop/src/main/core/Browser.ts +345 -0
- package/apps/desktop/src/main/core/BrowserManager.ts +154 -0
- package/apps/desktop/src/main/core/I18nManager.ts +185 -0
- package/apps/desktop/src/main/core/IoCContainer.ts +12 -0
- package/apps/desktop/src/main/core/MenuManager.ts +64 -0
- package/apps/desktop/src/main/core/ShortcutManager.ts +173 -0
- package/apps/desktop/src/main/core/StoreManager.ts +89 -0
- package/apps/desktop/src/main/core/UpdaterManager.ts +321 -0
- package/apps/desktop/src/main/index.ts +5 -0
- package/apps/desktop/src/main/locales/default/common.ts +34 -0
- package/apps/desktop/src/main/locales/default/dialog.ts +33 -0
- package/apps/desktop/src/main/locales/default/index.ts +11 -0
- package/apps/desktop/src/main/locales/default/menu.ts +72 -0
- package/apps/desktop/src/main/locales/resources.ts +35 -0
- package/apps/desktop/src/main/menus/impls/BaseMenuPlatform.ts +10 -0
- package/apps/desktop/src/main/menus/impls/linux.ts +243 -0
- package/apps/desktop/src/main/menus/impls/macOS.ts +360 -0
- package/apps/desktop/src/main/menus/impls/windows.ts +226 -0
- package/apps/desktop/src/main/menus/index.ts +34 -0
- package/apps/desktop/src/main/menus/types.ts +28 -0
- package/apps/desktop/src/main/modules/fileSearch/impl/macOS.ts +577 -0
- package/apps/desktop/src/main/modules/fileSearch/index.ts +23 -0
- package/apps/desktop/src/main/modules/fileSearch/type.ts +27 -0
- package/apps/desktop/src/main/modules/updater/configs.ts +22 -0
- package/apps/desktop/src/main/modules/updater/utils.ts +33 -0
- package/apps/desktop/src/main/services/fileSearchSrv.ts +35 -0
- package/apps/desktop/src/main/services/fileSrv.ts +255 -0
- package/apps/desktop/src/main/services/index.ts +9 -0
- package/apps/desktop/src/main/shortcuts/config.ts +18 -0
- package/apps/desktop/src/main/shortcuts/index.ts +1 -0
- package/apps/desktop/src/main/types/fileSearch.ts +51 -0
- package/apps/desktop/src/main/types/store.ts +14 -0
- package/apps/desktop/src/main/utils/file-system.ts +15 -0
- package/apps/desktop/src/main/utils/logger.ts +44 -0
- package/apps/desktop/src/main/utils/next-electron-rsc.ts +383 -0
- package/apps/desktop/src/preload/electronApi.ts +18 -0
- package/apps/desktop/src/preload/index.ts +14 -0
- package/apps/desktop/src/preload/invoke.ts +10 -0
- package/apps/desktop/src/preload/routeInterceptor.ts +162 -0
- package/apps/desktop/tsconfig.json +21 -0
- package/changelog/v1.json +14 -0
- package/package.json +1 -1
- package/packages/electron-client-ipc/src/events/remoteServer.ts +11 -4
- package/packages/electron-client-ipc/src/types/dataSync.ts +15 -0
- package/packages/electron-client-ipc/src/types/index.ts +2 -1
- package/packages/electron-client-ipc/src/types/proxyTRPCRequest.ts +21 -0
- package/packages/electron-server-ipc/src/const.ts +3 -3
- package/packages/electron-server-ipc/src/ipcClient.test.ts +7 -6
- package/packages/electron-server-ipc/src/ipcClient.ts +17 -8
- package/packages/electron-server-ipc/src/ipcServer.ts +7 -3
- package/scripts/electronWorkflow/setDesktopVersion.ts +60 -43
- package/src/app/[variants]/(main)/_layout/Desktop/index.tsx +1 -1
- package/src/components/Analytics/Desktop.tsx +19 -0
- package/src/components/Analytics/index.tsx +3 -0
- package/src/database/core/db-adaptor.ts +4 -1
- package/src/database/core/electron.ts +317 -0
- package/src/{app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Mode.tsx → features/ElectronTitlebar/Connection/ConnectionMode.tsx} +24 -21
- package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/Option.tsx +3 -5
- package/src/{app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Sync.tsx → features/ElectronTitlebar/Connection/RemoteStatus.tsx} +10 -7
- package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/index.tsx +4 -4
- package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/UpdateModal.tsx +2 -1
- package/src/libs/trpc/client/async.ts +6 -0
- package/src/libs/trpc/client/edge.ts +6 -0
- package/src/libs/trpc/client/helpers/desktopRemoteRPCFetch.ts +72 -0
- package/src/libs/trpc/client/index.ts +1 -0
- package/src/libs/trpc/client/lambda.ts +10 -1
- package/src/libs/trpc/client/tools.ts +6 -0
- package/src/server/globalConfig/index.ts +0 -3
- package/src/server/modules/ElectronIPCClient/index.ts +3 -1
- package/src/server/routers/desktop/index.ts +2 -0
- package/src/server/routers/desktop/mcp.ts +47 -0
- package/src/server/routers/lambda/user.ts +38 -23
- package/src/server/routers/tools/mcp.ts +0 -6
- package/src/services/electron/remoteServer.ts +4 -4
- package/src/services/mcp.ts +17 -7
- package/src/services/upload.ts +9 -0
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +11 -2
- package/src/store/chat/slices/builtinTool/actions/localFile.ts +110 -53
- package/src/store/electron/actions/sync.ts +20 -19
- package/src/store/electron/initialState.ts +3 -3
- package/src/store/electron/selectors/sync.ts +6 -3
- package/src/store/electron/store.ts +2 -0
- package/src/store/file/slices/upload/action.ts +11 -3
- package/src/store/tool/selectors/tool.ts +10 -1
- package/src/utils/fetch/headers.ts +27 -0
- package/src/utils/fetch/index.ts +2 -0
- package/src/utils/fetch/request.ts +28 -0
- package/packages/electron-client-ipc/src/types/remoteServer.ts +0 -8
- /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/Connection/Waiting.tsx +0 -0
- /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/UpdateNotification.tsx +0 -0
- /package/src/{app/[variants]/(main)/_layout/Desktop → features}/ElectronTitlebar/index.tsx +0 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
import { FileSearchImpl, createFileSearchModule } from '@/modules/fileSearch';
|
2
|
+
import { FileResult, SearchOptions } from '@/types/fileSearch';
|
3
|
+
|
4
|
+
import { ServiceModule } from './index';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* File Search Service
|
8
|
+
* Main service class that uses platform-specific implementations internally
|
9
|
+
*/
|
10
|
+
export default class FileSearchService extends ServiceModule {
|
11
|
+
private impl: FileSearchImpl = createFileSearchModule();
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Perform file search
|
15
|
+
*/
|
16
|
+
async search(query: string, options: Omit<SearchOptions, 'keywords'> = {}): Promise<FileResult[]> {
|
17
|
+
return this.impl.search({ ...options, keywords: query });
|
18
|
+
}
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Check search service status
|
22
|
+
*/
|
23
|
+
async checkSearchServiceStatus(): Promise<boolean> {
|
24
|
+
return this.impl.checkSearchServiceStatus();
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Update search index
|
29
|
+
* @param path Optional specified path
|
30
|
+
* @returns Promise indicating operation success
|
31
|
+
*/
|
32
|
+
async updateSearchIndex(path?: string): Promise<boolean> {
|
33
|
+
return this.impl.updateSearchIndex(path);
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,255 @@
|
|
1
|
+
import { DeleteFilesResponse } from '@lobechat/electron-server-ipc';
|
2
|
+
import * as fs from 'node:fs';
|
3
|
+
import { writeFile } from 'node:fs/promises';
|
4
|
+
import { join } from 'node:path';
|
5
|
+
import { promisify } from 'node:util';
|
6
|
+
|
7
|
+
import { FILE_STORAGE_DIR } from '@/const/dir';
|
8
|
+
import { makeSureDirExist } from '@/utils/file-system';
|
9
|
+
|
10
|
+
import { ServiceModule } from './index';
|
11
|
+
|
12
|
+
const readFilePromise = promisify(fs.readFile);
|
13
|
+
const unlinkPromise = promisify(fs.unlink);
|
14
|
+
|
15
|
+
interface UploadFileParams {
|
16
|
+
content: ArrayBuffer;
|
17
|
+
filename: string;
|
18
|
+
hash: string;
|
19
|
+
path: string;
|
20
|
+
type: string;
|
21
|
+
}
|
22
|
+
|
23
|
+
interface FileMetadata {
|
24
|
+
date: string;
|
25
|
+
dirname: string;
|
26
|
+
filename: string;
|
27
|
+
path: string;
|
28
|
+
}
|
29
|
+
|
30
|
+
export default class FileService extends ServiceModule {
|
31
|
+
get UPLOADS_DIR() {
|
32
|
+
return join(this.app.appStoragePath, FILE_STORAGE_DIR, 'uploads');
|
33
|
+
}
|
34
|
+
|
35
|
+
constructor(app) {
|
36
|
+
super(app);
|
37
|
+
|
38
|
+
// 初始化文件存储目录
|
39
|
+
makeSureDirExist(this.UPLOADS_DIR);
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* 上传文件到本地存储
|
44
|
+
*/
|
45
|
+
async uploadFile({
|
46
|
+
content,
|
47
|
+
filename,
|
48
|
+
hash,
|
49
|
+
type,
|
50
|
+
}: UploadFileParams): Promise<{ metadata: FileMetadata; success: boolean }> {
|
51
|
+
try {
|
52
|
+
// 创建时间戳目录
|
53
|
+
const date = (Date.now() / 1000 / 60 / 60).toFixed(0);
|
54
|
+
const dirname = join(this.UPLOADS_DIR, date);
|
55
|
+
makeSureDirExist(dirname);
|
56
|
+
|
57
|
+
// 生成文件保存路径
|
58
|
+
const fileExt = filename.split('.').pop() || '';
|
59
|
+
const savedFilename = `${hash}${fileExt ? `.${fileExt}` : ''}`;
|
60
|
+
const savedPath = join(dirname, savedFilename);
|
61
|
+
|
62
|
+
// 写入文件内容
|
63
|
+
const buffer = Buffer.from(content);
|
64
|
+
await writeFile(savedPath, buffer);
|
65
|
+
|
66
|
+
// 写入元数据文件
|
67
|
+
const metaFilePath = `${savedPath}.meta`;
|
68
|
+
const metadata = {
|
69
|
+
createdAt: Date.now(),
|
70
|
+
filename,
|
71
|
+
hash,
|
72
|
+
size: buffer.length,
|
73
|
+
type,
|
74
|
+
};
|
75
|
+
await writeFile(metaFilePath, JSON.stringify(metadata, null, 2));
|
76
|
+
|
77
|
+
// 返回与S3兼容的元数据格式
|
78
|
+
const desktopPath = `desktop://${date}/${savedFilename}`;
|
79
|
+
|
80
|
+
return {
|
81
|
+
metadata: {
|
82
|
+
date,
|
83
|
+
dirname: date,
|
84
|
+
filename: savedFilename,
|
85
|
+
path: desktopPath,
|
86
|
+
},
|
87
|
+
success: true,
|
88
|
+
};
|
89
|
+
} catch (error) {
|
90
|
+
console.error('File upload failed:', error);
|
91
|
+
throw new Error(`File upload failed: ${(error as Error).message}`);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* 获取文件内容
|
97
|
+
*/
|
98
|
+
async getFile(path: string): Promise<{ content: ArrayBuffer; mimeType: string }> {
|
99
|
+
try {
|
100
|
+
// 处理desktop://路径
|
101
|
+
if (!path.startsWith('desktop://')) {
|
102
|
+
throw new Error(`Invalid desktop file path: ${path}`);
|
103
|
+
}
|
104
|
+
|
105
|
+
// 标准化路径格式
|
106
|
+
// 可能收到的格式: desktop:/12345/file.png 或 desktop://12345/file.png
|
107
|
+
const normalizedPath = path.replace(/^desktop:\/+/, 'desktop://');
|
108
|
+
|
109
|
+
// 解析路径
|
110
|
+
const relativePath = normalizedPath.replace('desktop://', '');
|
111
|
+
const filePath = join(this.UPLOADS_DIR, relativePath);
|
112
|
+
|
113
|
+
console.log('Reading file from:', filePath);
|
114
|
+
|
115
|
+
// 读取文件内容
|
116
|
+
const content = await readFilePromise(filePath);
|
117
|
+
|
118
|
+
// 读取元数据获取MIME类型
|
119
|
+
const metaFilePath = `${filePath}.meta`;
|
120
|
+
let mimeType = 'application/octet-stream'; // 默认MIME类型
|
121
|
+
|
122
|
+
try {
|
123
|
+
const metaContent = await readFilePromise(metaFilePath, 'utf8');
|
124
|
+
const metadata = JSON.parse(metaContent);
|
125
|
+
mimeType = metadata.type || mimeType;
|
126
|
+
} catch (metaError) {
|
127
|
+
console.warn(`Failed to read metadata file: ${metaError.message}, using default MIME type`);
|
128
|
+
// 如果元数据文件不存在,尝试从文件扩展名猜测MIME类型
|
129
|
+
const ext = path.split('.').pop()?.toLowerCase();
|
130
|
+
if (ext) {
|
131
|
+
if (['jpg', 'jpeg'].includes(ext)) mimeType = 'image/jpeg';
|
132
|
+
else
|
133
|
+
switch (ext) {
|
134
|
+
case 'png': {
|
135
|
+
mimeType = 'image/png';
|
136
|
+
break;
|
137
|
+
}
|
138
|
+
case 'gif': {
|
139
|
+
mimeType = 'image/gif';
|
140
|
+
break;
|
141
|
+
}
|
142
|
+
case 'webp': {
|
143
|
+
mimeType = 'image/webp';
|
144
|
+
break;
|
145
|
+
}
|
146
|
+
case 'svg': {
|
147
|
+
mimeType = 'image/svg+xml';
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
case 'pdf': {
|
151
|
+
{
|
152
|
+
mimeType = 'application/pdf';
|
153
|
+
// No default
|
154
|
+
}
|
155
|
+
break;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
return {
|
162
|
+
content: content.buffer as ArrayBuffer,
|
163
|
+
mimeType,
|
164
|
+
};
|
165
|
+
} catch (error) {
|
166
|
+
console.error('File retrieval failed:', error);
|
167
|
+
throw new Error(`File retrieval failed: ${(error as Error).message}`);
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
/**
|
172
|
+
* 删除文件
|
173
|
+
*/
|
174
|
+
async deleteFile(path: string): Promise<{ success: boolean }> {
|
175
|
+
try {
|
176
|
+
// 处理desktop://路径
|
177
|
+
if (!path.startsWith('desktop://')) {
|
178
|
+
throw new Error(`Invalid desktop file path: ${path}`);
|
179
|
+
}
|
180
|
+
|
181
|
+
// 解析路径
|
182
|
+
const relativePath = path.replace('desktop://', '');
|
183
|
+
const filePath = join(this.UPLOADS_DIR, relativePath);
|
184
|
+
|
185
|
+
// 删除文件及其元数据
|
186
|
+
await unlinkPromise(filePath);
|
187
|
+
|
188
|
+
// 尝试删除元数据文件,但不强制要求存在
|
189
|
+
try {
|
190
|
+
await unlinkPromise(`${filePath}.meta`);
|
191
|
+
} catch (error) {
|
192
|
+
console.warn(`Failed to delete metadata file: ${(error as Error).message}`);
|
193
|
+
}
|
194
|
+
|
195
|
+
return { success: true };
|
196
|
+
} catch (error) {
|
197
|
+
console.error('File deletion failed:', error);
|
198
|
+
throw new Error(`File deletion failed: ${(error as Error).message}`);
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
/**
|
203
|
+
* 批量删除文件
|
204
|
+
*/
|
205
|
+
async deleteFiles(paths: string[]): Promise<DeleteFilesResponse> {
|
206
|
+
const errors: { message: string; path: string }[] = [];
|
207
|
+
|
208
|
+
// 并行处理所有删除请求
|
209
|
+
const results = await Promise.allSettled(
|
210
|
+
paths.map(async (path) => {
|
211
|
+
try {
|
212
|
+
await this.deleteFile(path);
|
213
|
+
return { path, success: true };
|
214
|
+
} catch (error) {
|
215
|
+
return {
|
216
|
+
error: (error as Error).message,
|
217
|
+
path,
|
218
|
+
success: false,
|
219
|
+
};
|
220
|
+
}
|
221
|
+
}),
|
222
|
+
);
|
223
|
+
|
224
|
+
// 处理结果
|
225
|
+
results.forEach((result) => {
|
226
|
+
if (result.status === 'rejected') {
|
227
|
+
errors.push({
|
228
|
+
message: `Unexpected error: ${result.reason}`,
|
229
|
+
path: 'unknown',
|
230
|
+
});
|
231
|
+
} else if (!result.value.success) {
|
232
|
+
errors.push({
|
233
|
+
message: result.value.error,
|
234
|
+
path: result.value.path,
|
235
|
+
});
|
236
|
+
}
|
237
|
+
});
|
238
|
+
|
239
|
+
return {
|
240
|
+
success: errors.length === 0,
|
241
|
+
...(errors.length > 0 && { errors }),
|
242
|
+
};
|
243
|
+
}
|
244
|
+
|
245
|
+
async getFilePath(path: string): Promise<string> {
|
246
|
+
// 处理desktop://路径
|
247
|
+
if (!path.startsWith('desktop://')) {
|
248
|
+
throw new Error(`Invalid desktop file path: ${path}`);
|
249
|
+
}
|
250
|
+
|
251
|
+
// 解析路径
|
252
|
+
const relativePath = path.replace('desktop://', '');
|
253
|
+
return join(this.UPLOADS_DIR, relativePath);
|
254
|
+
}
|
255
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
/**
|
2
|
+
* 快捷键操作类型枚举
|
3
|
+
*/
|
4
|
+
export const ShortcutActionEnum = {
|
5
|
+
/**
|
6
|
+
* 显示/隐藏主窗口
|
7
|
+
*/
|
8
|
+
toggleMainWindow: 'toggleMainWindow',
|
9
|
+
} as const;
|
10
|
+
|
11
|
+
export type ShortcutActionType = (typeof ShortcutActionEnum)[keyof typeof ShortcutActionEnum];
|
12
|
+
|
13
|
+
/**
|
14
|
+
* 默认快捷键配置
|
15
|
+
*/
|
16
|
+
export const DEFAULT_SHORTCUTS_CONFIG: Record<ShortcutActionType, string> = {
|
17
|
+
[ShortcutActionEnum.toggleMainWindow]: 'CommandOrControl+E',
|
18
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './config';
|
@@ -0,0 +1,51 @@
|
|
1
|
+
export interface FileResult {
|
2
|
+
contentType?: string;
|
3
|
+
createdTime: Date;
|
4
|
+
isDirectory: boolean;
|
5
|
+
lastAccessTime: Date;
|
6
|
+
// Spotlight specific metadata
|
7
|
+
metadata?: {
|
8
|
+
[key: string]: any;
|
9
|
+
};
|
10
|
+
modifiedTime: Date;
|
11
|
+
name: string;
|
12
|
+
path: string;
|
13
|
+
size: number;
|
14
|
+
type: string;
|
15
|
+
}
|
16
|
+
|
17
|
+
export interface SearchOptions {
|
18
|
+
// Directory options
|
19
|
+
// Content options
|
20
|
+
contentContains?: string;
|
21
|
+
// Created after specific date
|
22
|
+
createdAfter?: Date;
|
23
|
+
|
24
|
+
// Created before specific date
|
25
|
+
createdBefore?: Date;
|
26
|
+
// Whether to return detailed results
|
27
|
+
detailed?: boolean;
|
28
|
+
|
29
|
+
// Limit search to specific directories
|
30
|
+
exclude?: string[]; // Files containing specific content
|
31
|
+
|
32
|
+
// File type options
|
33
|
+
fileTypes?: string[];
|
34
|
+
|
35
|
+
// Basic options
|
36
|
+
keywords: string;
|
37
|
+
limit?: number;
|
38
|
+
// Created before specific date
|
39
|
+
// Advanced options
|
40
|
+
liveUpdate?: boolean;
|
41
|
+
// File type filters, like "public.image", "public.movie"
|
42
|
+
// Time options
|
43
|
+
modifiedAfter?: Date;
|
44
|
+
|
45
|
+
// Modified after specific date
|
46
|
+
modifiedBefore?: Date;
|
47
|
+
// Path options
|
48
|
+
onlyIn?: string; // Whether to return detailed metadata
|
49
|
+
sortBy?: 'name' | 'date' | 'size'; // Result sorting
|
50
|
+
sortDirection?: 'asc' | 'desc'; // Sort direction
|
51
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { DataSyncConfig } from '@lobechat/electron-client-ipc';
|
2
|
+
|
3
|
+
export interface ElectronMainStore {
|
4
|
+
dataSyncConfig: DataSyncConfig;
|
5
|
+
encryptedTokens: {
|
6
|
+
accessToken?: string;
|
7
|
+
refreshToken?: string;
|
8
|
+
};
|
9
|
+
locale: string;
|
10
|
+
shortcuts: Record<string, string>;
|
11
|
+
storagePath: string;
|
12
|
+
}
|
13
|
+
|
14
|
+
export type StoreKey = keyof ElectronMainStore;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { mkdirSync, statSync } from 'node:fs';
|
2
|
+
|
3
|
+
export const makeSureDirExist = (dir: string) => {
|
4
|
+
try {
|
5
|
+
statSync(dir);
|
6
|
+
} catch {
|
7
|
+
// 使用 recursive: true,如果目录已存在则此操作无效果,如果不存在则创建
|
8
|
+
try {
|
9
|
+
mkdirSync(dir, { recursive: true });
|
10
|
+
} catch (mkdirError: any) {
|
11
|
+
// 如果创建目录失败(例如权限问题),则抛出错误
|
12
|
+
throw new Error(`Could not create target directory: ${dir}. Error: ${mkdirError.message}`);
|
13
|
+
}
|
14
|
+
}
|
15
|
+
};
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import debug from 'debug';
|
2
|
+
import electronLog from 'electron-log';
|
3
|
+
|
4
|
+
// 配置 electron-log
|
5
|
+
electronLog.transports.file.level = 'info'; // 生产环境记录 info 及以上级别
|
6
|
+
electronLog.transports.console.level =
|
7
|
+
process.env.NODE_ENV === 'development'
|
8
|
+
? 'debug' // 开发环境显示更多日志
|
9
|
+
: 'warn'; // 生产环境只显示警告和错误
|
10
|
+
|
11
|
+
// 创建命名空间调试器
|
12
|
+
export const createLogger = (namespace: string) => {
|
13
|
+
const debugLogger = debug(namespace);
|
14
|
+
|
15
|
+
return {
|
16
|
+
debug: (message, ...args) => {
|
17
|
+
debugLogger(message, ...args);
|
18
|
+
},
|
19
|
+
error: (message, ...args) => {
|
20
|
+
if (process.env.NODE_ENV === 'production') {
|
21
|
+
electronLog.error(message, ...args);
|
22
|
+
}
|
23
|
+
debugLogger(`ERROR: ${message}`, ...args);
|
24
|
+
},
|
25
|
+
info: (message, ...args) => {
|
26
|
+
if (process.env.NODE_ENV === 'production') {
|
27
|
+
electronLog.info(message, ...args);
|
28
|
+
}
|
29
|
+
debugLogger(`INFO: ${message}`, ...args);
|
30
|
+
},
|
31
|
+
verbose: (message, ...args) => {
|
32
|
+
electronLog.verbose(message, ...args);
|
33
|
+
if (process.env.DEBUG_VERBOSE) {
|
34
|
+
debugLogger(`VERBOSE: ${message}`, ...args);
|
35
|
+
}
|
36
|
+
},
|
37
|
+
warn: (message, ...args) => {
|
38
|
+
if (process.env.NODE_ENV === 'production') {
|
39
|
+
electronLog.warn(message, ...args);
|
40
|
+
}
|
41
|
+
debugLogger(`WARN: ${message}`, ...args);
|
42
|
+
},
|
43
|
+
};
|
44
|
+
};
|