@lobehub/chat 1.36.46 → 1.37.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.ja-JP.md +8 -8
  3. package/README.md +8 -8
  4. package/README.zh-CN.md +8 -8
  5. package/changelog/v1.json +18 -0
  6. package/next.config.mjs +4 -1
  7. package/package.json +5 -3
  8. package/scripts/migrateClientDB/compile-migrations.ts +14 -0
  9. package/src/app/(main)/(mobile)/me/(home)/layout.tsx +2 -0
  10. package/src/app/(main)/chat/_layout/Desktop/index.tsx +3 -2
  11. package/src/app/(main)/chat/_layout/Mobile.tsx +5 -3
  12. package/src/app/(main)/chat/features/Migration/DBReader.ts +290 -0
  13. package/src/app/(main)/chat/features/Migration/UpgradeButton.tsx +4 -8
  14. package/src/app/(main)/chat/features/Migration/index.tsx +26 -15
  15. package/src/app/(main)/settings/_layout/Desktop/index.tsx +2 -0
  16. package/src/app/loading/Client/Content.tsx +11 -1
  17. package/src/app/loading/Client/Error.tsx +27 -0
  18. package/src/app/loading/stage.ts +8 -0
  19. package/src/components/FullscreenLoading/index.tsx +4 -3
  20. package/src/const/version.ts +1 -0
  21. package/src/database/client/db.test.ts +172 -0
  22. package/src/database/client/db.ts +246 -0
  23. package/src/database/client/migrations.json +289 -0
  24. package/src/features/InitClientDB/EnableModal.tsx +111 -0
  25. package/src/features/InitClientDB/ErrorResult.tsx +125 -0
  26. package/src/features/InitClientDB/InitIndicator.tsx +124 -0
  27. package/src/features/InitClientDB/PGliteSVG.tsx +22 -0
  28. package/src/features/InitClientDB/index.tsx +37 -0
  29. package/src/hooks/useCheckPluginsIsInstalled.ts +2 -2
  30. package/src/hooks/useFetchInstalledPlugins.ts +2 -2
  31. package/src/hooks/useFetchMessages.ts +2 -2
  32. package/src/hooks/useFetchSessions.ts +2 -2
  33. package/src/hooks/useFetchThreads.ts +2 -2
  34. package/src/hooks/useFetchTopics.ts +2 -2
  35. package/src/layout/GlobalProvider/StoreInitialization.tsx +2 -2
  36. package/src/services/baseClientService/index.ts +9 -0
  37. package/src/services/debug.ts +32 -34
  38. package/src/services/file/{client.test.ts → _deprecated.test.ts} +1 -1
  39. package/src/services/file/index.ts +6 -2
  40. package/src/services/file/pglite.test.ts +198 -0
  41. package/src/services/file/pglite.ts +84 -0
  42. package/src/services/file/type.ts +4 -3
  43. package/src/services/github.ts +17 -0
  44. package/src/services/import/index.ts +6 -2
  45. package/src/services/import/pglite.test.ts +997 -0
  46. package/src/services/import/pglite.ts +34 -0
  47. package/src/services/message/{client.test.ts → _deprecated.test.ts} +1 -1
  48. package/src/services/message/{client.ts → _deprecated.ts} +2 -0
  49. package/src/services/message/index.ts +6 -2
  50. package/src/services/message/pglite.test.ts +430 -0
  51. package/src/services/message/pglite.ts +118 -0
  52. package/src/services/message/server.ts +9 -9
  53. package/src/services/message/type.ts +3 -4
  54. package/src/services/plugin/{client.test.ts → _deprecated.test.ts} +1 -1
  55. package/src/services/plugin/index.ts +6 -2
  56. package/src/services/plugin/pglite.test.ts +175 -0
  57. package/src/services/plugin/pglite.ts +51 -0
  58. package/src/services/session/{client.test.ts → _deprecated.test.ts} +1 -1
  59. package/src/services/session/{client.ts → _deprecated.ts} +1 -1
  60. package/src/services/session/index.ts +6 -2
  61. package/src/services/session/pglite.test.ts +411 -0
  62. package/src/services/session/pglite.ts +184 -0
  63. package/src/services/session/type.ts +14 -1
  64. package/src/services/topic/client.test.ts +1 -1
  65. package/src/services/topic/index.ts +6 -3
  66. package/src/services/topic/pglite.test.ts +212 -0
  67. package/src/services/topic/pglite.ts +85 -0
  68. package/src/services/user/{client.test.ts → _deprecated.test.ts} +1 -2
  69. package/src/services/user/index.ts +8 -2
  70. package/src/services/user/pglite.test.ts +98 -0
  71. package/src/services/user/pglite.ts +92 -0
  72. package/src/store/chat/slices/builtinTool/action.test.ts +4 -5
  73. package/src/store/global/actions/clientDb.ts +51 -0
  74. package/src/store/global/initialState.ts +13 -0
  75. package/src/store/global/selectors.ts +24 -3
  76. package/src/store/global/store.ts +3 -1
  77. package/src/store/session/slices/sessionGroup/reducer.test.ts +6 -6
  78. package/src/store/user/slices/common/action.test.ts +1 -1
  79. package/src/store/user/slices/common/action.ts +2 -4
  80. package/src/types/clientDB.ts +29 -0
  81. package/src/types/importer.ts +17 -5
  82. package/src/types/meta.ts +0 -9
  83. package/src/types/session/sessionGroup.ts +3 -3
  84. package/src/services/message/index.test.ts +0 -48
  85. /package/src/services/file/{client.ts → _deprecated.ts} +0 -0
  86. /package/src/services/import/{client.ts → _deprecated.ts} +0 -0
  87. /package/src/services/plugin/{client.ts → _deprecated.ts} +0 -0
  88. /package/src/services/topic/{client.ts → _deprecated.ts} +0 -0
  89. /package/src/services/user/{client.ts → _deprecated.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import { DB_Message } from '@/database/_deprecated/schemas/message';
1
+ import { MessageItem } from '@/database/schemas';
2
2
  import {
3
3
  ChatMessage,
4
4
  ChatMessageError,
@@ -11,7 +11,7 @@ import {
11
11
 
12
12
  export interface IMessageService {
13
13
  createMessage(data: CreateMessageParams): Promise<string>;
14
- batchCreateMessages(messages: ChatMessage[]): Promise<any>;
14
+ batchCreateMessages(messages: MessageItem[]): Promise<any>;
15
15
 
16
16
  getMessages(sessionId: string, topicId?: string): Promise<ChatMessage[]>;
17
17
  getAllMessages(): Promise<ChatMessage[]>;
@@ -20,11 +20,10 @@ export interface IMessageService {
20
20
  countTodayMessages(): Promise<number>;
21
21
 
22
22
  updateMessageError(id: string, error: ChatMessageError): Promise<any>;
23
- updateMessage(id: string, message: Partial<DB_Message>): Promise<any>;
23
+ updateMessage(id: string, message: Partial<MessageItem>): Promise<any>;
24
24
  updateMessageTTS(id: string, tts: Partial<ChatTTS> | false): Promise<any>;
25
25
  updateMessageTranslate(id: string, translate: Partial<ChatTranslate> | false): Promise<any>;
26
26
  updateMessagePluginState(id: string, value: Record<string, any>): Promise<any>;
27
- bindMessagesToTopic(topicId: string, messageIds: string[]): Promise<any>;
28
27
 
29
28
  removeMessage(id: string): Promise<any>;
30
29
  removeMessages(ids: string[]): Promise<any>;
@@ -6,7 +6,7 @@ import { DB_Plugin } from '@/database/_deprecated/schemas/plugin';
6
6
  import { LobeTool } from '@/types/tool';
7
7
  import { LobeToolCustomPlugin } from '@/types/tool/plugin';
8
8
 
9
- import { ClientService } from './client';
9
+ import { ClientService } from './_deprecated';
10
10
  import { InstallPluginParams } from './type';
11
11
 
12
12
  const pluginService = new ClientService();
@@ -1,5 +1,9 @@
1
- import { ClientService } from './client';
1
+ import { ClientService as DeprecatedService } from './_deprecated';
2
+ import { ClientService } from './pglite';
2
3
  import { ServerService } from './server';
3
4
 
5
+ const clientService =
6
+ process.env.NEXT_PUBLIC_CLIENT_DB === 'pglite' ? new ClientService() : new DeprecatedService();
7
+
4
8
  export const pluginService =
5
- process.env.NEXT_PUBLIC_SERVICE_MODE === 'server' ? new ServerService() : new ClientService();
9
+ process.env.NEXT_PUBLIC_SERVICE_MODE === 'server' ? new ServerService() : clientService;
@@ -0,0 +1,175 @@
1
+ import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
2
+ import { eq } from 'drizzle-orm';
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
+
5
+ import { clientDB, initializeDB } from '@/database/client/db';
6
+ import { installedPlugins, users } from '@/database/schemas';
7
+ import { LobeTool } from '@/types/tool';
8
+ import { LobeToolCustomPlugin } from '@/types/tool/plugin';
9
+
10
+ import { ClientService } from './pglite';
11
+ import { InstallPluginParams } from './type';
12
+
13
+ // Mocking modules and functions
14
+
15
+ const userId = 'message-db';
16
+ const pluginService = new ClientService(userId);
17
+
18
+ // Mock data
19
+ beforeEach(async () => {
20
+ await initializeDB();
21
+
22
+ // 在每个测试用例之前,重置表数据
23
+ await clientDB.transaction(async (trx) => {
24
+ await trx.delete(users);
25
+ await trx.insert(users).values([{ id: userId }, { id: '456' }]);
26
+ });
27
+ });
28
+
29
+ describe('PluginService', () => {
30
+ describe('installPlugin', () => {
31
+ it('should install a plugin', async () => {
32
+ // Arrange
33
+ const fakePlugin = {
34
+ identifier: 'test-plugin-d',
35
+ manifest: { name: 'TestPlugin', version: '1.0.0' } as unknown as LobeChatPluginManifest,
36
+ type: 'plugin',
37
+ } as InstallPluginParams;
38
+
39
+ // Act
40
+ await pluginService.installPlugin(fakePlugin);
41
+
42
+ // Assert
43
+ const result = await clientDB.query.installedPlugins.findFirst({
44
+ where: eq(installedPlugins.identifier, fakePlugin.identifier),
45
+ });
46
+ expect(result).toMatchObject(fakePlugin);
47
+ });
48
+ });
49
+
50
+ describe('getInstalledPlugins', () => {
51
+ it('should return a list of installed plugins', async () => {
52
+ // Arrange
53
+ const fakePlugins = [{ identifier: 'test-plugin', type: 'plugin' }] as LobeTool[];
54
+ await clientDB
55
+ .insert(installedPlugins)
56
+ .values([{ identifier: 'test-plugin', type: 'plugin', userId }]);
57
+ // Act
58
+ const data = await pluginService.getInstalledPlugins();
59
+
60
+ // Assert
61
+ expect(data).toMatchObject(fakePlugins);
62
+ });
63
+ });
64
+
65
+ describe('uninstallPlugin', () => {
66
+ it('should uninstall a plugin', async () => {
67
+ // Arrange
68
+ const identifier = 'test-plugin';
69
+ await clientDB.insert(installedPlugins).values([{ identifier, type: 'plugin', userId }]);
70
+
71
+ // Act
72
+ await pluginService.uninstallPlugin(identifier);
73
+
74
+ // Assert
75
+ const result = await clientDB.query.installedPlugins.findFirst({
76
+ where: eq(installedPlugins.identifier, identifier),
77
+ });
78
+ expect(result).toBe(undefined);
79
+ });
80
+ });
81
+
82
+ describe('createCustomPlugin', () => {
83
+ it('should create a custom plugin', async () => {
84
+ // Arrange
85
+ const customPlugin = {
86
+ identifier: 'custom-plugin-x',
87
+ manifest: {},
88
+ type: 'customPlugin',
89
+ } as LobeToolCustomPlugin;
90
+
91
+ // Act
92
+ await pluginService.createCustomPlugin(customPlugin);
93
+
94
+ // Assert
95
+ const result = await clientDB.query.installedPlugins.findFirst({
96
+ where: eq(installedPlugins.identifier, customPlugin.identifier),
97
+ });
98
+ expect(result).toMatchObject(customPlugin);
99
+ });
100
+ });
101
+
102
+ describe('updatePlugin', () => {
103
+ it('should update a plugin', async () => {
104
+ // Arrange
105
+ const identifier = 'plugin-id';
106
+ const value = { customParams: { ab: '1' } } as unknown as LobeToolCustomPlugin;
107
+ await clientDB.insert(installedPlugins).values([{ identifier, type: 'plugin', userId }]);
108
+
109
+ // Act
110
+ await pluginService.updatePlugin(identifier, value);
111
+
112
+ // Assert
113
+ const result = await clientDB.query.installedPlugins.findFirst({
114
+ where: eq(installedPlugins.identifier, identifier),
115
+ });
116
+ expect(result).toMatchObject(value);
117
+ });
118
+ });
119
+
120
+ describe('updatePluginManifest', () => {
121
+ it('should update a plugin manifest', async () => {
122
+ // Arrange
123
+ const identifier = 'plugin-id';
124
+ const manifest = { name: 'NewPluginManifest' } as unknown as LobeChatPluginManifest;
125
+ await clientDB.insert(installedPlugins).values([{ identifier, type: 'plugin', userId }]);
126
+
127
+ // Act
128
+ await pluginService.updatePluginManifest(identifier, manifest);
129
+
130
+ // Assert
131
+ const result = await clientDB.query.installedPlugins.findFirst({
132
+ where: eq(installedPlugins.identifier, identifier),
133
+ });
134
+ expect(result).toMatchObject({ manifest });
135
+ });
136
+ });
137
+
138
+ describe('removeAllPlugins', () => {
139
+ it('should remove all plugins', async () => {
140
+ // Arrange
141
+ await clientDB.insert(installedPlugins).values([
142
+ { identifier: '123', type: 'plugin', userId },
143
+ { identifier: '234', type: 'plugin', userId },
144
+ ]);
145
+
146
+ // Act
147
+ await pluginService.removeAllPlugins();
148
+
149
+ // Assert
150
+ const result = await clientDB.query.installedPlugins.findMany({
151
+ where: eq(installedPlugins.userId, userId),
152
+ });
153
+ expect(result.length).toEqual(0);
154
+ });
155
+ });
156
+
157
+ describe('updatePluginSettings', () => {
158
+ it('should update plugin settings', async () => {
159
+ // Arrange
160
+ const id = 'plugin-id';
161
+ const settings = { color: 'blue' };
162
+ await clientDB.insert(installedPlugins).values([{ identifier: id, type: 'plugin', userId }]);
163
+
164
+ // Act
165
+ await pluginService.updatePluginSettings(id, settings);
166
+
167
+ // Assert
168
+ const result = await clientDB.query.installedPlugins.findFirst({
169
+ where: eq(installedPlugins.identifier, id),
170
+ });
171
+
172
+ expect(result).toMatchObject({ settings });
173
+ });
174
+ });
175
+ });
@@ -0,0 +1,51 @@
1
+ import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
2
+
3
+ import { clientDB } from '@/database/client/db';
4
+ import { PluginModel } from '@/database/server/models/plugin';
5
+ import { BaseClientService } from '@/services/baseClientService';
6
+ import { LobeTool } from '@/types/tool';
7
+ import { LobeToolCustomPlugin } from '@/types/tool/plugin';
8
+
9
+ import { IPluginService, InstallPluginParams } from './type';
10
+
11
+ export class ClientService extends BaseClientService implements IPluginService {
12
+ private get pluginModel(): PluginModel {
13
+ return new PluginModel(clientDB as any, this.userId);
14
+ }
15
+
16
+ installPlugin = async (plugin: InstallPluginParams) => {
17
+ await this.pluginModel.create(plugin);
18
+ return;
19
+ };
20
+
21
+ getInstalledPlugins = () => {
22
+ return this.pluginModel.query() as Promise<LobeTool[]>;
23
+ };
24
+
25
+ async uninstallPlugin(identifier: string) {
26
+ await this.pluginModel.delete(identifier);
27
+ return;
28
+ }
29
+
30
+ async createCustomPlugin(customPlugin: LobeToolCustomPlugin) {
31
+ await this.pluginModel.create({ ...customPlugin, type: 'customPlugin' });
32
+ return;
33
+ }
34
+
35
+ async updatePlugin(id: string, value: LobeToolCustomPlugin) {
36
+ await this.pluginModel.update(id, value);
37
+ return;
38
+ }
39
+ async updatePluginManifest(id: string, manifest: LobeChatPluginManifest) {
40
+ await this.pluginModel.update(id, { manifest });
41
+ }
42
+
43
+ async removeAllPlugins() {
44
+ await this.pluginModel.deleteAll();
45
+ }
46
+
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
48
+ async updatePluginSettings(id: string, settings: any, _?: AbortSignal) {
49
+ await this.pluginModel.update(id, { settings });
50
+ }
51
+ }
@@ -5,7 +5,7 @@ import { SessionGroupModel } from '@/database/_deprecated/models/sessionGroup';
5
5
  import { LobeAgentConfig } from '@/types/agent';
6
6
  import { LobeAgentSession, LobeSessionType, SessionGroups } from '@/types/session';
7
7
 
8
- import { ClientService } from './client';
8
+ import { ClientService } from './_deprecated';
9
9
 
10
10
  const sessionService = new ClientService();
11
11
 
@@ -166,7 +166,7 @@ export class ClientService implements ISessionService {
166
166
  }
167
167
 
168
168
  async updateSessionGroup(id: string, data: Partial<SessionGroupItem>) {
169
- return SessionGroupModel.update(id, data);
169
+ return SessionGroupModel.update(id, data as any);
170
170
  }
171
171
 
172
172
  async updateSessionGroupOrder(sortMap: { id: string; sort: number }[]) {
@@ -1,5 +1,9 @@
1
- import { ClientService } from './client';
1
+ import { ClientService as DeprecatedService } from './_deprecated';
2
+ import { ClientService } from './pglite';
2
3
  import { ServerService } from './server';
3
4
 
5
+ const clientService =
6
+ process.env.NEXT_PUBLIC_CLIENT_DB === 'pglite' ? new ClientService() : new DeprecatedService();
7
+
4
8
  export const sessionService =
5
- process.env.NEXT_PUBLIC_SERVICE_MODE === 'server' ? new ServerService() : new ClientService();
9
+ process.env.NEXT_PUBLIC_SERVICE_MODE === 'server' ? new ServerService() : clientService;