@lobehub/lobehub 2.0.0-next.13 → 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.
Files changed (210) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +1 -1
  4. package/packages/const/src/version.ts +3 -3
  5. package/packages/database/src/repositories/dataImporter/deprecated/__tests__/index.test.ts +2 -1
  6. package/packages/database/src/repositories/dataImporter/deprecated/index.ts +7 -1
  7. package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +9 -0
  8. package/src/app/[variants]/(main)/(mobile)/me/(home)/layout.tsx +0 -2
  9. package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/Actions.tsx +3 -28
  10. package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +0 -2
  11. package/src/app/[variants]/(main)/chat/_layout/Mobile.tsx +1 -5
  12. package/src/app/[variants]/(main)/chat/settings/features/HeaderContent.tsx +2 -62
  13. package/src/app/[variants]/(main)/image/page.tsx +0 -2
  14. package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +23 -24
  15. package/src/app/[variants]/(main)/profile/_layout/Mobile/index.tsx +5 -9
  16. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +0 -2
  17. package/src/app/[variants]/(main)/settings/_layout/Mobile/index.tsx +0 -2
  18. package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +1 -1
  19. package/src/app/[variants]/loading/index.tsx +1 -10
  20. package/src/components/Link.tsx +12 -0
  21. package/src/envs/app.ts +5 -8
  22. package/src/features/DataImporter/index.tsx +15 -60
  23. package/src/features/DevPanel/PostgresViewer/usePgTable.ts +3 -2
  24. package/src/hooks/useInterceptingRoutes.test.ts +21 -3
  25. package/src/libs/trpc/client/index.ts +0 -1
  26. package/src/libs/trpc/client/lambda.ts +8 -5
  27. package/src/server/routers/desktop/mcp.ts +1 -3
  28. package/src/server/routers/lambda/config/index.test.ts +2 -2
  29. package/src/server/routers/tools/mcp.ts +2 -3
  30. package/src/server/routers/tools/search.test.ts +1 -7
  31. package/src/server/routers/tools/search.ts +1 -4
  32. package/src/services/__tests__/tool.test.ts +0 -3
  33. package/src/services/aiModel/index.test.ts +0 -3
  34. package/src/services/aiModel/index.ts +1 -7
  35. package/src/services/aiProvider/index.test.ts +0 -3
  36. package/src/services/aiProvider/index.ts +1 -7
  37. package/src/services/chatGroup/index.ts +1 -10
  38. package/src/services/config.ts +1 -65
  39. package/src/services/export/index.ts +1 -4
  40. package/src/services/file/index.ts +1 -11
  41. package/src/services/import/index.ts +1 -7
  42. package/src/services/message/index.ts +1 -11
  43. package/src/services/plugin/index.ts +1 -11
  44. package/src/services/session/index.ts +1 -11
  45. package/src/services/tableViewer/client.ts +12 -15
  46. package/src/services/thread/index.ts +1 -7
  47. package/src/services/topic/index.ts +1 -11
  48. package/src/services/user/index.ts +1 -13
  49. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -241
  50. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +26 -1
  51. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +3 -1
  52. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +1 -138
  53. package/src/store/user/slices/common/action.test.ts +1 -4
  54. package/src/app/(backend)/trpc/edge/[trpc]/route.ts +0 -26
  55. package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +0 -48
  56. package/src/app/[variants]/(main)/(mobile)/me/data/features/Header.tsx +0 -33
  57. package/src/app/[variants]/(main)/(mobile)/me/data/layout.tsx +0 -13
  58. package/src/app/[variants]/(main)/(mobile)/me/data/loading.tsx +0 -5
  59. package/src/app/[variants]/(main)/(mobile)/me/data/page.tsx +0 -29
  60. package/src/app/[variants]/(main)/chat/features/Migration/DBReader.ts +0 -290
  61. package/src/app/[variants]/(main)/chat/features/Migration/ExportConfigButton.tsx +0 -35
  62. package/src/app/[variants]/(main)/chat/features/Migration/Failed.tsx +0 -120
  63. package/src/app/[variants]/(main)/chat/features/Migration/Modal.tsx +0 -81
  64. package/src/app/[variants]/(main)/chat/features/Migration/Start.tsx +0 -108
  65. package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +0 -71
  66. package/src/app/[variants]/(main)/chat/features/Migration/const.ts +0 -15
  67. package/src/app/[variants]/(main)/chat/features/Migration/index.tsx +0 -50
  68. package/src/app/[variants]/loading/Client/Content.tsx +0 -48
  69. package/src/app/[variants]/loading/Client/Error.tsx +0 -27
  70. package/src/app/[variants]/loading/Client/Redirect.tsx +0 -47
  71. package/src/app/[variants]/loading/Client/index.tsx +0 -22
  72. package/src/components/InnerLink.tsx +0 -20
  73. package/src/database/_deprecated/core/__tests__/db-upgrade.test.ts +0 -42
  74. package/src/database/_deprecated/core/__tests__/db.test.ts +0 -79
  75. package/src/database/_deprecated/core/__tests__/model.test.ts +0 -55
  76. package/src/database/_deprecated/core/db.ts +0 -246
  77. package/src/database/_deprecated/core/index.ts +0 -2
  78. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/input.json +0 -55
  79. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/output.json +0 -60
  80. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.test.ts +0 -14
  81. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.ts +0 -22
  82. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/type.ts +0 -105
  83. package/src/database/_deprecated/core/model.ts +0 -218
  84. package/src/database/_deprecated/core/schemas.ts +0 -88
  85. package/src/database/_deprecated/core/types/db.ts +0 -15
  86. package/src/database/_deprecated/models/__DEBUG.ts +0 -124
  87. package/src/database/_deprecated/models/__tests__/file.test.ts +0 -83
  88. package/src/database/_deprecated/models/__tests__/message.test.ts +0 -426
  89. package/src/database/_deprecated/models/__tests__/plugin.test.ts +0 -81
  90. package/src/database/_deprecated/models/__tests__/session.test.ts +0 -253
  91. package/src/database/_deprecated/models/__tests__/sessionGroup.test.ts +0 -220
  92. package/src/database/_deprecated/models/__tests__/topic.test.ts +0 -523
  93. package/src/database/_deprecated/models/__tests__/user.test.ts +0 -82
  94. package/src/database/_deprecated/models/file.ts +0 -51
  95. package/src/database/_deprecated/models/message.ts +0 -277
  96. package/src/database/_deprecated/models/plugin.ts +0 -62
  97. package/src/database/_deprecated/models/session.ts +0 -271
  98. package/src/database/_deprecated/models/sessionGroup.ts +0 -93
  99. package/src/database/_deprecated/models/topic.ts +0 -250
  100. package/src/database/_deprecated/models/user.ts +0 -69
  101. package/src/database/_deprecated/schemas/files.ts +0 -39
  102. package/src/database/_deprecated/schemas/message.ts +0 -50
  103. package/src/database/_deprecated/schemas/plugin.ts +0 -12
  104. package/src/database/_deprecated/schemas/session.ts +0 -54
  105. package/src/database/_deprecated/schemas/sessionGroup.ts +0 -8
  106. package/src/database/_deprecated/schemas/topic.ts +0 -12
  107. package/src/database/_deprecated/schemas/user.ts +0 -40
  108. package/src/features/DataImporter/_deprecated.ts +0 -43
  109. package/src/features/InitClientDB/EnableModal.tsx +0 -118
  110. package/src/features/InitClientDB/ErrorResult.tsx +0 -143
  111. package/src/features/InitClientDB/InitIndicator.tsx +0 -124
  112. package/src/features/InitClientDB/PGliteIcon.tsx +0 -28
  113. package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +0 -75
  114. package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +0 -98
  115. package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +0 -218
  116. package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +0 -91
  117. package/src/features/InitClientDB/index.tsx +0 -37
  118. package/src/libs/trpc/client/edge.ts +0 -26
  119. package/src/libs/trpc/edge/context.ts +0 -71
  120. package/src/libs/trpc/edge/index.ts +0 -45
  121. package/src/libs/trpc/edge/init.ts +0 -26
  122. package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +0 -75
  123. package/src/libs/trpc/edge/middleware/jwtPayload.ts +0 -14
  124. package/src/migrations/FromV0ToV1.ts +0 -10
  125. package/src/migrations/FromV1ToV2/fixtures/input-v1-session.json +0 -191
  126. package/src/migrations/FromV1ToV2/fixtures/output-v2.json +0 -202
  127. package/src/migrations/FromV1ToV2/index.ts +0 -82
  128. package/src/migrations/FromV1ToV2/migrations.test.ts +0 -224
  129. package/src/migrations/FromV1ToV2/types/v1.ts +0 -78
  130. package/src/migrations/FromV1ToV2/types/v2.ts +0 -52
  131. package/src/migrations/FromV2ToV3/fixtures/input-v2-session.json +0 -72
  132. package/src/migrations/FromV2ToV3/fixtures/output-v3-from-v1.json +0 -203
  133. package/src/migrations/FromV2ToV3/fixtures/output-v3.json +0 -74
  134. package/src/migrations/FromV2ToV3/index.ts +0 -30
  135. package/src/migrations/FromV2ToV3/migrations.test.ts +0 -42
  136. package/src/migrations/FromV2ToV3/types/v3.ts +0 -27
  137. package/src/migrations/FromV3ToV4/fixtures/azure-input-v3.json +0 -79
  138. package/src/migrations/FromV3ToV4/fixtures/azure-output-v4.json +0 -75
  139. package/src/migrations/FromV3ToV4/fixtures/ollama-input-v3.json +0 -85
  140. package/src/migrations/FromV3ToV4/fixtures/ollama-output-v4.json +0 -86
  141. package/src/migrations/FromV3ToV4/fixtures/openai-input-v3.json +0 -77
  142. package/src/migrations/FromV3ToV4/fixtures/openai-output-v4.json +0 -77
  143. package/src/migrations/FromV3ToV4/fixtures/openrouter-input-v3.json +0 -82
  144. package/src/migrations/FromV3ToV4/fixtures/openrouter-output-v4.json +0 -85
  145. package/src/migrations/FromV3ToV4/fixtures/output-v4-from-v1.json +0 -203
  146. package/src/migrations/FromV3ToV4/index.ts +0 -102
  147. package/src/migrations/FromV3ToV4/migrations.test.ts +0 -195
  148. package/src/migrations/FromV3ToV4/types/v3.ts +0 -52
  149. package/src/migrations/FromV3ToV4/types/v4.ts +0 -37
  150. package/src/migrations/FromV4ToV5/fixtures/from-v1-to-v5-output.json +0 -245
  151. package/src/migrations/FromV4ToV5/fixtures/function-input-v4.json +0 -96
  152. package/src/migrations/FromV4ToV5/fixtures/function-output-v5.json +0 -120
  153. package/src/migrations/FromV4ToV5/index.ts +0 -58
  154. package/src/migrations/FromV4ToV5/migrations.test.ts +0 -49
  155. package/src/migrations/FromV4ToV5/types/v4.ts +0 -21
  156. package/src/migrations/FromV4ToV5/types/v5.ts +0 -27
  157. package/src/migrations/FromV5ToV6/fixtures/from-v1-to-v6-output.json +0 -247
  158. package/src/migrations/FromV5ToV6/fixtures/session-input-v5.json +0 -81
  159. package/src/migrations/FromV5ToV6/fixtures/session-output-v6.json +0 -85
  160. package/src/migrations/FromV5ToV6/index.ts +0 -61
  161. package/src/migrations/FromV5ToV6/migrations.test.ts +0 -50
  162. package/src/migrations/FromV5ToV6/types/v5.ts +0 -48
  163. package/src/migrations/FromV5ToV6/types/v6.ts +0 -63
  164. package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +0 -203
  165. package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +0 -103
  166. package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +0 -118
  167. package/src/migrations/FromV6ToV7/index.ts +0 -101
  168. package/src/migrations/FromV6ToV7/migrations.test.ts +0 -64
  169. package/src/migrations/FromV6ToV7/types/v6.ts +0 -61
  170. package/src/migrations/FromV6ToV7/types/v7.ts +0 -69
  171. package/src/migrations/VersionController.test.ts +0 -88
  172. package/src/migrations/VersionController.ts +0 -67
  173. package/src/migrations/index.ts +0 -61
  174. package/src/server/routers/edge/appStatus.ts +0 -3
  175. package/src/server/routers/edge/index.ts +0 -14
  176. package/src/server/routers/edge/upload.ts +0 -16
  177. package/src/services/aiModel/client.ts +0 -70
  178. package/src/services/aiProvider/client.ts +0 -58
  179. package/src/services/baseClientService/index.ts +0 -9
  180. package/src/services/chatGroup/client.ts +0 -63
  181. package/src/services/export/_deprecated.ts +0 -155
  182. package/src/services/export/client.ts +0 -15
  183. package/src/services/file/_deprecated.test.ts +0 -119
  184. package/src/services/file/_deprecated.ts +0 -80
  185. package/src/services/file/client.test.ts +0 -199
  186. package/src/services/file/client.ts +0 -85
  187. package/src/services/import/_deprecated.ts +0 -115
  188. package/src/services/import/client.test.ts +0 -1015
  189. package/src/services/import/client.ts +0 -64
  190. package/src/services/message/_deprecated.test.ts +0 -398
  191. package/src/services/message/_deprecated.ts +0 -168
  192. package/src/services/message/client.test.ts +0 -410
  193. package/src/services/message/client.ts +0 -192
  194. package/src/services/plugin/_deprecated.test.ts +0 -162
  195. package/src/services/plugin/_deprecated.ts +0 -42
  196. package/src/services/plugin/client.test.ts +0 -177
  197. package/src/services/plugin/client.ts +0 -46
  198. package/src/services/session/_deprecated.test.ts +0 -440
  199. package/src/services/session/_deprecated.ts +0 -190
  200. package/src/services/session/client.test.ts +0 -413
  201. package/src/services/session/client.ts +0 -193
  202. package/src/services/thread/client.ts +0 -51
  203. package/src/services/topic/_deprecated.test.ts +0 -245
  204. package/src/services/topic/_deprecated.ts +0 -75
  205. package/src/services/topic/client.ts +0 -89
  206. package/src/services/topic/pglite.test.ts +0 -212
  207. package/src/services/user/_deprecated.test.ts +0 -101
  208. package/src/services/user/_deprecated.ts +0 -70
  209. package/src/services/user/client.test.ts +0 -111
  210. 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
- }