@lobehub/lobehub 2.0.0-next.46 → 2.0.0-next.47
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 +25 -0
- package/changelog/v1.json +9 -0
- package/package.json +1 -1
- package/packages/database/src/models/file.ts +15 -1
- package/packages/database/src/repositories/aiInfra/index.test.ts +1 -1
- package/packages/database/src/repositories/dataExporter/index.test.ts +1 -1
- package/packages/database/src/repositories/tableViewer/index.test.ts +1 -1
- package/packages/types/src/aiProvider.ts +1 -1
- package/packages/types/src/document/index.ts +38 -38
- package/packages/types/src/exportConfig.ts +15 -15
- package/packages/types/src/generation/index.ts +5 -5
- package/packages/types/src/openai/chat.ts +15 -15
- package/packages/types/src/plugins/mcp.ts +29 -29
- package/packages/types/src/plugins/protocol.ts +43 -43
- package/packages/types/src/search.ts +4 -4
- package/packages/types/src/tool/plugin.ts +3 -3
- package/src/app/(backend)/f/[id]/route.ts +55 -0
- package/src/envs/app.ts +4 -3
- package/src/features/Conversation/components/VirtualizedList/index.tsx +2 -1
- package/src/features/PluginsUI/Render/MCPType/index.tsx +26 -6
- package/src/server/routers/desktop/mcp.ts +23 -8
- package/src/server/routers/tools/mcp.ts +24 -4
- package/src/server/services/file/impls/local.ts +4 -1
- package/src/server/services/file/index.ts +96 -1
- package/src/server/services/mcp/contentProcessor.ts +101 -0
- package/src/server/services/mcp/index.test.ts +52 -10
- package/src/server/services/mcp/index.ts +29 -26
- package/src/services/session/index.ts +0 -14
- package/src/utils/server/routeVariants.test.ts +340 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_LANG } from '@/const/locale';
|
|
4
|
+
import { DynamicLayoutProps } from '@/types/next';
|
|
5
|
+
|
|
6
|
+
import { DEFAULT_VARIANTS, IRouteVariants, RouteVariants } from './routeVariants';
|
|
7
|
+
|
|
8
|
+
describe('RouteVariants', () => {
|
|
9
|
+
describe('DEFAULT_VARIANTS', () => {
|
|
10
|
+
it('should have correct default values', () => {
|
|
11
|
+
expect(DEFAULT_VARIANTS).toEqual({
|
|
12
|
+
isMobile: false,
|
|
13
|
+
locale: DEFAULT_LANG,
|
|
14
|
+
theme: 'light',
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('serializeVariants', () => {
|
|
20
|
+
it('should serialize variants with default values', () => {
|
|
21
|
+
const variants: IRouteVariants = {
|
|
22
|
+
isMobile: false,
|
|
23
|
+
locale: 'en-US',
|
|
24
|
+
theme: 'light',
|
|
25
|
+
};
|
|
26
|
+
const result = RouteVariants.serializeVariants(variants);
|
|
27
|
+
expect(result).toBe('en-US__0__light');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should serialize variants with mobile enabled', () => {
|
|
31
|
+
const variants: IRouteVariants = {
|
|
32
|
+
isMobile: true,
|
|
33
|
+
locale: 'zh-CN',
|
|
34
|
+
theme: 'dark',
|
|
35
|
+
};
|
|
36
|
+
const result = RouteVariants.serializeVariants(variants);
|
|
37
|
+
expect(result).toBe('zh-CN__1__dark');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should serialize variants with different locales', () => {
|
|
41
|
+
const variants: IRouteVariants = {
|
|
42
|
+
isMobile: false,
|
|
43
|
+
locale: 'ja-JP',
|
|
44
|
+
theme: 'light',
|
|
45
|
+
};
|
|
46
|
+
const result = RouteVariants.serializeVariants(variants);
|
|
47
|
+
expect(result).toBe('ja-JP__0__light');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should serialize variants with custom colors', () => {
|
|
51
|
+
const variants: IRouteVariants = {
|
|
52
|
+
isMobile: true,
|
|
53
|
+
locale: 'en-US',
|
|
54
|
+
neutralColor: '#cccccc',
|
|
55
|
+
primaryColor: '#ff0000',
|
|
56
|
+
theme: 'dark',
|
|
57
|
+
};
|
|
58
|
+
const result = RouteVariants.serializeVariants(variants);
|
|
59
|
+
expect(result).toBe('en-US__1__dark');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('deserializeVariants', () => {
|
|
64
|
+
it('should deserialize valid serialized string', () => {
|
|
65
|
+
const serialized = 'en-US__0__light';
|
|
66
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
67
|
+
expect(result).toEqual({
|
|
68
|
+
isMobile: false,
|
|
69
|
+
locale: 'en-US',
|
|
70
|
+
theme: 'light',
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should deserialize mobile variants', () => {
|
|
75
|
+
const serialized = 'zh-CN__1__dark';
|
|
76
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
77
|
+
expect(result).toEqual({
|
|
78
|
+
isMobile: true,
|
|
79
|
+
locale: 'zh-CN',
|
|
80
|
+
theme: 'dark',
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return default values for invalid serialized string', () => {
|
|
85
|
+
const serialized = 'invalid';
|
|
86
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
87
|
+
expect(result).toEqual(DEFAULT_VARIANTS);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should return default values for empty string', () => {
|
|
91
|
+
const serialized = '';
|
|
92
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
93
|
+
expect(result).toEqual(DEFAULT_VARIANTS);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should handle invalid locale by falling back to default', () => {
|
|
97
|
+
const serialized = 'invalid-locale__0__light';
|
|
98
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
99
|
+
expect(result).toEqual({
|
|
100
|
+
isMobile: false,
|
|
101
|
+
locale: DEFAULT_LANG,
|
|
102
|
+
theme: 'light',
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should handle invalid theme by falling back to default', () => {
|
|
107
|
+
const serialized = 'en-US__0__invalid-theme';
|
|
108
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
109
|
+
expect(result).toEqual({
|
|
110
|
+
isMobile: false,
|
|
111
|
+
locale: 'en-US',
|
|
112
|
+
theme: 'light',
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should handle malformed serialized string', () => {
|
|
117
|
+
const serialized = 'en-US';
|
|
118
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
119
|
+
expect(result).toEqual(DEFAULT_VARIANTS);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should handle isMobile value correctly for "0"', () => {
|
|
123
|
+
const serialized = 'en-US__0__dark';
|
|
124
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
125
|
+
expect(result.isMobile).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should handle isMobile value correctly for "1"', () => {
|
|
129
|
+
const serialized = 'en-US__1__dark';
|
|
130
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
131
|
+
expect(result.isMobile).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should handle isMobile value correctly for other values', () => {
|
|
135
|
+
const serialized = 'en-US__2__dark';
|
|
136
|
+
const result = RouteVariants.deserializeVariants(serialized);
|
|
137
|
+
expect(result.isMobile).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('getVariantsFromProps', () => {
|
|
142
|
+
it('should extract and deserialize variants from props', async () => {
|
|
143
|
+
const props: DynamicLayoutProps = {
|
|
144
|
+
params: Promise.resolve({ variants: 'en-US__0__light' }),
|
|
145
|
+
};
|
|
146
|
+
const result = await RouteVariants.getVariantsFromProps(props);
|
|
147
|
+
expect(result).toEqual({
|
|
148
|
+
isMobile: false,
|
|
149
|
+
locale: 'en-US',
|
|
150
|
+
theme: 'light',
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should handle mobile variants from props', async () => {
|
|
155
|
+
const props: DynamicLayoutProps = {
|
|
156
|
+
params: Promise.resolve({ variants: 'zh-CN__1__dark' }),
|
|
157
|
+
};
|
|
158
|
+
const result = await RouteVariants.getVariantsFromProps(props);
|
|
159
|
+
expect(result).toEqual({
|
|
160
|
+
isMobile: true,
|
|
161
|
+
locale: 'zh-CN',
|
|
162
|
+
theme: 'dark',
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should handle invalid variants in props', async () => {
|
|
167
|
+
const props: DynamicLayoutProps = {
|
|
168
|
+
params: Promise.resolve({ variants: 'invalid' }),
|
|
169
|
+
};
|
|
170
|
+
const result = await RouteVariants.getVariantsFromProps(props);
|
|
171
|
+
expect(result).toEqual(DEFAULT_VARIANTS);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('getIsMobile', () => {
|
|
176
|
+
it('should extract isMobile as false from props', async () => {
|
|
177
|
+
const props: DynamicLayoutProps = {
|
|
178
|
+
params: Promise.resolve({ variants: 'en-US__0__light' }),
|
|
179
|
+
};
|
|
180
|
+
const result = await RouteVariants.getIsMobile(props);
|
|
181
|
+
expect(result).toBe(false);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should extract isMobile as true from props', async () => {
|
|
185
|
+
const props: DynamicLayoutProps = {
|
|
186
|
+
params: Promise.resolve({ variants: 'en-US__1__dark' }),
|
|
187
|
+
};
|
|
188
|
+
const result = await RouteVariants.getIsMobile(props);
|
|
189
|
+
expect(result).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should return default isMobile for invalid props', async () => {
|
|
193
|
+
const props: DynamicLayoutProps = {
|
|
194
|
+
params: Promise.resolve({ variants: 'invalid' }),
|
|
195
|
+
};
|
|
196
|
+
const result = await RouteVariants.getIsMobile(props);
|
|
197
|
+
expect(result).toBe(DEFAULT_VARIANTS.isMobile);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('getLocale', () => {
|
|
202
|
+
it('should extract locale from props', async () => {
|
|
203
|
+
const props: DynamicLayoutProps = {
|
|
204
|
+
params: Promise.resolve({ variants: 'zh-CN__0__light' }),
|
|
205
|
+
};
|
|
206
|
+
const result = await RouteVariants.getLocale(props);
|
|
207
|
+
expect(result).toBe('zh-CN');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should extract different locale from props', async () => {
|
|
211
|
+
const props: DynamicLayoutProps = {
|
|
212
|
+
params: Promise.resolve({ variants: 'ja-JP__1__dark' }),
|
|
213
|
+
};
|
|
214
|
+
const result = await RouteVariants.getLocale(props);
|
|
215
|
+
expect(result).toBe('ja-JP');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should return default locale for invalid props', async () => {
|
|
219
|
+
const props: DynamicLayoutProps = {
|
|
220
|
+
params: Promise.resolve({ variants: 'invalid' }),
|
|
221
|
+
};
|
|
222
|
+
const result = await RouteVariants.getLocale(props);
|
|
223
|
+
expect(result).toBe(DEFAULT_LANG);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should return default locale for invalid locale in props', async () => {
|
|
227
|
+
const props: DynamicLayoutProps = {
|
|
228
|
+
params: Promise.resolve({ variants: 'invalid-locale__0__light' }),
|
|
229
|
+
};
|
|
230
|
+
const result = await RouteVariants.getLocale(props);
|
|
231
|
+
expect(result).toBe(DEFAULT_LANG);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
describe('createVariants', () => {
|
|
236
|
+
it('should create variants with default values when no options provided', () => {
|
|
237
|
+
const result = RouteVariants.createVariants();
|
|
238
|
+
expect(result).toEqual(DEFAULT_VARIANTS);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should create variants with custom isMobile', () => {
|
|
242
|
+
const result = RouteVariants.createVariants({ isMobile: true });
|
|
243
|
+
expect(result).toEqual({
|
|
244
|
+
...DEFAULT_VARIANTS,
|
|
245
|
+
isMobile: true,
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should create variants with custom locale', () => {
|
|
250
|
+
const result = RouteVariants.createVariants({ locale: 'zh-CN' });
|
|
251
|
+
expect(result).toEqual({
|
|
252
|
+
...DEFAULT_VARIANTS,
|
|
253
|
+
locale: 'zh-CN',
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should create variants with custom theme', () => {
|
|
258
|
+
const result = RouteVariants.createVariants({ theme: 'dark' });
|
|
259
|
+
expect(result).toEqual({
|
|
260
|
+
...DEFAULT_VARIANTS,
|
|
261
|
+
theme: 'dark',
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should create variants with multiple custom options', () => {
|
|
266
|
+
const result = RouteVariants.createVariants({
|
|
267
|
+
isMobile: true,
|
|
268
|
+
locale: 'ja-JP',
|
|
269
|
+
theme: 'dark',
|
|
270
|
+
});
|
|
271
|
+
expect(result).toEqual({
|
|
272
|
+
isMobile: true,
|
|
273
|
+
locale: 'ja-JP',
|
|
274
|
+
theme: 'dark',
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should create variants with custom colors', () => {
|
|
279
|
+
const result = RouteVariants.createVariants({
|
|
280
|
+
neutralColor: '#cccccc',
|
|
281
|
+
primaryColor: '#ff0000',
|
|
282
|
+
});
|
|
283
|
+
expect(result).toEqual({
|
|
284
|
+
...DEFAULT_VARIANTS,
|
|
285
|
+
neutralColor: '#cccccc',
|
|
286
|
+
primaryColor: '#ff0000',
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('should create variants with all custom options', () => {
|
|
291
|
+
const result = RouteVariants.createVariants({
|
|
292
|
+
isMobile: true,
|
|
293
|
+
locale: 'zh-CN',
|
|
294
|
+
neutralColor: '#aaaaaa',
|
|
295
|
+
primaryColor: '#00ff00',
|
|
296
|
+
theme: 'dark',
|
|
297
|
+
});
|
|
298
|
+
expect(result).toEqual({
|
|
299
|
+
isMobile: true,
|
|
300
|
+
locale: 'zh-CN',
|
|
301
|
+
neutralColor: '#aaaaaa',
|
|
302
|
+
primaryColor: '#00ff00',
|
|
303
|
+
theme: 'dark',
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
describe('roundtrip serialization', () => {
|
|
309
|
+
it('should maintain data integrity through serialize and deserialize', () => {
|
|
310
|
+
const original: IRouteVariants = {
|
|
311
|
+
isMobile: true,
|
|
312
|
+
locale: 'zh-CN',
|
|
313
|
+
theme: 'dark',
|
|
314
|
+
};
|
|
315
|
+
const serialized = RouteVariants.serializeVariants(original);
|
|
316
|
+
const deserialized = RouteVariants.deserializeVariants(serialized);
|
|
317
|
+
expect(deserialized).toEqual(original);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should maintain data integrity for default variants', () => {
|
|
321
|
+
const serialized = RouteVariants.serializeVariants(DEFAULT_VARIANTS);
|
|
322
|
+
const deserialized = RouteVariants.deserializeVariants(serialized);
|
|
323
|
+
expect(deserialized).toEqual(DEFAULT_VARIANTS);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should maintain data integrity for various locales', () => {
|
|
327
|
+
const locales = ['en-US', 'zh-CN', 'ja-JP', 'ko-KR', 'fr-FR'];
|
|
328
|
+
locales.forEach((locale) => {
|
|
329
|
+
const original: IRouteVariants = {
|
|
330
|
+
isMobile: false,
|
|
331
|
+
locale: locale as any,
|
|
332
|
+
theme: 'light',
|
|
333
|
+
};
|
|
334
|
+
const serialized = RouteVariants.serializeVariants(original);
|
|
335
|
+
const deserialized = RouteVariants.deserializeVariants(serialized);
|
|
336
|
+
expect(deserialized).toEqual(original);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|