@lobehub/chat 1.139.4 → 1.140.0
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/CHANGELOG.md +50 -0
- package/Dockerfile +3 -0
- package/Dockerfile.database +3 -0
- package/Dockerfile.pglite +3 -0
- package/apps/desktop/src/main/core/App.ts +26 -1
- package/apps/desktop/src/main/core/__tests__/App.test.ts +282 -0
- package/changelog/v1.json +14 -0
- package/docs/development/basic/comfyui-development.mdx +1009 -0
- package/docs/development/basic/comfyui-development.zh-CN.mdx +998 -0
- package/docs/self-hosting/environment-variables/model-provider.mdx +52 -0
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +52 -0
- package/docs/usage/providers/comfyui.mdx +816 -0
- package/docs/usage/providers/comfyui.zh-CN.mdx +816 -0
- package/locales/en-US/modelProvider.json +52 -0
- package/locales/zh-CN/modelProvider.json +52 -0
- package/locales/zh-CN/models.json +52 -0
- package/locales/zh-CN/providers.json +3 -0
- package/package.json +2 -1
- package/packages/model-bank/package.json +1 -0
- package/packages/model-bank/src/aiModels/comfyui.ts +335 -0
- package/packages/model-bank/src/aiModels/index.ts +3 -0
- package/packages/model-bank/src/const/modelProvider.ts +1 -0
- package/packages/model-bank/src/standard-parameters/index.ts +38 -0
- package/packages/model-runtime/src/core/ModelRuntime.ts +8 -1
- package/packages/model-runtime/src/index.ts +2 -0
- package/packages/model-runtime/src/providers/comfyui/__tests__/index.test.ts +521 -0
- package/packages/model-runtime/src/providers/comfyui/auth/AuthManager.ts +116 -0
- package/packages/model-runtime/src/providers/comfyui/index.ts +180 -0
- package/packages/model-runtime/src/runtimeMap.ts +2 -0
- package/packages/model-runtime/src/types/error.ts +8 -0
- package/packages/model-runtime/src/types/image.ts +9 -0
- package/packages/model-runtime/src/utils/comfyuiErrorParser.test.ts +369 -0
- package/packages/model-runtime/src/utils/comfyuiErrorParser.ts +266 -0
- package/packages/model-runtime/src/utils/modelParse.test.ts +10 -1
- package/packages/model-runtime/src/utils/modelParse.ts +7 -0
- package/packages/types/src/aiProvider.ts +11 -1
- package/packages/types/src/asyncTask.ts +4 -0
- package/packages/types/src/auth.ts +8 -0
- package/packages/types/src/user/settings/keyVaults.ts +10 -0
- package/packages/utils/src/base64.test.ts +117 -0
- package/packages/utils/src/base64.ts +44 -0
- package/packages/utils/src/index.ts +2 -0
- package/src/app/(backend)/webapi/create-image/comfyui/route.ts +98 -0
- package/src/app/[variants]/(main)/image/features/GenerationFeed/BatchItem.tsx +1 -0
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/ErrorState.tsx +42 -6
- package/src/app/[variants]/(main)/settings/provider/detail/comfyui/index.tsx +138 -0
- package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +4 -0
- package/src/components/InvalidAPIKey/APIKeyForm/ComfyUIForm.tsx +251 -0
- package/src/components/InvalidAPIKey/APIKeyForm/__tests__/ComfyUIForm.test.tsx +137 -0
- package/src/components/InvalidAPIKey/APIKeyForm/index.tsx +10 -1
- package/src/config/modelProviders/comfyui.ts +40 -0
- package/src/config/modelProviders/index.ts +3 -0
- package/src/envs/llm.ts +16 -0
- package/src/features/Conversation/Error/index.tsx +3 -1
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +1 -1
- package/src/features/Conversation/Messages/User/Actions.tsx +2 -3
- package/src/locales/default/error.ts +14 -0
- package/src/locales/default/modelProvider.ts +52 -0
- package/src/server/globalConfig/genServerAiProviderConfig.ts +1 -1
- package/src/server/modules/ModelRuntime/index.test.ts +66 -0
- package/src/server/modules/ModelRuntime/index.ts +35 -0
- package/src/server/routers/async/image.ts +87 -8
- package/src/server/routers/lambda/comfyui.ts +96 -0
- package/src/server/routers/lambda/index.ts +2 -0
- package/src/server/services/comfyui/__tests__/config/constants.test.ts +146 -0
- package/src/server/services/comfyui/__tests__/config/modelRegistry.test.ts +277 -0
- package/src/server/services/comfyui/__tests__/config/promptToolConst.test.ts +357 -0
- package/src/server/services/comfyui/__tests__/config/systemComponents.test.ts +137 -0
- package/src/server/services/comfyui/__tests__/core/comfyUIAuthService.test.ts +146 -0
- package/src/server/services/comfyui/__tests__/core/comfyUIConnectionService.test.ts +287 -0
- package/src/server/services/comfyui/__tests__/core/comfyuiClient.test.ts +666 -0
- package/src/server/services/comfyui/__tests__/core/errorHandler.test.ts +230 -0
- package/src/server/services/comfyui/__tests__/core/errorHandling.test.ts +134 -0
- package/src/server/services/comfyui/__tests__/core/imageService.test.ts +528 -0
- package/src/server/services/comfyui/__tests__/core/modelResolver.test.ts +454 -0
- package/src/server/services/comfyui/__tests__/core/workflowBuilder.test.ts +294 -0
- package/src/server/services/comfyui/__tests__/fixtures/parameters.fixture.ts +140 -0
- package/src/server/services/comfyui/__tests__/fixtures/supported.fixture.ts +97 -0
- package/src/server/services/comfyui/__tests__/fixtures/testModels.ts +64 -0
- package/src/server/services/comfyui/__tests__/helpers/mockContext.ts +98 -0
- package/src/server/services/comfyui/__tests__/helpers/realConfigData.ts +80 -0
- package/src/server/services/comfyui/__tests__/helpers/testSetup.ts +219 -0
- package/src/server/services/comfyui/__tests__/integration/parameterMapping.test.ts +138 -0
- package/src/server/services/comfyui/__tests__/integration/parameterTransformation.test.ts +88 -0
- package/src/server/services/comfyui/__tests__/integration/serviceIntegration.test.ts +160 -0
- package/src/server/services/comfyui/__tests__/setup/unifiedMocks.ts +48 -0
- package/src/server/services/comfyui/__tests__/utils/cacheManager.test.ts +571 -0
- package/src/server/services/comfyui/__tests__/utils/componentInfo.test.ts +329 -0
- package/src/server/services/comfyui/__tests__/utils/imageResizer.test.ts +424 -0
- package/src/server/services/comfyui/__tests__/utils/promptSplitter.test.ts +191 -0
- package/src/server/services/comfyui/__tests__/utils/weightDType.test.ts +192 -0
- package/src/server/services/comfyui/__tests__/utils/workflowDetector.test.ts +507 -0
- package/src/server/services/comfyui/__tests__/workflows/flux-kontext.test.ts +381 -0
- package/src/server/services/comfyui/__tests__/workflows/simple-sd.test.ts +558 -0
- package/src/server/services/comfyui/__tests__/workflows/unified-workflows.test.ts +392 -0
- package/src/server/services/comfyui/config/constants.ts +110 -0
- package/src/server/services/comfyui/config/fluxModelRegistry.ts +843 -0
- package/src/server/services/comfyui/config/modelRegistry.ts +48 -0
- package/src/server/services/comfyui/config/promptToolConst.ts +624 -0
- package/src/server/services/comfyui/config/sdModelRegistry.ts +508 -0
- package/src/server/services/comfyui/config/systemComponents.ts +385 -0
- package/src/server/services/comfyui/config/workflowRegistry.ts +70 -0
- package/src/server/services/comfyui/core/comfyUIAuthService.ts +145 -0
- package/src/server/services/comfyui/core/comfyUIClientService.ts +249 -0
- package/src/server/services/comfyui/core/comfyUIConnectionService.ts +136 -0
- package/src/server/services/comfyui/core/errorHandlerService.ts +538 -0
- package/src/server/services/comfyui/core/imageService.ts +272 -0
- package/src/server/services/comfyui/core/modelResolverService.ts +290 -0
- package/src/server/services/comfyui/core/workflowBuilderService.ts +79 -0
- package/src/server/services/comfyui/errors/base.ts +21 -0
- package/src/server/services/comfyui/errors/configError.ts +26 -0
- package/src/server/services/comfyui/errors/index.ts +29 -0
- package/src/server/services/comfyui/errors/modelResolverError.ts +42 -0
- package/src/server/services/comfyui/errors/servicesError.ts +42 -0
- package/src/server/services/comfyui/errors/typeGuards.ts +12 -0
- package/src/server/services/comfyui/errors/utilsError.ts +34 -0
- package/src/server/services/comfyui/errors/workflowError.ts +26 -0
- package/src/server/services/comfyui/types/index.ts +42 -0
- package/src/server/services/comfyui/utils/cacheManager.ts +92 -0
- package/src/server/services/comfyui/utils/componentInfo.ts +86 -0
- package/src/server/services/comfyui/utils/imageResizer.ts +173 -0
- package/src/server/services/comfyui/utils/promptSplitter.ts +132 -0
- package/src/server/services/comfyui/utils/staticModelLookup.ts +138 -0
- package/src/server/services/comfyui/utils/weightDType.ts +18 -0
- package/src/server/services/comfyui/utils/workflowDetector.ts +60 -0
- package/src/server/services/comfyui/utils/workflowUtils.ts +73 -0
- package/src/server/services/comfyui/workflows/flux-dev.ts +234 -0
- package/src/server/services/comfyui/workflows/flux-kontext.ts +308 -0
- package/src/server/services/comfyui/workflows/flux-schnell.ts +169 -0
- package/src/server/services/comfyui/workflows/index.ts +5 -0
- package/src/server/services/comfyui/workflows/sd35.ts +227 -0
- package/src/server/services/comfyui/workflows/simple-sd.ts +273 -0
- package/src/server/services/generation/index.test.ts +39 -4
- package/src/server/services/generation/index.ts +37 -5
- package/src/services/_auth.ts +15 -2
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 1.140.0](https://github.com/lobehub/lobe-chat/compare/v1.139.5...v1.140.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-10-21**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Add ComfyUI integration Phase1(RFC-128).
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Add ComfyUI integration Phase1(RFC-128), closes [#9043](https://github.com/lobehub/lobe-chat/issues/9043) ([15ffe28](https://github.com/lobehub/lobe-chat/commit/15ffe28))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.139.5](https://github.com/lobehub/lobe-chat/compare/v1.139.4...v1.139.5)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2025-10-21**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **desktop**: Fix desktop open error in some edge cases.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **desktop**: Fix desktop open error in some edge cases, closes [#9813](https://github.com/lobehub/lobe-chat/issues/9813) ([6334f62](https://github.com/lobehub/lobe-chat/commit/6334f62))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.139.4](https://github.com/lobehub/lobe-chat/compare/v1.139.3...v1.139.4)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2025-10-21**</sup>
|
package/Dockerfile
CHANGED
|
@@ -165,6 +165,9 @@ ENV \
|
|
|
165
165
|
CLOUDFLARE_API_KEY="" CLOUDFLARE_BASE_URL_OR_ACCOUNT_ID="" CLOUDFLARE_MODEL_LIST="" \
|
|
166
166
|
# Cohere
|
|
167
167
|
COHERE_API_KEY="" COHERE_MODEL_LIST="" COHERE_PROXY_URL="" \
|
|
168
|
+
# ComfyUI
|
|
169
|
+
COMFYUI_BASE_URL="" COMFYUI_AUTH_TYPE="" \
|
|
170
|
+
COMFYUI_API_KEY="" COMFYUI_USERNAME="" COMFYUI_PASSWORD="" COMFYUI_CUSTOM_HEADERS="" \
|
|
168
171
|
# DeepSeek
|
|
169
172
|
DEEPSEEK_API_KEY="" DEEPSEEK_MODEL_LIST="" \
|
|
170
173
|
# Fireworks AI
|
package/Dockerfile.database
CHANGED
|
@@ -218,6 +218,9 @@ ENV \
|
|
|
218
218
|
CLOUDFLARE_API_KEY="" CLOUDFLARE_BASE_URL_OR_ACCOUNT_ID="" CLOUDFLARE_MODEL_LIST="" \
|
|
219
219
|
# Cohere
|
|
220
220
|
COHERE_API_KEY="" COHERE_MODEL_LIST="" COHERE_PROXY_URL="" \
|
|
221
|
+
# ComfyUI
|
|
222
|
+
COMFYUI_BASE_URL="" COMFYUI_AUTH_TYPE="" \
|
|
223
|
+
COMFYUI_API_KEY="" COMFYUI_USERNAME="" COMFYUI_PASSWORD="" COMFYUI_CUSTOM_HEADERS="" \
|
|
221
224
|
# DeepSeek
|
|
222
225
|
DEEPSEEK_API_KEY="" DEEPSEEK_MODEL_LIST="" \
|
|
223
226
|
# Fireworks AI
|
package/Dockerfile.pglite
CHANGED
|
@@ -167,6 +167,9 @@ ENV \
|
|
|
167
167
|
CLOUDFLARE_API_KEY="" CLOUDFLARE_BASE_URL_OR_ACCOUNT_ID="" CLOUDFLARE_MODEL_LIST="" \
|
|
168
168
|
# Cohere
|
|
169
169
|
COHERE_API_KEY="" COHERE_MODEL_LIST="" COHERE_PROXY_URL="" \
|
|
170
|
+
# ComfyUI
|
|
171
|
+
COMFYUI_BASE_URL="" COMFYUI_AUTH_TYPE="" \
|
|
172
|
+
COMFYUI_API_KEY="" COMFYUI_USERNAME="" COMFYUI_PASSWORD="" COMFYUI_CUSTOM_HEADERS="" \
|
|
170
173
|
# DeepSeek
|
|
171
174
|
DEEPSEEK_API_KEY="" DEEPSEEK_MODEL_LIST="" \
|
|
172
175
|
# Fireworks AI
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ElectronIPCEventHandler, ElectronIPCServer } from '@lobechat/electron-server-ipc';
|
|
2
2
|
import { Session, app, ipcMain, protocol } from 'electron';
|
|
3
3
|
import { macOS, windows } from 'electron-is';
|
|
4
|
+
import { pathExistsSync, remove } from 'fs-extra';
|
|
4
5
|
import os from 'node:os';
|
|
5
6
|
import { join } from 'node:path';
|
|
6
7
|
|
|
7
8
|
import { name } from '@/../../package.json';
|
|
8
|
-
import { buildDir, nextStandaloneDir } from '@/const/dir';
|
|
9
|
+
import { buildDir, LOCAL_DATABASE_DIR, nextStandaloneDir } from '@/const/dir';
|
|
9
10
|
import { isDev } from '@/const/env';
|
|
10
11
|
import { IControlModule } from '@/controllers';
|
|
11
12
|
import { IServiceModule } from '@/services';
|
|
@@ -129,6 +130,9 @@ export class App {
|
|
|
129
130
|
|
|
130
131
|
this.initDevBranding();
|
|
131
132
|
|
|
133
|
+
// Clean up stale database lock file before starting IPC server
|
|
134
|
+
await this.cleanupDatabaseLock();
|
|
135
|
+
|
|
132
136
|
// ==============
|
|
133
137
|
await this.ipcServer.start();
|
|
134
138
|
logger.debug('IPC server started');
|
|
@@ -371,6 +375,27 @@ export class App {
|
|
|
371
375
|
}
|
|
372
376
|
};
|
|
373
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Clean up stale database lock file from previous crashes or abnormal exits
|
|
380
|
+
*/
|
|
381
|
+
private cleanupDatabaseLock = async () => {
|
|
382
|
+
try {
|
|
383
|
+
const dbPath = join(this.appStoragePath, LOCAL_DATABASE_DIR);
|
|
384
|
+
const lockPath = `${dbPath}.lock`;
|
|
385
|
+
|
|
386
|
+
if (pathExistsSync(lockPath)) {
|
|
387
|
+
logger.info(`Cleaning up stale database lock file: ${lockPath}`);
|
|
388
|
+
await remove(lockPath);
|
|
389
|
+
logger.info('Database lock file removed successfully');
|
|
390
|
+
} else {
|
|
391
|
+
logger.debug('No database lock file found, skipping cleanup');
|
|
392
|
+
}
|
|
393
|
+
} catch (error) {
|
|
394
|
+
logger.error('Failed to cleanup database lock file:', error);
|
|
395
|
+
// Non-fatal error, allow application to continue
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
374
399
|
private registerNextHandler() {
|
|
375
400
|
logger.debug('Registering Next.js handler');
|
|
376
401
|
const handler = createHandler({
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { app } from 'electron';
|
|
2
|
+
import { pathExistsSync, remove } from 'fs-extra';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
|
|
6
|
+
import { LOCAL_DATABASE_DIR } from '@/const/dir';
|
|
7
|
+
|
|
8
|
+
// Mock electron modules
|
|
9
|
+
vi.mock('electron', () => ({
|
|
10
|
+
app: {
|
|
11
|
+
getAppPath: vi.fn(() => '/mock/app/path'),
|
|
12
|
+
getLocale: vi.fn(() => 'en-US'),
|
|
13
|
+
getPath: vi.fn(() => '/mock/user/path'),
|
|
14
|
+
requestSingleInstanceLock: vi.fn(() => true),
|
|
15
|
+
whenReady: vi.fn(() => Promise.resolve()),
|
|
16
|
+
on: vi.fn(),
|
|
17
|
+
commandLine: {
|
|
18
|
+
appendSwitch: vi.fn(),
|
|
19
|
+
},
|
|
20
|
+
dock: {
|
|
21
|
+
setIcon: vi.fn(),
|
|
22
|
+
},
|
|
23
|
+
exit: vi.fn(),
|
|
24
|
+
},
|
|
25
|
+
ipcMain: {
|
|
26
|
+
handle: vi.fn(),
|
|
27
|
+
},
|
|
28
|
+
nativeTheme: {
|
|
29
|
+
on: vi.fn(),
|
|
30
|
+
shouldUseDarkColors: false,
|
|
31
|
+
},
|
|
32
|
+
protocol: {
|
|
33
|
+
registerSchemesAsPrivileged: vi.fn(),
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
// Mock logger
|
|
38
|
+
vi.mock('@/utils/logger', () => ({
|
|
39
|
+
createLogger: () => ({
|
|
40
|
+
debug: vi.fn(),
|
|
41
|
+
info: vi.fn(),
|
|
42
|
+
warn: vi.fn(),
|
|
43
|
+
error: vi.fn(),
|
|
44
|
+
}),
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
// Mock fs-extra module
|
|
48
|
+
vi.mock('fs-extra', async () => {
|
|
49
|
+
const actual = await vi.importActual('fs-extra');
|
|
50
|
+
return {
|
|
51
|
+
...actual,
|
|
52
|
+
pathExistsSync: vi.fn(),
|
|
53
|
+
remove: vi.fn(),
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Mock common/routes
|
|
58
|
+
vi.mock('~common/routes', () => ({
|
|
59
|
+
findMatchingRoute: vi.fn(),
|
|
60
|
+
extractSubPath: vi.fn(),
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
// Mock other dependencies
|
|
64
|
+
vi.mock('electron-is', () => ({
|
|
65
|
+
macOS: vi.fn(() => false),
|
|
66
|
+
windows: vi.fn(() => false),
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
vi.mock('fix-path', () => ({
|
|
70
|
+
default: vi.fn(),
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
vi.mock('@/const/env', () => ({
|
|
74
|
+
isDev: false,
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
vi.mock('@/const/dir', () => ({
|
|
78
|
+
buildDir: '/mock/build',
|
|
79
|
+
nextStandaloneDir: '/mock/standalone',
|
|
80
|
+
LOCAL_DATABASE_DIR: 'lobehub-local-db',
|
|
81
|
+
appStorageDir: '/mock/storage/path',
|
|
82
|
+
userDataDir: '/mock/user/data',
|
|
83
|
+
DB_SCHEMA_HASH_FILENAME: 'lobehub-local-db-schema-hash',
|
|
84
|
+
FILE_STORAGE_DIR: 'file-storage',
|
|
85
|
+
INSTALL_PLUGINS_DIR: 'plugins',
|
|
86
|
+
LOCAL_STORAGE_URL_PREFIX: '/lobe-desktop-file',
|
|
87
|
+
}));
|
|
88
|
+
|
|
89
|
+
vi.mock('@lobechat/electron-server-ipc', () => ({
|
|
90
|
+
ElectronIPCServer: vi.fn().mockImplementation(() => ({
|
|
91
|
+
start: vi.fn().mockResolvedValue(undefined),
|
|
92
|
+
})),
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
// Mock all infrastructure managers
|
|
96
|
+
vi.mock('../infrastructure/I18nManager', () => ({
|
|
97
|
+
I18nManager: vi.fn().mockImplementation(() => ({
|
|
98
|
+
init: vi.fn().mockResolvedValue(undefined),
|
|
99
|
+
})),
|
|
100
|
+
}));
|
|
101
|
+
|
|
102
|
+
vi.mock('../infrastructure/StoreManager', () => ({
|
|
103
|
+
StoreManager: vi.fn().mockImplementation(() => ({
|
|
104
|
+
get: vi.fn((key) => {
|
|
105
|
+
if (key === 'storagePath') return '/mock/storage/path';
|
|
106
|
+
return undefined;
|
|
107
|
+
}),
|
|
108
|
+
set: vi.fn(),
|
|
109
|
+
})),
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
vi.mock('../infrastructure/StaticFileServerManager', () => ({
|
|
113
|
+
StaticFileServerManager: vi.fn().mockImplementation(() => ({
|
|
114
|
+
initialize: vi.fn().mockResolvedValue(undefined),
|
|
115
|
+
destroy: vi.fn(),
|
|
116
|
+
})),
|
|
117
|
+
}));
|
|
118
|
+
|
|
119
|
+
vi.mock('../infrastructure/UpdaterManager', () => ({
|
|
120
|
+
UpdaterManager: vi.fn().mockImplementation(() => ({
|
|
121
|
+
initialize: vi.fn().mockResolvedValue(undefined),
|
|
122
|
+
})),
|
|
123
|
+
}));
|
|
124
|
+
|
|
125
|
+
vi.mock('../infrastructure/ProtocolManager', () => ({
|
|
126
|
+
ProtocolManager: vi.fn().mockImplementation(() => ({
|
|
127
|
+
initialize: vi.fn(),
|
|
128
|
+
processPendingUrls: vi.fn().mockResolvedValue(undefined),
|
|
129
|
+
})),
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
vi.mock('../browser/BrowserManager', () => ({
|
|
133
|
+
BrowserManager: vi.fn().mockImplementation(() => ({
|
|
134
|
+
initializeBrowsers: vi.fn(),
|
|
135
|
+
getIdentifierByWebContents: vi.fn(),
|
|
136
|
+
})),
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
vi.mock('../ui/MenuManager', () => ({
|
|
140
|
+
MenuManager: vi.fn().mockImplementation(() => ({
|
|
141
|
+
initialize: vi.fn(),
|
|
142
|
+
})),
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
vi.mock('../ui/ShortcutManager', () => ({
|
|
146
|
+
ShortcutManager: vi.fn().mockImplementation(() => ({
|
|
147
|
+
initialize: vi.fn(),
|
|
148
|
+
})),
|
|
149
|
+
}));
|
|
150
|
+
|
|
151
|
+
vi.mock('../ui/TrayManager', () => ({
|
|
152
|
+
TrayManager: vi.fn().mockImplementation(() => ({
|
|
153
|
+
initializeTrays: vi.fn(),
|
|
154
|
+
destroyAll: vi.fn(),
|
|
155
|
+
})),
|
|
156
|
+
}));
|
|
157
|
+
|
|
158
|
+
vi.mock('@/utils/next-electron-rsc', () => ({
|
|
159
|
+
createHandler: vi.fn(() => ({
|
|
160
|
+
createInterceptor: vi.fn(),
|
|
161
|
+
registerCustomHandler: vi.fn(),
|
|
162
|
+
})),
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
// Mock controllers and services
|
|
166
|
+
vi.mock('../../controllers/*Ctr.ts', () => ({}));
|
|
167
|
+
vi.mock('../../services/*Srv.ts', () => ({}));
|
|
168
|
+
|
|
169
|
+
// Import after mocks are set up
|
|
170
|
+
import { App } from '../App';
|
|
171
|
+
|
|
172
|
+
describe('App - Database Lock Cleanup', () => {
|
|
173
|
+
let appInstance: App;
|
|
174
|
+
let mockLockPath: string;
|
|
175
|
+
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
vi.clearAllMocks();
|
|
178
|
+
|
|
179
|
+
// Mock glob imports to return empty arrays
|
|
180
|
+
(import.meta as any).glob = vi.fn(() => ({}));
|
|
181
|
+
|
|
182
|
+
mockLockPath = join('/mock/storage/path', LOCAL_DATABASE_DIR) + '.lock';
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
afterEach(() => {
|
|
186
|
+
vi.clearAllMocks();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('bootstrap - database lock cleanup', () => {
|
|
190
|
+
it('should remove stale lock file if it exists during bootstrap', async () => {
|
|
191
|
+
// Setup: simulate existing lock file
|
|
192
|
+
vi.mocked(pathExistsSync).mockReturnValue(true);
|
|
193
|
+
vi.mocked(remove).mockResolvedValue(undefined);
|
|
194
|
+
|
|
195
|
+
// Create app instance
|
|
196
|
+
appInstance = new App();
|
|
197
|
+
|
|
198
|
+
// Call bootstrap which should trigger cleanup
|
|
199
|
+
await appInstance.bootstrap();
|
|
200
|
+
|
|
201
|
+
// Verify: lock file check was called
|
|
202
|
+
expect(pathExistsSync).toHaveBeenCalledWith(mockLockPath);
|
|
203
|
+
|
|
204
|
+
// Verify: lock file was removed
|
|
205
|
+
expect(remove).toHaveBeenCalledWith(mockLockPath);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should not attempt to remove lock file if it does not exist', async () => {
|
|
209
|
+
// Setup: no lock file exists
|
|
210
|
+
vi.mocked(pathExistsSync).mockReturnValue(false);
|
|
211
|
+
|
|
212
|
+
// Create app instance
|
|
213
|
+
appInstance = new App();
|
|
214
|
+
|
|
215
|
+
// Call bootstrap
|
|
216
|
+
await appInstance.bootstrap();
|
|
217
|
+
|
|
218
|
+
// Verify: lock file check was called
|
|
219
|
+
expect(pathExistsSync).toHaveBeenCalledWith(mockLockPath);
|
|
220
|
+
|
|
221
|
+
// Verify: remove was NOT called since file doesn't exist
|
|
222
|
+
expect(remove).not.toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should continue bootstrap even if lock cleanup fails', async () => {
|
|
226
|
+
// Setup: simulate lock file exists but cleanup fails
|
|
227
|
+
vi.mocked(pathExistsSync).mockReturnValue(true);
|
|
228
|
+
vi.mocked(remove).mockRejectedValue(new Error('Permission denied'));
|
|
229
|
+
|
|
230
|
+
// Create app instance
|
|
231
|
+
appInstance = new App();
|
|
232
|
+
|
|
233
|
+
// Bootstrap should not throw even if cleanup fails
|
|
234
|
+
await expect(appInstance.bootstrap()).resolves.not.toThrow();
|
|
235
|
+
|
|
236
|
+
// Verify: cleanup was attempted
|
|
237
|
+
expect(pathExistsSync).toHaveBeenCalledWith(mockLockPath);
|
|
238
|
+
expect(remove).toHaveBeenCalledWith(mockLockPath);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should clean up lock file before starting IPC server', async () => {
|
|
242
|
+
// Setup
|
|
243
|
+
vi.mocked(pathExistsSync).mockReturnValue(true);
|
|
244
|
+
const callOrder: string[] = [];
|
|
245
|
+
|
|
246
|
+
vi.mocked(remove).mockImplementation(async () => {
|
|
247
|
+
callOrder.push('remove');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Mock IPC server start to track call order
|
|
251
|
+
const { ElectronIPCServer } = await import('@lobechat/electron-server-ipc');
|
|
252
|
+
const mockStart = vi.fn().mockImplementation(() => {
|
|
253
|
+
callOrder.push('ipcServer.start');
|
|
254
|
+
return Promise.resolve();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
vi.mocked(ElectronIPCServer).mockImplementation(
|
|
258
|
+
() =>
|
|
259
|
+
({
|
|
260
|
+
start: mockStart,
|
|
261
|
+
}) as any,
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
// Create app instance and bootstrap
|
|
265
|
+
appInstance = new App();
|
|
266
|
+
await appInstance.bootstrap();
|
|
267
|
+
|
|
268
|
+
// Verify: cleanup happens before IPC server starts
|
|
269
|
+
expect(callOrder).toEqual(['remove', 'ipcServer.start']);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('appStoragePath', () => {
|
|
274
|
+
it('should return storage path from store manager', () => {
|
|
275
|
+
appInstance = new App();
|
|
276
|
+
|
|
277
|
+
const storagePath = appInstance.appStoragePath;
|
|
278
|
+
|
|
279
|
+
expect(storagePath).toBe('/mock/storage/path');
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"features": [
|
|
5
|
+
"Add ComfyUI integration Phase1(RFC-128)."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2025-10-21",
|
|
9
|
+
"version": "1.140.0"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {},
|
|
13
|
+
"date": "2025-10-21",
|
|
14
|
+
"version": "1.139.5"
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"children": {
|
|
4
18
|
"fixes": [
|