@lobehub/chat 1.37.0 → 1.37.2
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/locales/en-US/common.json +2 -2
- package/package.json +1 -1
- package/src/services/file/_deprecated.test.ts +119 -0
- package/src/services/file/{pglite.ts → _deprecated.ts} +28 -32
- package/src/services/file/client.test.ts +153 -74
- package/src/services/file/client.ts +32 -28
- package/src/services/file/index.ts +2 -2
- package/src/services/import/_deprecated.ts +74 -0
- package/src/services/import/{pglite.test.ts → client.test.ts} +1 -1
- package/src/services/import/client.ts +21 -61
- package/src/services/import/index.ts +2 -2
- package/src/services/message/_deprecated.test.ts +398 -0
- package/src/services/message/_deprecated.ts +121 -0
- package/src/services/message/client.test.ts +191 -159
- package/src/services/message/client.ts +47 -50
- package/src/services/message/index.ts +2 -2
- package/src/services/plugin/_deprecated.test.ts +162 -0
- package/src/services/plugin/_deprecated.ts +42 -0
- package/src/services/plugin/client.test.ts +68 -55
- package/src/services/plugin/client.ts +20 -11
- package/src/services/plugin/index.ts +2 -2
- package/src/services/session/_deprecated.test.ts +440 -0
- package/src/services/session/_deprecated.ts +183 -0
- package/src/services/session/client.test.ts +212 -241
- package/src/services/session/client.ts +61 -60
- package/src/services/session/index.ts +2 -2
- package/src/services/topic/{client.test.ts → _deprecated.test.ts} +1 -1
- package/src/services/topic/_deprecated.ts +70 -0
- package/src/services/topic/client.ts +40 -25
- package/src/services/topic/index.ts +2 -2
- package/src/services/topic/pglite.test.ts +1 -1
- package/src/services/user/{pglite.test.ts → _deprecated.test.ts} +32 -29
- package/src/services/user/_deprecated.ts +57 -0
- package/src/services/user/client.test.ts +28 -31
- package/src/services/user/client.ts +51 -16
- package/src/services/user/index.ts +2 -2
- package/src/store/chat/slices/builtinTool/action.test.ts +1 -1
- package/src/store/user/slices/common/action.test.ts +1 -1
- package/src/services/file/pglite.test.ts +0 -198
- package/src/services/import/pglite.ts +0 -34
- package/src/services/message/pglite.test.ts +0 -430
- package/src/services/message/pglite.ts +0 -118
- package/src/services/plugin/pglite.test.ts +0 -175
- package/src/services/plugin/pglite.ts +0 -51
- package/src/services/session/pglite.test.ts +0 -411
- package/src/services/session/pglite.ts +0 -184
- package/src/services/topic/pglite.ts +0 -85
- package/src/services/user/pglite.ts +0 -92
@@ -1,10 +1,11 @@
|
|
1
1
|
import dayjs from 'dayjs';
|
2
2
|
|
3
|
-
import {
|
4
|
-
import {
|
5
|
-
import {
|
3
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
4
|
+
import { clientDB } from '@/database/client/db';
|
5
|
+
import { MessageItem } from '@/database/schemas';
|
6
|
+
import { MessageModel } from '@/database/server/models/message';
|
7
|
+
import { BaseClientService } from '@/services/baseClientService';
|
6
8
|
import {
|
7
|
-
ChatFileItem,
|
8
9
|
ChatMessage,
|
9
10
|
ChatMessageError,
|
10
11
|
ChatTTS,
|
@@ -14,108 +15,104 @@ import {
|
|
14
15
|
|
15
16
|
import { IMessageService } from './type';
|
16
17
|
|
17
|
-
export class ClientService implements IMessageService {
|
18
|
-
|
19
|
-
|
18
|
+
export class ClientService extends BaseClientService implements IMessageService {
|
19
|
+
private get messageModel(): MessageModel {
|
20
|
+
return new MessageModel(clientDB as any, this.userId);
|
21
|
+
}
|
22
|
+
|
23
|
+
async createMessage({ sessionId, ...params }: CreateMessageParams) {
|
24
|
+
const { id } = await this.messageModel.create({
|
25
|
+
...params,
|
26
|
+
sessionId: this.toDbSessionId(sessionId) as string,
|
27
|
+
});
|
20
28
|
|
21
29
|
return id;
|
22
30
|
}
|
23
31
|
|
24
|
-
|
25
|
-
|
26
|
-
return MessageModel.batchCreate(messages);
|
32
|
+
async batchCreateMessages(messages: MessageItem[]) {
|
33
|
+
return this.messageModel.batchCreate(messages);
|
27
34
|
}
|
28
35
|
|
29
|
-
async getMessages(sessionId: string, topicId?: string)
|
30
|
-
const
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
.flatMap((item) => item.files)
|
35
|
-
.filter(Boolean)
|
36
|
-
.map(async (id) => FileModel.findById(id!)),
|
37
|
-
)) as ChatFileItem[];
|
36
|
+
async getMessages(sessionId: string, topicId?: string) {
|
37
|
+
const data = await this.messageModel.query({
|
38
|
+
sessionId: this.toDbSessionId(sessionId),
|
39
|
+
topicId,
|
40
|
+
});
|
38
41
|
|
39
|
-
return
|
40
|
-
...item,
|
41
|
-
imageList: fileList
|
42
|
-
.filter((file) => item.files?.includes(file.id) && file.fileType.startsWith('image'))
|
43
|
-
.map((file) => ({
|
44
|
-
alt: file.name,
|
45
|
-
id: file.id,
|
46
|
-
url: file.url,
|
47
|
-
})),
|
48
|
-
}));
|
42
|
+
return data as unknown as ChatMessage[];
|
49
43
|
}
|
50
44
|
|
51
45
|
async getAllMessages() {
|
52
|
-
|
46
|
+
const data = await this.messageModel.queryAll();
|
47
|
+
|
48
|
+
return data as unknown as ChatMessage[];
|
53
49
|
}
|
54
50
|
|
55
51
|
async countMessages() {
|
56
|
-
return
|
52
|
+
return this.messageModel.count();
|
57
53
|
}
|
58
54
|
|
59
55
|
async countTodayMessages() {
|
60
|
-
const topics = await
|
56
|
+
const topics = await this.messageModel.queryAll();
|
61
57
|
return topics.filter(
|
62
58
|
(item) => dayjs(item.createdAt).format('YYYY-MM-DD') === dayjs().format('YYYY-MM-DD'),
|
63
59
|
).length;
|
64
60
|
}
|
65
61
|
|
66
62
|
async getAllMessagesInSession(sessionId: string) {
|
67
|
-
|
63
|
+
const data = this.messageModel.queryBySessionId(this.toDbSessionId(sessionId));
|
64
|
+
|
65
|
+
return data as unknown as ChatMessage[];
|
68
66
|
}
|
69
67
|
|
70
68
|
async updateMessageError(id: string, error: ChatMessageError) {
|
71
|
-
return
|
69
|
+
return this.messageModel.update(id, { error });
|
72
70
|
}
|
73
71
|
|
74
|
-
|
75
|
-
|
76
|
-
return MessageModel.update(id, message);
|
72
|
+
async updateMessage(id: string, message: Partial<MessageItem>) {
|
73
|
+
return this.messageModel.update(id, message);
|
77
74
|
}
|
78
75
|
|
79
76
|
async updateMessageTTS(id: string, tts: Partial<ChatTTS> | false) {
|
80
|
-
return
|
77
|
+
return this.messageModel.updateTTS(id, tts as any);
|
81
78
|
}
|
82
79
|
|
83
80
|
async updateMessageTranslate(id: string, translate: Partial<ChatTranslate> | false) {
|
84
|
-
return
|
81
|
+
return this.messageModel.updateTranslate(id, translate as any);
|
85
82
|
}
|
86
83
|
|
87
84
|
async updateMessagePluginState(id: string, value: Record<string, any>) {
|
88
|
-
return
|
85
|
+
return this.messageModel.updatePluginState(id, value);
|
89
86
|
}
|
90
87
|
|
91
88
|
async updateMessagePluginArguments(id: string, value: string | Record<string, any>) {
|
92
89
|
const args = typeof value === 'string' ? value : JSON.stringify(value);
|
93
90
|
|
94
|
-
return
|
95
|
-
}
|
96
|
-
|
97
|
-
async bindMessagesToTopic(topicId: string, messageIds: string[]) {
|
98
|
-
return MessageModel.batchUpdate(messageIds, { topicId });
|
91
|
+
return this.messageModel.updateMessagePlugin(id, { arguments: args });
|
99
92
|
}
|
100
93
|
|
101
94
|
async removeMessage(id: string) {
|
102
|
-
return
|
95
|
+
return this.messageModel.deleteMessage(id);
|
103
96
|
}
|
104
97
|
|
105
98
|
async removeMessages(ids: string[]) {
|
106
|
-
return
|
99
|
+
return this.messageModel.deleteMessages(ids);
|
107
100
|
}
|
108
101
|
|
109
|
-
async removeMessagesByAssistant(
|
110
|
-
return
|
102
|
+
async removeMessagesByAssistant(sessionId: string, topicId?: string) {
|
103
|
+
return this.messageModel.deleteMessagesBySession(this.toDbSessionId(sessionId), topicId);
|
111
104
|
}
|
112
105
|
|
113
106
|
async removeAllMessages() {
|
114
|
-
return
|
107
|
+
return this.messageModel.deleteAllMessages();
|
115
108
|
}
|
116
109
|
|
117
110
|
async hasMessages() {
|
118
111
|
const number = await this.countMessages();
|
119
112
|
return number > 0;
|
120
113
|
}
|
114
|
+
|
115
|
+
private toDbSessionId(sessionId: string | undefined) {
|
116
|
+
return sessionId === INBOX_SESSION_ID ? undefined : sessionId;
|
117
|
+
}
|
121
118
|
}
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import { ClientService as DeprecatedService } from './
|
2
|
-
import { ClientService } from './
|
1
|
+
import { ClientService as DeprecatedService } from './_deprecated';
|
2
|
+
import { ClientService } from './client';
|
3
3
|
import { ServerService } from './server';
|
4
4
|
|
5
5
|
const clientService =
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { PluginModel } from '@/database/_deprecated/models/plugin';
|
5
|
+
import { DB_Plugin } from '@/database/_deprecated/schemas/plugin';
|
6
|
+
import { LobeTool } from '@/types/tool';
|
7
|
+
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
8
|
+
|
9
|
+
import { ClientService } from './_deprecated';
|
10
|
+
import { InstallPluginParams } from './type';
|
11
|
+
|
12
|
+
const pluginService = new ClientService();
|
13
|
+
|
14
|
+
// Mocking modules and functions
|
15
|
+
|
16
|
+
vi.mock('@/database/_deprecated/models/plugin', () => ({
|
17
|
+
PluginModel: {
|
18
|
+
getList: vi.fn(),
|
19
|
+
create: vi.fn(),
|
20
|
+
delete: vi.fn(),
|
21
|
+
update: vi.fn(),
|
22
|
+
clear: vi.fn(),
|
23
|
+
},
|
24
|
+
}));
|
25
|
+
|
26
|
+
beforeEach(() => {
|
27
|
+
vi.resetAllMocks();
|
28
|
+
});
|
29
|
+
|
30
|
+
describe('PluginService', () => {
|
31
|
+
describe('installPlugin', () => {
|
32
|
+
it('should install a plugin', async () => {
|
33
|
+
// Arrange
|
34
|
+
const fakePlugin = {
|
35
|
+
identifier: 'test-plugin',
|
36
|
+
manifest: { name: 'TestPlugin', version: '1.0.0' } as unknown as LobeChatPluginManifest,
|
37
|
+
type: 'plugin',
|
38
|
+
} as InstallPluginParams;
|
39
|
+
vi.mocked(PluginModel.create).mockResolvedValue(fakePlugin);
|
40
|
+
|
41
|
+
// Act
|
42
|
+
const installedPlugin = await pluginService.installPlugin(fakePlugin);
|
43
|
+
|
44
|
+
// Assert
|
45
|
+
expect(PluginModel.create).toHaveBeenCalledWith(fakePlugin);
|
46
|
+
expect(installedPlugin).toEqual(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
|
+
vi.mocked(PluginModel.getList).mockResolvedValue(fakePlugins as DB_Plugin[]);
|
55
|
+
|
56
|
+
// Act
|
57
|
+
const installedPlugins = await pluginService.getInstalledPlugins();
|
58
|
+
|
59
|
+
// Assert
|
60
|
+
expect(PluginModel.getList).toHaveBeenCalled();
|
61
|
+
expect(installedPlugins).toEqual(fakePlugins);
|
62
|
+
});
|
63
|
+
});
|
64
|
+
|
65
|
+
describe('uninstallPlugin', () => {
|
66
|
+
it('should uninstall a plugin', async () => {
|
67
|
+
// Arrange
|
68
|
+
const identifier = 'test-plugin';
|
69
|
+
vi.mocked(PluginModel.delete).mockResolvedValue();
|
70
|
+
|
71
|
+
// Act
|
72
|
+
const result = await pluginService.uninstallPlugin(identifier);
|
73
|
+
|
74
|
+
// Assert
|
75
|
+
expect(PluginModel.delete).toHaveBeenCalledWith(identifier);
|
76
|
+
expect(result).toBe(undefined);
|
77
|
+
});
|
78
|
+
});
|
79
|
+
|
80
|
+
describe('createCustomPlugin', () => {
|
81
|
+
it('should create a custom plugin', async () => {
|
82
|
+
// Arrange
|
83
|
+
const customPlugin = {
|
84
|
+
identifier: 'custom-plugin',
|
85
|
+
manifest: {},
|
86
|
+
type: 'customPlugin',
|
87
|
+
} as LobeToolCustomPlugin;
|
88
|
+
vi.mocked(PluginModel.create).mockResolvedValue(customPlugin);
|
89
|
+
|
90
|
+
// Act
|
91
|
+
const result = await pluginService.createCustomPlugin(customPlugin);
|
92
|
+
|
93
|
+
// Assert
|
94
|
+
expect(PluginModel.create).toHaveBeenCalledWith({
|
95
|
+
...customPlugin,
|
96
|
+
type: 'customPlugin',
|
97
|
+
});
|
98
|
+
expect(result).toEqual(customPlugin);
|
99
|
+
});
|
100
|
+
});
|
101
|
+
|
102
|
+
describe('updatePlugin', () => {
|
103
|
+
it('should update a plugin', async () => {
|
104
|
+
// Arrange
|
105
|
+
const id = 'plugin-id';
|
106
|
+
const value = { settings: { ab: '1' } } as unknown as LobeToolCustomPlugin;
|
107
|
+
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
108
|
+
|
109
|
+
// Act
|
110
|
+
const result = await pluginService.updatePlugin(id, value);
|
111
|
+
|
112
|
+
// Assert
|
113
|
+
expect(PluginModel.update).toHaveBeenCalledWith(id, value);
|
114
|
+
expect(result).toEqual(undefined);
|
115
|
+
});
|
116
|
+
});
|
117
|
+
|
118
|
+
describe('updatePluginManifest', () => {
|
119
|
+
it('should update a plugin manifest', async () => {
|
120
|
+
// Arrange
|
121
|
+
const id = 'plugin-id';
|
122
|
+
const manifest = { name: 'NewPluginManifest' } as unknown as LobeChatPluginManifest;
|
123
|
+
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
124
|
+
|
125
|
+
// Act
|
126
|
+
const result = await pluginService.updatePluginManifest(id, manifest);
|
127
|
+
|
128
|
+
// Assert
|
129
|
+
expect(PluginModel.update).toHaveBeenCalledWith(id, { manifest });
|
130
|
+
expect(result).toEqual(undefined);
|
131
|
+
});
|
132
|
+
});
|
133
|
+
|
134
|
+
describe('removeAllPlugins', () => {
|
135
|
+
it('should remove all plugins', async () => {
|
136
|
+
// Arrange
|
137
|
+
vi.mocked(PluginModel.clear).mockResolvedValue(undefined);
|
138
|
+
|
139
|
+
// Act
|
140
|
+
const result = await pluginService.removeAllPlugins();
|
141
|
+
|
142
|
+
// Assert
|
143
|
+
expect(PluginModel.clear).toHaveBeenCalled();
|
144
|
+
expect(result).toBe(undefined);
|
145
|
+
});
|
146
|
+
});
|
147
|
+
|
148
|
+
describe('updatePluginSettings', () => {
|
149
|
+
it('should update plugin settings', async () => {
|
150
|
+
// Arrange
|
151
|
+
const id = 'plugin-id';
|
152
|
+
const settings = { color: 'blue' };
|
153
|
+
|
154
|
+
// Act
|
155
|
+
const result = await pluginService.updatePluginSettings(id, settings);
|
156
|
+
|
157
|
+
// Assert
|
158
|
+
expect(PluginModel.update).toHaveBeenCalledWith(id, { settings });
|
159
|
+
expect(result).toEqual(undefined);
|
160
|
+
});
|
161
|
+
});
|
162
|
+
});
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
2
|
+
|
3
|
+
import { PluginModel } from '@/database/_deprecated/models/plugin';
|
4
|
+
import { LobeTool } from '@/types/tool';
|
5
|
+
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
6
|
+
|
7
|
+
import { IPluginService, InstallPluginParams } from './type';
|
8
|
+
|
9
|
+
export class ClientService implements IPluginService {
|
10
|
+
installPlugin = async (plugin: InstallPluginParams) => {
|
11
|
+
return PluginModel.create(plugin);
|
12
|
+
};
|
13
|
+
|
14
|
+
getInstalledPlugins = () => {
|
15
|
+
return PluginModel.getList() as Promise<LobeTool[]>;
|
16
|
+
};
|
17
|
+
|
18
|
+
uninstallPlugin(identifier: string) {
|
19
|
+
return PluginModel.delete(identifier);
|
20
|
+
}
|
21
|
+
|
22
|
+
async createCustomPlugin(customPlugin: LobeToolCustomPlugin) {
|
23
|
+
return PluginModel.create({ ...customPlugin, type: 'customPlugin' });
|
24
|
+
}
|
25
|
+
|
26
|
+
async updatePlugin(id: string, value: LobeToolCustomPlugin) {
|
27
|
+
await PluginModel.update(id, value);
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
async updatePluginManifest(id: string, manifest: LobeChatPluginManifest) {
|
31
|
+
await PluginModel.update(id, { manifest });
|
32
|
+
}
|
33
|
+
|
34
|
+
async removeAllPlugins() {
|
35
|
+
return PluginModel.clear();
|
36
|
+
}
|
37
|
+
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
39
|
+
async updatePluginSettings(id: string, settings: any, _?: AbortSignal) {
|
40
|
+
await PluginModel.update(id, { settings });
|
41
|
+
}
|
42
|
+
}
|
@@ -1,30 +1,29 @@
|
|
1
1
|
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
2
|
-
import {
|
2
|
+
import { eq } from 'drizzle-orm';
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import {
|
5
|
-
import {
|
5
|
+
import { clientDB, initializeDB } from '@/database/client/db';
|
6
|
+
import { installedPlugins, users } from '@/database/schemas';
|
6
7
|
import { LobeTool } from '@/types/tool';
|
7
8
|
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
8
9
|
|
9
10
|
import { ClientService } from './client';
|
10
11
|
import { InstallPluginParams } from './type';
|
11
12
|
|
12
|
-
const pluginService = new ClientService();
|
13
|
-
|
14
13
|
// Mocking modules and functions
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
+
});
|
28
27
|
});
|
29
28
|
|
30
29
|
describe('PluginService', () => {
|
@@ -32,18 +31,19 @@ describe('PluginService', () => {
|
|
32
31
|
it('should install a plugin', async () => {
|
33
32
|
// Arrange
|
34
33
|
const fakePlugin = {
|
35
|
-
identifier: 'test-plugin',
|
34
|
+
identifier: 'test-plugin-d',
|
36
35
|
manifest: { name: 'TestPlugin', version: '1.0.0' } as unknown as LobeChatPluginManifest,
|
37
36
|
type: 'plugin',
|
38
37
|
} as InstallPluginParams;
|
39
|
-
vi.mocked(PluginModel.create).mockResolvedValue(fakePlugin);
|
40
38
|
|
41
39
|
// Act
|
42
|
-
|
40
|
+
await pluginService.installPlugin(fakePlugin);
|
43
41
|
|
44
42
|
// Assert
|
45
|
-
|
46
|
-
|
43
|
+
const result = await clientDB.query.installedPlugins.findFirst({
|
44
|
+
where: eq(installedPlugins.identifier, fakePlugin.identifier),
|
45
|
+
});
|
46
|
+
expect(result).toMatchObject(fakePlugin);
|
47
47
|
});
|
48
48
|
});
|
49
49
|
|
@@ -51,14 +51,14 @@ describe('PluginService', () => {
|
|
51
51
|
it('should return a list of installed plugins', async () => {
|
52
52
|
// Arrange
|
53
53
|
const fakePlugins = [{ identifier: 'test-plugin', type: 'plugin' }] as LobeTool[];
|
54
|
-
|
55
|
-
|
54
|
+
await clientDB
|
55
|
+
.insert(installedPlugins)
|
56
|
+
.values([{ identifier: 'test-plugin', type: 'plugin', userId }]);
|
56
57
|
// Act
|
57
|
-
const
|
58
|
+
const data = await pluginService.getInstalledPlugins();
|
58
59
|
|
59
60
|
// Assert
|
60
|
-
expect(
|
61
|
-
expect(installedPlugins).toEqual(fakePlugins);
|
61
|
+
expect(data).toMatchObject(fakePlugins);
|
62
62
|
});
|
63
63
|
});
|
64
64
|
|
@@ -66,13 +66,15 @@ describe('PluginService', () => {
|
|
66
66
|
it('should uninstall a plugin', async () => {
|
67
67
|
// Arrange
|
68
68
|
const identifier = 'test-plugin';
|
69
|
-
|
69
|
+
await clientDB.insert(installedPlugins).values([{ identifier, type: 'plugin', userId }]);
|
70
70
|
|
71
71
|
// Act
|
72
|
-
|
72
|
+
await pluginService.uninstallPlugin(identifier);
|
73
73
|
|
74
74
|
// Assert
|
75
|
-
|
75
|
+
const result = await clientDB.query.installedPlugins.findFirst({
|
76
|
+
where: eq(installedPlugins.identifier, identifier),
|
77
|
+
});
|
76
78
|
expect(result).toBe(undefined);
|
77
79
|
});
|
78
80
|
});
|
@@ -81,67 +83,74 @@ describe('PluginService', () => {
|
|
81
83
|
it('should create a custom plugin', async () => {
|
82
84
|
// Arrange
|
83
85
|
const customPlugin = {
|
84
|
-
identifier: 'custom-plugin',
|
86
|
+
identifier: 'custom-plugin-x',
|
85
87
|
manifest: {},
|
86
88
|
type: 'customPlugin',
|
87
89
|
} as LobeToolCustomPlugin;
|
88
|
-
vi.mocked(PluginModel.create).mockResolvedValue(customPlugin);
|
89
90
|
|
90
91
|
// Act
|
91
|
-
|
92
|
+
await pluginService.createCustomPlugin(customPlugin);
|
92
93
|
|
93
94
|
// Assert
|
94
|
-
|
95
|
-
|
96
|
-
type: 'customPlugin',
|
95
|
+
const result = await clientDB.query.installedPlugins.findFirst({
|
96
|
+
where: eq(installedPlugins.identifier, customPlugin.identifier),
|
97
97
|
});
|
98
|
-
expect(result).
|
98
|
+
expect(result).toMatchObject(customPlugin);
|
99
99
|
});
|
100
100
|
});
|
101
101
|
|
102
102
|
describe('updatePlugin', () => {
|
103
103
|
it('should update a plugin', async () => {
|
104
104
|
// Arrange
|
105
|
-
const
|
106
|
-
const value = {
|
107
|
-
|
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
108
|
|
109
109
|
// Act
|
110
|
-
|
110
|
+
await pluginService.updatePlugin(identifier, value);
|
111
111
|
|
112
112
|
// Assert
|
113
|
-
|
114
|
-
|
113
|
+
const result = await clientDB.query.installedPlugins.findFirst({
|
114
|
+
where: eq(installedPlugins.identifier, identifier),
|
115
|
+
});
|
116
|
+
expect(result).toMatchObject(value);
|
115
117
|
});
|
116
118
|
});
|
117
119
|
|
118
120
|
describe('updatePluginManifest', () => {
|
119
121
|
it('should update a plugin manifest', async () => {
|
120
122
|
// Arrange
|
121
|
-
const
|
123
|
+
const identifier = 'plugin-id';
|
122
124
|
const manifest = { name: 'NewPluginManifest' } as unknown as LobeChatPluginManifest;
|
123
|
-
|
125
|
+
await clientDB.insert(installedPlugins).values([{ identifier, type: 'plugin', userId }]);
|
124
126
|
|
125
127
|
// Act
|
126
|
-
|
128
|
+
await pluginService.updatePluginManifest(identifier, manifest);
|
127
129
|
|
128
130
|
// Assert
|
129
|
-
|
130
|
-
|
131
|
+
const result = await clientDB.query.installedPlugins.findFirst({
|
132
|
+
where: eq(installedPlugins.identifier, identifier),
|
133
|
+
});
|
134
|
+
expect(result).toMatchObject({ manifest });
|
131
135
|
});
|
132
136
|
});
|
133
137
|
|
134
138
|
describe('removeAllPlugins', () => {
|
135
139
|
it('should remove all plugins', async () => {
|
136
140
|
// Arrange
|
137
|
-
|
141
|
+
await clientDB.insert(installedPlugins).values([
|
142
|
+
{ identifier: '123', type: 'plugin', userId },
|
143
|
+
{ identifier: '234', type: 'plugin', userId },
|
144
|
+
]);
|
138
145
|
|
139
146
|
// Act
|
140
|
-
|
147
|
+
await pluginService.removeAllPlugins();
|
141
148
|
|
142
149
|
// Assert
|
143
|
-
|
144
|
-
|
150
|
+
const result = await clientDB.query.installedPlugins.findMany({
|
151
|
+
where: eq(installedPlugins.userId, userId),
|
152
|
+
});
|
153
|
+
expect(result.length).toEqual(0);
|
145
154
|
});
|
146
155
|
});
|
147
156
|
|
@@ -150,13 +159,17 @@ describe('PluginService', () => {
|
|
150
159
|
// Arrange
|
151
160
|
const id = 'plugin-id';
|
152
161
|
const settings = { color: 'blue' };
|
162
|
+
await clientDB.insert(installedPlugins).values([{ identifier: id, type: 'plugin', userId }]);
|
153
163
|
|
154
164
|
// Act
|
155
|
-
|
165
|
+
await pluginService.updatePluginSettings(id, settings);
|
156
166
|
|
157
167
|
// Assert
|
158
|
-
|
159
|
-
|
168
|
+
const result = await clientDB.query.installedPlugins.findFirst({
|
169
|
+
where: eq(installedPlugins.identifier, id),
|
170
|
+
});
|
171
|
+
|
172
|
+
expect(result).toMatchObject({ settings });
|
160
173
|
});
|
161
174
|
});
|
162
175
|
});
|
@@ -1,42 +1,51 @@
|
|
1
1
|
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { clientDB } from '@/database/client/db';
|
4
|
+
import { PluginModel } from '@/database/server/models/plugin';
|
5
|
+
import { BaseClientService } from '@/services/baseClientService';
|
4
6
|
import { LobeTool } from '@/types/tool';
|
5
7
|
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
6
8
|
|
7
9
|
import { IPluginService, InstallPluginParams } from './type';
|
8
10
|
|
9
|
-
export class ClientService implements IPluginService {
|
11
|
+
export class ClientService extends BaseClientService implements IPluginService {
|
12
|
+
private get pluginModel(): PluginModel {
|
13
|
+
return new PluginModel(clientDB as any, this.userId);
|
14
|
+
}
|
15
|
+
|
10
16
|
installPlugin = async (plugin: InstallPluginParams) => {
|
11
|
-
|
17
|
+
await this.pluginModel.create(plugin);
|
18
|
+
return;
|
12
19
|
};
|
13
20
|
|
14
21
|
getInstalledPlugins = () => {
|
15
|
-
return
|
22
|
+
return this.pluginModel.query() as Promise<LobeTool[]>;
|
16
23
|
};
|
17
24
|
|
18
|
-
uninstallPlugin(identifier: string) {
|
19
|
-
|
25
|
+
async uninstallPlugin(identifier: string) {
|
26
|
+
await this.pluginModel.delete(identifier);
|
27
|
+
return;
|
20
28
|
}
|
21
29
|
|
22
30
|
async createCustomPlugin(customPlugin: LobeToolCustomPlugin) {
|
23
|
-
|
31
|
+
await this.pluginModel.create({ ...customPlugin, type: 'customPlugin' });
|
32
|
+
return;
|
24
33
|
}
|
25
34
|
|
26
35
|
async updatePlugin(id: string, value: LobeToolCustomPlugin) {
|
27
|
-
await
|
36
|
+
await this.pluginModel.update(id, value);
|
28
37
|
return;
|
29
38
|
}
|
30
39
|
async updatePluginManifest(id: string, manifest: LobeChatPluginManifest) {
|
31
|
-
await
|
40
|
+
await this.pluginModel.update(id, { manifest });
|
32
41
|
}
|
33
42
|
|
34
43
|
async removeAllPlugins() {
|
35
|
-
|
44
|
+
await this.pluginModel.deleteAll();
|
36
45
|
}
|
37
46
|
|
38
47
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
39
48
|
async updatePluginSettings(id: string, settings: any, _?: AbortSignal) {
|
40
|
-
await
|
49
|
+
await this.pluginModel.update(id, { settings });
|
41
50
|
}
|
42
51
|
}
|