@lobehub/lobehub 2.0.0-next.12 → 2.0.0-next.14
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/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/packages/const/src/version.ts +3 -3
- package/packages/database/src/repositories/dataImporter/deprecated/__tests__/index.test.ts +2 -1
- package/packages/database/src/repositories/dataImporter/deprecated/index.ts +7 -1
- package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +9 -0
- package/src/app/[variants]/(main)/(mobile)/me/(home)/layout.tsx +0 -2
- package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/Actions.tsx +3 -28
- package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +0 -2
- package/src/app/[variants]/(main)/chat/_layout/Mobile.tsx +1 -5
- package/src/app/[variants]/(main)/chat/settings/features/HeaderContent.tsx +2 -62
- package/src/app/[variants]/(main)/image/features/PromptInput/index.tsx +1 -1
- package/src/app/[variants]/(main)/image/page.tsx +0 -2
- package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +23 -24
- package/src/app/[variants]/(main)/profile/_layout/Mobile/index.tsx +5 -9
- package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/_layout/Mobile/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +1 -1
- package/src/app/[variants]/loading/index.tsx +1 -10
- package/src/components/Link.tsx +12 -0
- package/src/envs/app.ts +5 -8
- package/src/features/DataImporter/index.tsx +15 -60
- package/src/features/DevPanel/PostgresViewer/usePgTable.ts +3 -2
- package/src/hooks/useInterceptingRoutes.test.ts +21 -3
- package/src/libs/trpc/client/index.ts +0 -1
- package/src/libs/trpc/client/lambda.ts +8 -5
- package/src/libs/trpc/lambda/context.ts +4 -1
- package/src/server/routers/desktop/mcp.ts +1 -3
- package/src/server/routers/lambda/config/index.test.ts +2 -2
- package/src/server/routers/tools/mcp.ts +2 -3
- package/src/server/routers/tools/search.test.ts +1 -7
- package/src/server/routers/tools/search.ts +1 -4
- package/src/services/__tests__/tool.test.ts +0 -3
- package/src/services/aiModel/index.test.ts +0 -3
- package/src/services/aiModel/index.ts +1 -7
- package/src/services/aiProvider/index.test.ts +0 -3
- package/src/services/aiProvider/index.ts +1 -7
- package/src/services/chatGroup/index.ts +1 -10
- package/src/services/config.ts +1 -65
- package/src/services/export/index.ts +1 -4
- package/src/services/file/index.ts +1 -11
- package/src/services/import/index.ts +1 -7
- package/src/services/message/index.ts +1 -11
- package/src/services/plugin/index.ts +1 -11
- package/src/services/session/index.ts +1 -11
- package/src/services/tableViewer/client.ts +12 -15
- package/src/services/thread/index.ts +1 -7
- package/src/services/topic/index.ts +1 -11
- package/src/services/user/index.ts +1 -13
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -241
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +26 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +3 -1
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +1 -138
- package/src/store/user/slices/common/action.test.ts +1 -4
- package/src/app/(backend)/trpc/edge/[trpc]/route.ts +0 -26
- package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +0 -48
- package/src/app/[variants]/(main)/(mobile)/me/data/features/Header.tsx +0 -33
- package/src/app/[variants]/(main)/(mobile)/me/data/layout.tsx +0 -13
- package/src/app/[variants]/(main)/(mobile)/me/data/loading.tsx +0 -5
- package/src/app/[variants]/(main)/(mobile)/me/data/page.tsx +0 -29
- package/src/app/[variants]/(main)/chat/features/Migration/DBReader.ts +0 -290
- package/src/app/[variants]/(main)/chat/features/Migration/ExportConfigButton.tsx +0 -35
- package/src/app/[variants]/(main)/chat/features/Migration/Failed.tsx +0 -120
- package/src/app/[variants]/(main)/chat/features/Migration/Modal.tsx +0 -81
- package/src/app/[variants]/(main)/chat/features/Migration/Start.tsx +0 -108
- package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +0 -71
- package/src/app/[variants]/(main)/chat/features/Migration/const.ts +0 -15
- package/src/app/[variants]/(main)/chat/features/Migration/index.tsx +0 -50
- package/src/app/[variants]/loading/Client/Content.tsx +0 -48
- package/src/app/[variants]/loading/Client/Error.tsx +0 -27
- package/src/app/[variants]/loading/Client/Redirect.tsx +0 -47
- package/src/app/[variants]/loading/Client/index.tsx +0 -22
- package/src/components/InnerLink.tsx +0 -20
- package/src/database/_deprecated/core/__tests__/db-upgrade.test.ts +0 -42
- package/src/database/_deprecated/core/__tests__/db.test.ts +0 -79
- package/src/database/_deprecated/core/__tests__/model.test.ts +0 -55
- package/src/database/_deprecated/core/db.ts +0 -246
- package/src/database/_deprecated/core/index.ts +0 -2
- package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/input.json +0 -55
- package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/output.json +0 -60
- package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.test.ts +0 -14
- package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.ts +0 -22
- package/src/database/_deprecated/core/migrations/migrateSettingsToUser/type.ts +0 -105
- package/src/database/_deprecated/core/model.ts +0 -218
- package/src/database/_deprecated/core/schemas.ts +0 -88
- package/src/database/_deprecated/core/types/db.ts +0 -15
- package/src/database/_deprecated/models/__DEBUG.ts +0 -124
- package/src/database/_deprecated/models/__tests__/file.test.ts +0 -83
- package/src/database/_deprecated/models/__tests__/message.test.ts +0 -426
- package/src/database/_deprecated/models/__tests__/plugin.test.ts +0 -81
- package/src/database/_deprecated/models/__tests__/session.test.ts +0 -253
- package/src/database/_deprecated/models/__tests__/sessionGroup.test.ts +0 -220
- package/src/database/_deprecated/models/__tests__/topic.test.ts +0 -523
- package/src/database/_deprecated/models/__tests__/user.test.ts +0 -82
- package/src/database/_deprecated/models/file.ts +0 -51
- package/src/database/_deprecated/models/message.ts +0 -277
- package/src/database/_deprecated/models/plugin.ts +0 -62
- package/src/database/_deprecated/models/session.ts +0 -271
- package/src/database/_deprecated/models/sessionGroup.ts +0 -93
- package/src/database/_deprecated/models/topic.ts +0 -250
- package/src/database/_deprecated/models/user.ts +0 -69
- package/src/database/_deprecated/schemas/files.ts +0 -39
- package/src/database/_deprecated/schemas/message.ts +0 -50
- package/src/database/_deprecated/schemas/plugin.ts +0 -12
- package/src/database/_deprecated/schemas/session.ts +0 -54
- package/src/database/_deprecated/schemas/sessionGroup.ts +0 -8
- package/src/database/_deprecated/schemas/topic.ts +0 -12
- package/src/database/_deprecated/schemas/user.ts +0 -40
- package/src/features/DataImporter/_deprecated.ts +0 -43
- package/src/features/InitClientDB/EnableModal.tsx +0 -118
- package/src/features/InitClientDB/ErrorResult.tsx +0 -143
- package/src/features/InitClientDB/InitIndicator.tsx +0 -124
- package/src/features/InitClientDB/PGliteIcon.tsx +0 -28
- package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +0 -75
- package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +0 -98
- package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +0 -218
- package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +0 -91
- package/src/features/InitClientDB/index.tsx +0 -37
- package/src/libs/trpc/client/edge.ts +0 -26
- package/src/libs/trpc/edge/context.ts +0 -71
- package/src/libs/trpc/edge/index.ts +0 -45
- package/src/libs/trpc/edge/init.ts +0 -26
- package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +0 -75
- package/src/libs/trpc/edge/middleware/jwtPayload.ts +0 -14
- package/src/migrations/FromV0ToV1.ts +0 -10
- package/src/migrations/FromV1ToV2/fixtures/input-v1-session.json +0 -191
- package/src/migrations/FromV1ToV2/fixtures/output-v2.json +0 -202
- package/src/migrations/FromV1ToV2/index.ts +0 -82
- package/src/migrations/FromV1ToV2/migrations.test.ts +0 -224
- package/src/migrations/FromV1ToV2/types/v1.ts +0 -78
- package/src/migrations/FromV1ToV2/types/v2.ts +0 -52
- package/src/migrations/FromV2ToV3/fixtures/input-v2-session.json +0 -72
- package/src/migrations/FromV2ToV3/fixtures/output-v3-from-v1.json +0 -203
- package/src/migrations/FromV2ToV3/fixtures/output-v3.json +0 -74
- package/src/migrations/FromV2ToV3/index.ts +0 -30
- package/src/migrations/FromV2ToV3/migrations.test.ts +0 -42
- package/src/migrations/FromV2ToV3/types/v3.ts +0 -27
- package/src/migrations/FromV3ToV4/fixtures/azure-input-v3.json +0 -79
- package/src/migrations/FromV3ToV4/fixtures/azure-output-v4.json +0 -75
- package/src/migrations/FromV3ToV4/fixtures/ollama-input-v3.json +0 -85
- package/src/migrations/FromV3ToV4/fixtures/ollama-output-v4.json +0 -86
- package/src/migrations/FromV3ToV4/fixtures/openai-input-v3.json +0 -77
- package/src/migrations/FromV3ToV4/fixtures/openai-output-v4.json +0 -77
- package/src/migrations/FromV3ToV4/fixtures/openrouter-input-v3.json +0 -82
- package/src/migrations/FromV3ToV4/fixtures/openrouter-output-v4.json +0 -85
- package/src/migrations/FromV3ToV4/fixtures/output-v4-from-v1.json +0 -203
- package/src/migrations/FromV3ToV4/index.ts +0 -102
- package/src/migrations/FromV3ToV4/migrations.test.ts +0 -195
- package/src/migrations/FromV3ToV4/types/v3.ts +0 -52
- package/src/migrations/FromV3ToV4/types/v4.ts +0 -37
- package/src/migrations/FromV4ToV5/fixtures/from-v1-to-v5-output.json +0 -245
- package/src/migrations/FromV4ToV5/fixtures/function-input-v4.json +0 -96
- package/src/migrations/FromV4ToV5/fixtures/function-output-v5.json +0 -120
- package/src/migrations/FromV4ToV5/index.ts +0 -58
- package/src/migrations/FromV4ToV5/migrations.test.ts +0 -49
- package/src/migrations/FromV4ToV5/types/v4.ts +0 -21
- package/src/migrations/FromV4ToV5/types/v5.ts +0 -27
- package/src/migrations/FromV5ToV6/fixtures/from-v1-to-v6-output.json +0 -247
- package/src/migrations/FromV5ToV6/fixtures/session-input-v5.json +0 -81
- package/src/migrations/FromV5ToV6/fixtures/session-output-v6.json +0 -85
- package/src/migrations/FromV5ToV6/index.ts +0 -61
- package/src/migrations/FromV5ToV6/migrations.test.ts +0 -50
- package/src/migrations/FromV5ToV6/types/v5.ts +0 -48
- package/src/migrations/FromV5ToV6/types/v6.ts +0 -63
- package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +0 -203
- package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +0 -103
- package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +0 -118
- package/src/migrations/FromV6ToV7/index.ts +0 -101
- package/src/migrations/FromV6ToV7/migrations.test.ts +0 -64
- package/src/migrations/FromV6ToV7/types/v6.ts +0 -61
- package/src/migrations/FromV6ToV7/types/v7.ts +0 -69
- package/src/migrations/VersionController.test.ts +0 -88
- package/src/migrations/VersionController.ts +0 -67
- package/src/migrations/index.ts +0 -61
- package/src/server/routers/edge/appStatus.ts +0 -3
- package/src/server/routers/edge/index.ts +0 -14
- package/src/server/routers/edge/upload.ts +0 -16
- package/src/services/aiModel/client.ts +0 -70
- package/src/services/aiProvider/client.ts +0 -58
- package/src/services/baseClientService/index.ts +0 -9
- package/src/services/chatGroup/client.ts +0 -63
- package/src/services/export/_deprecated.ts +0 -155
- package/src/services/export/client.ts +0 -15
- package/src/services/file/_deprecated.test.ts +0 -119
- package/src/services/file/_deprecated.ts +0 -80
- package/src/services/file/client.test.ts +0 -199
- package/src/services/file/client.ts +0 -85
- package/src/services/import/_deprecated.ts +0 -115
- package/src/services/import/client.test.ts +0 -1015
- package/src/services/import/client.ts +0 -64
- package/src/services/message/_deprecated.test.ts +0 -398
- package/src/services/message/_deprecated.ts +0 -168
- package/src/services/message/client.test.ts +0 -410
- package/src/services/message/client.ts +0 -192
- package/src/services/plugin/_deprecated.test.ts +0 -162
- package/src/services/plugin/_deprecated.ts +0 -42
- package/src/services/plugin/client.test.ts +0 -177
- package/src/services/plugin/client.ts +0 -46
- package/src/services/session/_deprecated.test.ts +0 -440
- package/src/services/session/_deprecated.ts +0 -190
- package/src/services/session/client.test.ts +0 -413
- package/src/services/session/client.ts +0 -193
- package/src/services/thread/client.ts +0 -51
- package/src/services/topic/_deprecated.test.ts +0 -245
- package/src/services/topic/_deprecated.ts +0 -75
- package/src/services/topic/client.ts +0 -89
- package/src/services/topic/pglite.test.ts +0 -212
- package/src/services/user/_deprecated.test.ts +0 -101
- package/src/services/user/_deprecated.ts +0 -70
- package/src/services/user/client.test.ts +0 -111
- package/src/services/user/client.ts +0 -104
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import type { PartialDeep } from 'type-fest';
|
|
2
|
-
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { UserModel } from '@/database/_deprecated/models/user';
|
|
5
|
-
import { UserPreference } from '@/types/user';
|
|
6
|
-
import { UserSettings } from '@/types/user/settings';
|
|
7
|
-
|
|
8
|
-
import { ClientService } from './_deprecated';
|
|
9
|
-
|
|
10
|
-
vi.mock('@/database/_deprecated/models/user', () => ({
|
|
11
|
-
UserModel: {
|
|
12
|
-
getUser: vi.fn(),
|
|
13
|
-
updateSettings: vi.fn(),
|
|
14
|
-
resetSettings: vi.fn(),
|
|
15
|
-
updateAvatar: vi.fn(),
|
|
16
|
-
},
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
const mockUser = {
|
|
20
|
-
avatar: 'avatar.png',
|
|
21
|
-
settings: { themeMode: 'light' } as unknown as UserSettings,
|
|
22
|
-
uuid: 'user-id',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const mockPreference = {
|
|
26
|
-
useCmdEnterToSend: true,
|
|
27
|
-
} as UserPreference;
|
|
28
|
-
|
|
29
|
-
describe('ClientService', () => {
|
|
30
|
-
let clientService: ClientService;
|
|
31
|
-
|
|
32
|
-
beforeEach(() => {
|
|
33
|
-
vi.clearAllMocks();
|
|
34
|
-
clientService = new ClientService();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should get user state correctly', async () => {
|
|
38
|
-
(UserModel.getUser as Mock).mockResolvedValue(mockUser);
|
|
39
|
-
const spyOn = vi
|
|
40
|
-
.spyOn(clientService['preferenceStorage'], 'getFromLocalStorage')
|
|
41
|
-
.mockResolvedValue(mockPreference);
|
|
42
|
-
|
|
43
|
-
const userState = await clientService.getUserState();
|
|
44
|
-
|
|
45
|
-
expect(userState).toEqual({
|
|
46
|
-
avatar: mockUser.avatar,
|
|
47
|
-
isOnboard: true,
|
|
48
|
-
canEnablePWAGuide: false,
|
|
49
|
-
hasConversation: false,
|
|
50
|
-
canEnableTrace: false,
|
|
51
|
-
preference: mockPreference,
|
|
52
|
-
settings: mockUser.settings,
|
|
53
|
-
userId: mockUser.uuid,
|
|
54
|
-
});
|
|
55
|
-
expect(UserModel.getUser).toHaveBeenCalledTimes(1);
|
|
56
|
-
expect(spyOn).toHaveBeenCalledTimes(1);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should update user settings correctly', async () => {
|
|
60
|
-
const settingsPatch: PartialDeep<UserSettings> = { general: { fontSize: 12 } };
|
|
61
|
-
(UserModel.updateSettings as Mock).mockResolvedValue(undefined);
|
|
62
|
-
|
|
63
|
-
await clientService.updateUserSettings(settingsPatch);
|
|
64
|
-
|
|
65
|
-
expect(UserModel.updateSettings).toHaveBeenCalledWith(settingsPatch);
|
|
66
|
-
expect(UserModel.updateSettings).toHaveBeenCalledTimes(1);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should reset user settings correctly', async () => {
|
|
70
|
-
(UserModel.resetSettings as Mock).mockResolvedValue(undefined);
|
|
71
|
-
|
|
72
|
-
await clientService.resetUserSettings();
|
|
73
|
-
|
|
74
|
-
expect(UserModel.resetSettings).toHaveBeenCalledTimes(1);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should update user avatar correctly', async () => {
|
|
78
|
-
const newAvatar = 'new-avatar.png';
|
|
79
|
-
(UserModel.updateAvatar as Mock).mockResolvedValue(undefined);
|
|
80
|
-
|
|
81
|
-
await clientService.updateAvatar(newAvatar);
|
|
82
|
-
|
|
83
|
-
expect(UserModel.updateAvatar).toHaveBeenCalledWith(newAvatar);
|
|
84
|
-
expect(UserModel.updateAvatar).toHaveBeenCalledTimes(1);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should update user preference correctly', async () => {
|
|
88
|
-
const newPreference = {
|
|
89
|
-
useCmdEnterToSend: false,
|
|
90
|
-
} as UserPreference;
|
|
91
|
-
|
|
92
|
-
const spyOn = vi
|
|
93
|
-
.spyOn(clientService['preferenceStorage'], 'saveToLocalStorage')
|
|
94
|
-
.mockResolvedValue(undefined);
|
|
95
|
-
|
|
96
|
-
await clientService.updatePreference(newPreference);
|
|
97
|
-
|
|
98
|
-
expect(spyOn).toHaveBeenCalledWith(newPreference);
|
|
99
|
-
expect(spyOn).toHaveBeenCalledTimes(1);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { PartialDeep } from 'type-fest';
|
|
2
|
-
|
|
3
|
-
import { MessageModel } from '@/database/_deprecated/models/message';
|
|
4
|
-
import { SessionModel } from '@/database/_deprecated/models/session';
|
|
5
|
-
import { UserModel } from '@/database/_deprecated/models/user';
|
|
6
|
-
import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
|
|
7
|
-
import { UserSettings } from '@/types/user/settings';
|
|
8
|
-
import { AsyncLocalStorage } from '@/utils/localStorage';
|
|
9
|
-
|
|
10
|
-
import { IUserService } from './type';
|
|
11
|
-
|
|
12
|
-
export class ClientService implements IUserService {
|
|
13
|
-
private preferenceStorage: AsyncLocalStorage<UserPreference>;
|
|
14
|
-
|
|
15
|
-
constructor() {
|
|
16
|
-
this.preferenceStorage = new AsyncLocalStorage('LOBE_PREFERENCE');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
getUserRegistrationDuration = async () => {
|
|
20
|
-
throw new Error('Method not implemented.');
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
async getUserState(): Promise<UserInitializationState> {
|
|
24
|
-
const user = await UserModel.getUser();
|
|
25
|
-
const messageCount = await MessageModel.count();
|
|
26
|
-
const sessionCount = await SessionModel.count();
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
avatar: user.avatar,
|
|
30
|
-
canEnablePWAGuide: messageCount >= 4,
|
|
31
|
-
canEnableTrace: messageCount >= 4,
|
|
32
|
-
hasConversation: messageCount > 0 || sessionCount > 0,
|
|
33
|
-
isOnboard: true,
|
|
34
|
-
preference: await this.preferenceStorage.getFromLocalStorage(),
|
|
35
|
-
settings: user.settings as UserSettings,
|
|
36
|
-
userId: user.uuid,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getUserSSOProviders = async () => {
|
|
41
|
-
// Account not exist on next-auth in client mode, no need to implement this method
|
|
42
|
-
return [];
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
unlinkSSOProvider = async () => {
|
|
46
|
-
// Account not exist on next-auth in client mode, no need to implement this method
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
50
|
-
updateUserSettings = async (patch: PartialDeep<UserSettings>, _?: any) => {
|
|
51
|
-
return UserModel.updateSettings(patch);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
resetUserSettings = async () => {
|
|
55
|
-
return UserModel.resetSettings();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
async updateAvatar(avatar: string) {
|
|
59
|
-
await UserModel.updateAvatar(avatar);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async updatePreference(preference: Partial<UserPreference>) {
|
|
63
|
-
await this.preferenceStorage.saveToLocalStorage(preference);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars,unused-imports/no-unused-vars
|
|
67
|
-
async updateGuide(guide: Partial<UserGuide>) {
|
|
68
|
-
throw new Error('Method not implemented.');
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { eq } from 'drizzle-orm';
|
|
2
|
-
import type { PartialDeep } from 'type-fest';
|
|
3
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
-
|
|
5
|
-
import { clientDB, initializeDB } from '@/database/client/db';
|
|
6
|
-
import { userSettings, users } from '@/database/schemas';
|
|
7
|
-
import { UserPreference } from '@/types/user';
|
|
8
|
-
import { UserSettings } from '@/types/user/settings';
|
|
9
|
-
|
|
10
|
-
import { ClientService } from './client';
|
|
11
|
-
|
|
12
|
-
const mockUser = {
|
|
13
|
-
avatar: 'avatar.png',
|
|
14
|
-
settings: { themeMode: 'light' } as unknown as UserSettings,
|
|
15
|
-
uuid: 'user-id',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const mockPreference = {
|
|
19
|
-
useCmdEnterToSend: true,
|
|
20
|
-
} as UserPreference;
|
|
21
|
-
const clientService = new ClientService(mockUser.uuid);
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
vi.clearAllMocks();
|
|
25
|
-
|
|
26
|
-
await initializeDB();
|
|
27
|
-
await clientDB.delete(users);
|
|
28
|
-
|
|
29
|
-
await clientDB
|
|
30
|
-
.insert(users)
|
|
31
|
-
.values({ id: mockUser.uuid, avatar: 'avatar.png' })
|
|
32
|
-
.onConflictDoNothing();
|
|
33
|
-
await clientDB
|
|
34
|
-
.insert(userSettings)
|
|
35
|
-
.values({ id: mockUser.uuid, general: { themeMode: 'light' } });
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
describe('ClientService', () => {
|
|
39
|
-
it('should get user state correctly', async () => {
|
|
40
|
-
const spyOn = vi
|
|
41
|
-
.spyOn(clientService['preferenceStorage'], 'getFromLocalStorage')
|
|
42
|
-
.mockResolvedValue(mockPreference);
|
|
43
|
-
|
|
44
|
-
const userState = await clientService.getUserState();
|
|
45
|
-
|
|
46
|
-
expect(userState).toMatchObject({
|
|
47
|
-
avatar: mockUser.avatar,
|
|
48
|
-
isOnboard: true,
|
|
49
|
-
canEnablePWAGuide: false,
|
|
50
|
-
hasConversation: false,
|
|
51
|
-
canEnableTrace: false,
|
|
52
|
-
preference: mockPreference,
|
|
53
|
-
settings: { general: { themeMode: 'light' } },
|
|
54
|
-
userId: mockUser.uuid,
|
|
55
|
-
});
|
|
56
|
-
expect(spyOn).toHaveBeenCalledTimes(1);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should update user settings correctly', async () => {
|
|
60
|
-
const settingsPatch: PartialDeep<UserSettings> = { general: { fontSize: 12 } };
|
|
61
|
-
|
|
62
|
-
await clientService.updateUserSettings(settingsPatch);
|
|
63
|
-
|
|
64
|
-
const result = await clientDB.query.userSettings.findFirst({
|
|
65
|
-
where: eq(userSettings.id, mockUser.uuid),
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(result).toMatchObject(settingsPatch);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should reset user settings correctly', async () => {
|
|
72
|
-
await clientService.resetUserSettings();
|
|
73
|
-
|
|
74
|
-
const result = await clientDB.query.userSettings.findFirst({
|
|
75
|
-
where: eq(userSettings.id, mockUser.uuid),
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
expect(result).toBeUndefined();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should update user avatar correctly', async () => {
|
|
82
|
-
const newAvatar = 'new-avatar.png';
|
|
83
|
-
|
|
84
|
-
await clientService.updateAvatar(newAvatar);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should update user preference correctly', async () => {
|
|
88
|
-
const newPreference = {
|
|
89
|
-
useCmdEnterToSend: false,
|
|
90
|
-
} as UserPreference;
|
|
91
|
-
|
|
92
|
-
const spyOn = vi
|
|
93
|
-
.spyOn(clientService['preferenceStorage'], 'saveToLocalStorage')
|
|
94
|
-
.mockResolvedValue(undefined);
|
|
95
|
-
|
|
96
|
-
await clientService.updatePreference(newPreference);
|
|
97
|
-
|
|
98
|
-
expect(spyOn).toHaveBeenCalledWith(newPreference);
|
|
99
|
-
expect(spyOn).toHaveBeenCalledTimes(1);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should return empty array for getUserSSOProviders', async () => {
|
|
103
|
-
const providers = await clientService.getUserSSOProviders();
|
|
104
|
-
expect(providers).toEqual([]);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should do nothing when unlinkSSOProvider is called', async () => {
|
|
108
|
-
const result = await clientService.unlinkSSOProvider('google', '123');
|
|
109
|
-
expect(result).toBeUndefined();
|
|
110
|
-
});
|
|
111
|
-
});
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { clientDB } from '@/database/client/db';
|
|
2
|
-
import { MessageModel } from '@/database/models/message';
|
|
3
|
-
import { SessionModel } from '@/database/models/session';
|
|
4
|
-
import { UserModel } from '@/database/models/user';
|
|
5
|
-
import { users } from '@/database/schemas';
|
|
6
|
-
import { BaseClientService } from '@/services/baseClientService';
|
|
7
|
-
import { UserPreference } from '@/types/user';
|
|
8
|
-
import { AsyncLocalStorage } from '@/utils/localStorage';
|
|
9
|
-
|
|
10
|
-
import { IUserService } from './type';
|
|
11
|
-
|
|
12
|
-
export class ClientService extends BaseClientService implements IUserService {
|
|
13
|
-
private preferenceStorage: AsyncLocalStorage<UserPreference>;
|
|
14
|
-
|
|
15
|
-
private get userModel(): UserModel {
|
|
16
|
-
return new UserModel(clientDB as any, this.userId);
|
|
17
|
-
}
|
|
18
|
-
private get messageModel(): MessageModel {
|
|
19
|
-
return new MessageModel(clientDB as any, this.userId);
|
|
20
|
-
}
|
|
21
|
-
private get sessionModel(): SessionModel {
|
|
22
|
-
return new SessionModel(clientDB as any, this.userId);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
constructor(userId?: string) {
|
|
26
|
-
super(userId);
|
|
27
|
-
this.preferenceStorage = new AsyncLocalStorage('LOBE_PREFERENCE');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
getUserRegistrationDuration: IUserService['getUserRegistrationDuration'] = async () => {
|
|
31
|
-
return this.userModel.getUserRegistrationDuration();
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
getUserState: IUserService['getUserState'] = async () => {
|
|
35
|
-
// if user not exist in the db, create one to make sure the user exist
|
|
36
|
-
await this.makeSureUserExist();
|
|
37
|
-
|
|
38
|
-
const state = await this.userModel.getUserState((encryptKeyVaultsStr) =>
|
|
39
|
-
encryptKeyVaultsStr ? JSON.parse(encryptKeyVaultsStr) : {},
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
const messageCount = await this.messageModel.count();
|
|
43
|
-
const sessionCount = await this.sessionModel.count();
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
...state,
|
|
47
|
-
avatar: state.avatar ?? '',
|
|
48
|
-
canEnablePWAGuide: messageCount >= 4,
|
|
49
|
-
canEnableTrace: messageCount >= 4,
|
|
50
|
-
firstName: state.firstName,
|
|
51
|
-
fullName: state.fullName,
|
|
52
|
-
hasConversation: messageCount > 0 || sessionCount > 0,
|
|
53
|
-
isOnboard: true,
|
|
54
|
-
lastName: state.lastName,
|
|
55
|
-
preference: await this.preferenceStorage.getFromLocalStorage(),
|
|
56
|
-
username: state.username,
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
getUserSSOProviders: IUserService['getUserSSOProviders'] = async () => {
|
|
61
|
-
// Account not exist on next-auth in client mode, no need to implement this method
|
|
62
|
-
return [];
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
unlinkSSOProvider: IUserService['unlinkSSOProvider'] = async () => {
|
|
66
|
-
// Account not exist on next-auth in client mode, no need to implement this method
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
updateUserSettings: IUserService['updateUserSettings'] = async (value) => {
|
|
70
|
-
const { keyVaults, ...res } = value;
|
|
71
|
-
|
|
72
|
-
return this.userModel.updateSetting({ ...res, keyVaults: JSON.stringify(keyVaults) });
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
resetUserSettings: IUserService['resetUserSettings'] = async () => {
|
|
76
|
-
return this.userModel.deleteSetting();
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
updateAvatar = async (avatar: string) => {
|
|
80
|
-
await this.userModel.updateUser({ avatar });
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
updatePreference: IUserService['updatePreference'] = async (preference) => {
|
|
84
|
-
await this.preferenceStorage.saveToLocalStorage(preference);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
updateGuide: IUserService['updateGuide'] = async () => {
|
|
88
|
-
throw new Error('Method not implemented.');
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
makeSureUserExist = async () => {
|
|
92
|
-
const existUsers = await clientDB.query.users.findMany();
|
|
93
|
-
|
|
94
|
-
let user: { id: string };
|
|
95
|
-
if (existUsers.length === 0) {
|
|
96
|
-
const result = await clientDB.insert(users).values({ id: this.userId }).returning();
|
|
97
|
-
user = result[0];
|
|
98
|
-
} else {
|
|
99
|
-
user = existUsers[0];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return user;
|
|
103
|
-
};
|
|
104
|
-
}
|