@lobehub/chat 1.36.38 → 1.36.40

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 (60) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/common.json +7 -3
  4. package/locales/bg-BG/common.json +7 -3
  5. package/locales/de-DE/common.json +7 -3
  6. package/locales/en-US/common.json +7 -3
  7. package/locales/es-ES/common.json +7 -3
  8. package/locales/fa-IR/common.json +7 -3
  9. package/locales/fr-FR/common.json +7 -3
  10. package/locales/it-IT/common.json +7 -3
  11. package/locales/ja-JP/common.json +7 -3
  12. package/locales/ko-KR/common.json +7 -3
  13. package/locales/nl-NL/common.json +7 -3
  14. package/locales/pl-PL/common.json +7 -3
  15. package/locales/pt-BR/common.json +7 -3
  16. package/locales/ru-RU/common.json +7 -3
  17. package/locales/tr-TR/common.json +7 -3
  18. package/locales/vi-VN/common.json +7 -3
  19. package/locales/zh-CN/common.json +8 -4
  20. package/locales/zh-TW/common.json +7 -3
  21. package/package.json +1 -2
  22. package/src/app/(main)/(mobile)/me/(home)/page.tsx +2 -2
  23. package/src/app/(main)/(mobile)/me/data/page.tsx +2 -2
  24. package/src/app/(main)/(mobile)/me/profile/page.tsx +2 -2
  25. package/src/app/(main)/(mobile)/me/settings/page.tsx +2 -2
  26. package/src/app/(main)/chat/(workspace)/@conversation/default.tsx +3 -3
  27. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/index.tsx +1 -3
  28. package/src/app/(main)/chat/(workspace)/@portal/default.tsx +2 -2
  29. package/src/app/(main)/chat/(workspace)/@topic/default.tsx +2 -2
  30. package/src/app/(main)/chat/(workspace)/page.tsx +1 -1
  31. package/src/app/(main)/discover/(detail)/assistant/[slug]/page.tsx +1 -1
  32. package/src/app/(main)/discover/(detail)/model/[...slugs]/page.tsx +1 -1
  33. package/src/app/(main)/discover/(detail)/plugin/[slug]/page.tsx +1 -1
  34. package/src/app/(main)/discover/(detail)/provider/[slug]/page.tsx +1 -1
  35. package/src/app/(main)/discover/(list)/assistants/[slug]/page.tsx +1 -1
  36. package/src/app/(main)/discover/(list)/assistants/page.tsx +1 -1
  37. package/src/app/(main)/discover/(list)/models/[slug]/page.tsx +1 -1
  38. package/src/app/(main)/discover/(list)/models/page.tsx +1 -1
  39. package/src/app/(main)/discover/(list)/plugins/[slug]/page.tsx +1 -1
  40. package/src/app/(main)/discover/(list)/plugins/page.tsx +1 -1
  41. package/src/app/(main)/discover/(list)/providers/page.tsx +1 -1
  42. package/src/app/(main)/discover/search/page.tsx +1 -1
  43. package/src/app/(main)/profile/[[...slugs]]/page.tsx +3 -2
  44. package/src/app/(main)/profile/layout.tsx +3 -2
  45. package/src/app/(main)/profile/loading.tsx +2 -2
  46. package/src/app/(main)/settings/about/page.tsx +2 -2
  47. package/src/app/(main)/settings/sync/page.tsx +3 -3
  48. package/src/app/@modal/(.)settings/modal/page.tsx +3 -3
  49. package/src/app/layout.tsx +2 -2
  50. package/src/components/server/ServerLayout.tsx +2 -2
  51. package/src/database/schemas/user.ts +1 -0
  52. package/src/database/server/models/__tests__/user.test.ts +23 -19
  53. package/src/database/server/models/session.ts +3 -1
  54. package/src/database/server/models/user.ts +25 -58
  55. package/src/layout/GlobalProvider/index.tsx +1 -1
  56. package/src/locales/default/common.ts +6 -3
  57. package/src/server/modules/KeyVaultsEncrypt/index.ts +23 -0
  58. package/src/server/routers/lambda/user.ts +19 -2
  59. package/src/server/services/user/index.ts +5 -0
  60. package/src/utils/server/responsive.ts +4 -5
@@ -10,7 +10,9 @@
10
10
  }
11
11
  },
12
12
  "appLoading": {
13
+ "appIdle": "准备启动",
13
14
  "appInitializing": "应用启动中...",
15
+ "failed": "很抱歉,应用初始化失败,请查看详情进行排查",
14
16
  "finished": "数据库初始化完成",
15
17
  "goToChat": "对话页面加载中...",
16
18
  "initAuth": "鉴权服务初始化...",
@@ -19,7 +21,8 @@
19
21
  "loadingDependencies": "初始化依赖...",
20
22
  "loadingWasm": "加载 WASM 模块...",
21
23
  "migrating": "执行数据表迁移...",
22
- "ready": "数据库已就绪"
24
+ "ready": "数据库已就绪",
25
+ "showDetail": "查看详情"
23
26
  },
24
27
  "autoGenerate": "自动补全",
25
28
  "autoGenerateTooltip": "基于提示词自动补全助手描述",
@@ -36,12 +39,13 @@
36
39
  "title": "初始化 PGlite 数据库"
37
40
  },
38
41
  "error": {
39
- "desc": "非常抱歉,Pglite 数据库初始化过程发生异常。请点击 「重试」按钮。<br><br> 如仍然出错,请 <1>提交问题</1> ,我们将会第一时间帮你排查",
42
+ "desc": "非常抱歉,Pglite 数据库初始化过程发生异常。请点击按钮重试。如多次重试后仍重复出错,请 <1>提交问题</1> ,我们将会第一时间帮你排查",
43
+ "detail": "错误原因:[{{type}}] {{message}},明细如下:",
40
44
  "retry": "重试",
41
- "title": "数据库升级失败"
45
+ "title": "数据库初始化失败"
42
46
  },
43
47
  "initing": {
44
- "error": "发生错误,请重试",
48
+ "error": "数据库初始化出错,点击查看详情",
45
49
  "idle": "等待初始化...",
46
50
  "initializing": "正在初始化...",
47
51
  "loadingDependencies": "加载依赖中...",
@@ -10,7 +10,9 @@
10
10
  }
11
11
  },
12
12
  "appLoading": {
13
+ "appIdle": "準備啟動",
13
14
  "appInitializing": "應用啟動中...",
15
+ "failed": "很抱歉,應用初始化失敗,請查看詳情進行排查",
14
16
  "finished": "資料庫初始化完成",
15
17
  "goToChat": "對話頁面加載中...",
16
18
  "initAuth": "鑑權服務初始化...",
@@ -19,7 +21,8 @@
19
21
  "loadingDependencies": "初始化依賴...",
20
22
  "loadingWasm": "加載 WASM 模組...",
21
23
  "migrating": "執行資料表遷移...",
22
- "ready": "資料庫已就緒"
24
+ "ready": "資料庫已就緒",
25
+ "showDetail": "查看詳情"
23
26
  },
24
27
  "autoGenerate": "自動生成",
25
28
  "autoGenerateTooltip": "基於提示詞自動生成助手描述",
@@ -36,9 +39,10 @@
36
39
  "title": "初始化 PGlite 數據庫"
37
40
  },
38
41
  "error": {
39
- "desc": "非常抱歉,Pglite 數據庫初始化過程發生異常。請點擊 「重試」按鈕。<br><br> 如仍然出錯,請 <1>提交問題</1> ,我們將會第一時間幫你排查",
42
+ "desc": "非常抱歉,Pglite 資料庫初始化過程發生異常。請點擊按鈕重試。如多次重試後仍重複出錯,請 <1>提交問題</1> ,我們將會第一時間幫你排查",
43
+ "detail": "錯誤原因:[{{type}}] {{message}},明細如下:",
40
44
  "retry": "重試",
41
- "title": "數據庫升級失敗"
45
+ "title": "資料庫初始化失敗"
42
46
  },
43
47
  "initing": {
44
48
  "error": "發生錯誤,請重試",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.36.38",
3
+ "version": "1.36.40",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -162,7 +162,6 @@
162
162
  "i18next-resources-to-backend": "^1.2.1",
163
163
  "idb-keyval": "^6.2.1",
164
164
  "immer": "^10.1.1",
165
- "ip": "^2.0.1",
166
165
  "jose": "^5.9.4",
167
166
  "js-sha256": "^0.11.0",
168
167
  "jsonl-parse-stringify": "^1.0.3",
@@ -17,8 +17,8 @@ export const generateMetadata = async () => {
17
17
  });
18
18
  };
19
19
 
20
- const Page = () => {
21
- const mobile = isMobileDevice();
20
+ const Page = async () => {
21
+ const mobile = await isMobileDevice();
22
22
 
23
23
  if (!mobile) return redirect('/chat');
24
24
 
@@ -14,8 +14,8 @@ export const generateMetadata = async () => {
14
14
  });
15
15
  };
16
16
 
17
- const Page = () => {
18
- const mobile = isMobileDevice();
17
+ const Page = async () => {
18
+ const mobile = await isMobileDevice();
19
19
 
20
20
  if (!mobile) return redirect('/chat');
21
21
 
@@ -15,8 +15,8 @@ export const generateMetadata = async () => {
15
15
  });
16
16
  };
17
17
 
18
- const Page = () => {
19
- const mobile = isMobileDevice();
18
+ const Page = async () => {
19
+ const mobile = await isMobileDevice();
20
20
 
21
21
  if (!mobile) return redirect('/profile');
22
22
 
@@ -15,8 +15,8 @@ export const generateMetadata = async () => {
15
15
  });
16
16
  };
17
17
 
18
- const Page = () => {
19
- const mobile = isMobileDevice();
18
+ const Page = async () => {
19
+ const mobile = await isMobileDevice();
20
20
 
21
21
  if (!mobile) return redirect('/settings/common');
22
22
 
@@ -6,14 +6,14 @@ import ChatList from './features/ChatList';
6
6
  import ThreadHydration from './features/ThreadHydration';
7
7
  import ZenModeToast from './features/ZenModeToast';
8
8
 
9
- const ChatConversation = () => {
10
- const mobile = isMobileDevice();
9
+ const ChatConversation = async () => {
10
+ const mobile = await isMobileDevice();
11
11
 
12
12
  return (
13
13
  <>
14
14
  <ZenModeToast />
15
15
  <ChatList mobile={mobile} />
16
- <ChatInput />
16
+ <ChatInput mobile={mobile} />
17
17
  <ChatHydration />
18
18
  <ThreadHydration />
19
19
  </>
@@ -1,10 +1,8 @@
1
1
  import MobileChatInput from '@/features/ChatInput/Mobile';
2
- import { isMobileDevice } from '@/utils/server/responsive';
3
2
 
4
3
  import DesktopChatInput from './Desktop';
5
4
 
6
- const ChatInput = () => {
7
- const mobile = isMobileDevice();
5
+ const ChatInput = ({ mobile }: { mobile: boolean }) => {
8
6
  const Input = mobile ? MobileChatInput : DesktopChatInput;
9
7
 
10
8
  return <Input />;
@@ -8,8 +8,8 @@ import Mobile from './_layout/Mobile';
8
8
 
9
9
  const PortalBody = lazy(() => import('@/features/Portal/router'));
10
10
 
11
- const Inspector = () => {
12
- const mobile = isMobileDevice();
11
+ const Inspector = async () => {
12
+ const mobile = await isMobileDevice();
13
13
 
14
14
  const Layout = mobile ? Mobile : Desktop;
15
15
 
@@ -10,8 +10,8 @@ import SystemRole from './features/SystemRole';
10
10
 
11
11
  const TopicContent = lazy(() => import('./features/TopicListContent'));
12
12
 
13
- const Topic = () => {
14
- const mobile = isMobileDevice();
13
+ const Topic = async () => {
14
+ const mobile = await isMobileDevice();
15
15
 
16
16
  const Layout = mobile ? Mobile : Desktop;
17
17
 
@@ -18,7 +18,7 @@ export const generateMetadata = async () => {
18
18
  };
19
19
 
20
20
  const Page = async () => {
21
- const mobile = isMobileDevice();
21
+ const mobile = await isMobileDevice();
22
22
  const { t } = await translation('metadata');
23
23
  const ld = ldModule.generate({
24
24
  description: t('chat.title', { appName: BRANDING_NAME }),
@@ -62,7 +62,7 @@ const Page = async (props: DiscoverPageProps) => {
62
62
 
63
63
  const { slug: identifier } = params;
64
64
  const { t, locale } = await translation('metadata', searchParams?.hl);
65
- const mobile = isMobileDevice();
65
+ const mobile = await isMobileDevice();
66
66
 
67
67
  const discoverService = new DiscoverService();
68
68
  const data = await discoverService.getAssistantById(locale, identifier);
@@ -72,7 +72,7 @@ const Page = async (props: Props) => {
72
72
  const identifier = decodeURIComponent(slugs.join('/'));
73
73
  const { t, locale } = await translation('metadata', searchParams?.hl);
74
74
  const { t: td } = await translation('models', searchParams?.hl);
75
- const mobile = isMobileDevice();
75
+ const mobile = await isMobileDevice();
76
76
 
77
77
  const discoverService = new DiscoverService();
78
78
  const data = await discoverService.getModelById(locale, identifier);
@@ -64,7 +64,7 @@ const Page = async (props: DiscoverPageProps) => {
64
64
 
65
65
  const { slug: identifier } = params;
66
66
  const { t, locale } = await translation('metadata', searchParams?.hl);
67
- const mobile = isMobileDevice();
67
+ const mobile = await isMobileDevice();
68
68
 
69
69
  const discoverService = new DiscoverService();
70
70
  const data = await discoverService.getPluginById(locale, identifier, true);
@@ -62,7 +62,7 @@ const Page = async (props: DiscoverPageProps) => {
62
62
  const { slug: identifier } = params;
63
63
  const { t, locale } = await translation('metadata', searchParams?.hl);
64
64
  const { t: td } = await translation('models', searchParams?.hl);
65
- const mobile = isMobileDevice();
65
+ const mobile = await isMobileDevice();
66
66
 
67
67
  const discoverService = new DiscoverService();
68
68
  const data = await discoverService.getProviderById(locale, identifier);
@@ -32,7 +32,7 @@ const Page = async (props: DiscoverPageProps<AssistantCategory>) => {
32
32
 
33
33
  const { t, locale } = await translation('metadata', searchParams?.hl);
34
34
  const { t: td } = await translation('discover', searchParams?.hl);
35
- const mobile = isMobileDevice();
35
+ const mobile = await isMobileDevice();
36
36
 
37
37
  const discoverService = new DiscoverService();
38
38
  const items = await discoverService.getAssistantCategory(locale, params.slug);
@@ -25,7 +25,7 @@ export const generateMetadata = async (props: Props) => {
25
25
  const Page = async (props: Props) => {
26
26
  const searchParams = await props.searchParams;
27
27
  const { t, locale } = await translation('metadata', searchParams?.hl);
28
- const mobile = isMobileDevice();
28
+ const mobile = await isMobileDevice();
29
29
 
30
30
  const discoverService = new DiscoverService();
31
31
  const items = await discoverService.getAssistantList(locale);
@@ -35,7 +35,7 @@ const Page = async (props: DiscoverPageProps) => {
35
35
  const searchParams = await props.searchParams;
36
36
 
37
37
  const { t, locale } = await translation('metadata', searchParams?.hl);
38
- const mobile = isMobileDevice();
38
+ const mobile = await isMobileDevice();
39
39
 
40
40
  const discoverService = new DiscoverService();
41
41
  const list = await discoverService.getProviderList(locale);
@@ -29,7 +29,7 @@ const Page = async (props: Props) => {
29
29
  const searchParams = await props.searchParams;
30
30
 
31
31
  const { t, locale } = await translation('metadata', searchParams?.hl);
32
- const mobile = isMobileDevice();
32
+ const mobile = await isMobileDevice();
33
33
 
34
34
  const discoverService = new DiscoverService();
35
35
  const items = await discoverService.getModelList(locale);
@@ -32,7 +32,7 @@ const Page = async (props: DiscoverPageProps<PluginCategory>) => {
32
32
 
33
33
  const { t, locale } = await translation('metadata', searchParams?.hl);
34
34
  const { t: td } = await translation('discover', searchParams?.hl);
35
- const mobile = isMobileDevice();
35
+ const mobile = await isMobileDevice();
36
36
 
37
37
  const discoverService = new DiscoverService();
38
38
  const items = await discoverService.getPluginCategory(locale, params.slug);
@@ -26,7 +26,7 @@ export const generateMetadata = async (props: Props) => {
26
26
  const Page = async (props: Props) => {
27
27
  const searchParams = await props.searchParams;
28
28
  const { t, locale } = await translation('metadata', searchParams?.hl);
29
- const mobile = isMobileDevice();
29
+ const mobile = await isMobileDevice();
30
30
 
31
31
  const discoverService = new DiscoverService();
32
32
  const items = await discoverService.getPluginList(locale);
@@ -26,7 +26,7 @@ export const generateMetadata = async (props: Props) => {
26
26
  const Page = async (props: Props) => {
27
27
  const searchParams = await props.searchParams;
28
28
  const { t, locale } = await translation('metadata', searchParams?.hl);
29
- const mobile = isMobileDevice();
29
+ const mobile = await isMobileDevice();
30
30
 
31
31
  const discoverService = new DiscoverService();
32
32
  const items = await discoverService.getProviderList(locale);
@@ -56,7 +56,7 @@ const Page = async (props: Props) => {
56
56
  const keywords = decodeURIComponent(q);
57
57
 
58
58
  const { t, locale } = await translation('metadata', searchParams?.hl);
59
- const mobile = isMobileDevice();
59
+ const mobile = await isMobileDevice();
60
60
 
61
61
  const ld = ldModule.generate({
62
62
  description: t('discover.description'),
@@ -13,8 +13,9 @@ export const generateMetadata = async () => {
13
13
  });
14
14
  };
15
15
 
16
- const Page = () => {
17
- const mobile = isMobileDevice();
16
+ const Page = async () => {
17
+ const mobile = await isMobileDevice();
18
+
18
19
  return <Client mobile={mobile} />;
19
20
  };
20
21
 
@@ -6,10 +6,11 @@ import { isMobileDevice } from '@/utils/server/responsive';
6
6
 
7
7
  import MobileLayout from './_layout/Mobile';
8
8
 
9
- const Layout = ({ children }: PropsWithChildren) => {
9
+ const Layout = async ({ children }: PropsWithChildren) => {
10
10
  if (!enableClerk) return notFound();
11
11
 
12
- const mobile = isMobileDevice();
12
+ const mobile = await isMobileDevice();
13
+
13
14
  if (mobile) return <MobileLayout>{children}</MobileLayout>;
14
15
 
15
16
  return children;
@@ -3,8 +3,8 @@ import { Flexbox } from 'react-layout-kit';
3
3
  import SkeletonLoading from '@/components/SkeletonLoading';
4
4
  import { isMobileDevice } from '@/utils/server/responsive';
5
5
 
6
- const Loading = () => {
7
- const mobile = isMobileDevice();
6
+ const Loading = async () => {
7
+ const mobile = await isMobileDevice();
8
8
  if (mobile) return <SkeletonLoading paragraph={{ rows: 8 }} />;
9
9
  return (
10
10
  <Flexbox horizontal style={{ position: 'relative' }} width={'100%'}>
@@ -13,8 +13,8 @@ export const generateMetadata = async () => {
13
13
  });
14
14
  };
15
15
 
16
- export default () => {
17
- const isMobile = isMobileDevice();
16
+ export default async () => {
17
+ const isMobile = await isMobileDevice();
18
18
 
19
19
  return <Page mobile={isMobile} />;
20
20
  };
@@ -15,12 +15,12 @@ export const generateMetadata = async () => {
15
15
  url: '/settings/sync',
16
16
  });
17
17
  };
18
- export default () => {
18
+ export default async () => {
19
19
  const enableWebrtc = serverFeatureFlags().enableWebrtc;
20
20
  if (!enableWebrtc) return notFound();
21
21
 
22
- const isMobile = isMobileDevice();
23
- const { os, browser } = gerServerDeviceInfo();
22
+ const isMobile = await isMobileDevice();
23
+ const { os, browser } = await gerServerDeviceInfo();
24
24
 
25
25
  return <Page browser={browser} mobile={isMobile} os={os} />;
26
26
  };
@@ -7,9 +7,9 @@ import SettingsModal from './index';
7
7
  * @refs: https://github.com/lobehub/lobe-chat/discussions/2295#discussioncomment-9290942
8
8
  */
9
9
 
10
- const Page = () => {
11
- const isMobile = isMobileDevice();
12
- const { os, browser } = gerServerDeviceInfo();
10
+ const Page = async () => {
11
+ const isMobile = await isMobileDevice();
12
+ const { os, browser } = await gerServerDeviceInfo();
13
13
 
14
14
  return <SettingsModal browser={browser} mobile={isMobile} os={os} />;
15
15
  };
@@ -25,7 +25,7 @@ const RootLayout = async ({ children, modal }: RootLayoutProps) => {
25
25
  const locale = lang?.value || DEFAULT_LANG;
26
26
 
27
27
  const direction = isRtlLang(locale) ? 'rtl' : 'ltr';
28
- const mobile = isMobileDevice();
28
+ const mobile = await isMobileDevice();
29
29
 
30
30
  return (
31
31
  <html dir={direction} lang={locale} suppressHydrationWarning>
@@ -49,7 +49,7 @@ export default RootLayout;
49
49
  export { generateMetadata } from './metadata';
50
50
 
51
51
  export const generateViewport = async (): ResolvingViewport => {
52
- const isMobile = isMobileDevice();
52
+ const isMobile = await isMobileDevice();
53
53
 
54
54
  const dynamicScale = isMobile ? { maximumScale: 1, userScalable: false } : {};
55
55
 
@@ -9,8 +9,8 @@ interface ServerLayoutProps<T> {
9
9
 
10
10
  const ServerLayout =
11
11
  <T extends PropsWithChildren>({ Desktop, Mobile }: ServerLayoutProps<T>): FC<T> =>
12
- (props: T) => {
13
- const mobile = isMobileDevice();
12
+ async (props: T) => {
13
+ const mobile = await isMobileDevice();
14
14
  return mobile ? <Mobile {...props} /> : <Desktop {...props} />;
15
15
  };
16
16
 
@@ -46,6 +46,7 @@ export const userSettings = pgTable('user_settings', {
46
46
  defaultAgent: jsonb('default_agent'),
47
47
  tool: jsonb('tool'),
48
48
  });
49
+ export type UserSettingsItem = typeof userSettings.$inferSelect;
49
50
 
50
51
  export const installedPlugins = pgTable(
51
52
  'user_installed_plugins',
@@ -7,7 +7,7 @@ import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
7
7
  import { UserGuide, UserPreference } from '@/types/user';
8
8
  import { UserSettings } from '@/types/user/settings';
9
9
 
10
- import { userSettings, users } from '../../../schemas';
10
+ import { UserSettingsItem, userSettings, users } from '../../../schemas';
11
11
  import { SessionModel } from '../session';
12
12
  import { UserModel } from '../user';
13
13
 
@@ -101,7 +101,7 @@ describe('UserModel', () => {
101
101
  keyVaults: encryptedKeyVaults,
102
102
  });
103
103
 
104
- const state = await userModel.getUserState();
104
+ const state = await userModel.getUserState(KeyVaultsGateKeeper.getUserKeyVaults);
105
105
 
106
106
  expect(state.userId).toBe(userId);
107
107
  expect(state.preference).toEqual(preference);
@@ -111,7 +111,9 @@ describe('UserModel', () => {
111
111
  it('should throw an error if user not found', async () => {
112
112
  const userModel = new UserModel(serverDB, 'invalid-user-id');
113
113
 
114
- await expect(userModel.getUserState()).rejects.toThrow('user not found');
114
+ await expect(userModel.getUserState(KeyVaultsGateKeeper.getUserKeyVaults)).rejects.toThrow(
115
+ 'user not found',
116
+ );
115
117
  });
116
118
  });
117
119
 
@@ -144,11 +146,10 @@ describe('UserModel', () => {
144
146
  });
145
147
 
146
148
  describe('updateSetting', () => {
147
- it('should update user settings with encrypted keyVaults', async () => {
149
+ it('should update user settings with new item', async () => {
148
150
  const settings = {
149
151
  general: { language: 'en-US' },
150
- keyVaults: { openai: { apiKey: 'secret' } },
151
- } as UserSettings;
152
+ } as UserSettingsItem;
152
153
  await serverDB.insert(users).values({ id: userId });
153
154
 
154
155
  await userModel.updateSetting(settings);
@@ -157,23 +158,18 @@ describe('UserModel', () => {
157
158
  where: eq(users.id, userId),
158
159
  });
159
160
  expect(updatedSettings?.general).toEqual(settings.general);
160
- expect(updatedSettings?.keyVaults).not.toBe(JSON.stringify(settings.keyVaults));
161
-
162
- const gateKeeper = await KeyVaultsGateKeeper.initWithEnvKey();
163
- const { plaintext } = await gateKeeper.decrypt(updatedSettings!.keyVaults!);
164
- expect(JSON.parse(plaintext)).toEqual(settings.keyVaults);
165
161
  });
166
162
 
167
- it('should update user settings with encrypted keyVaults', async () => {
163
+ it('should update user settings with exist item', async () => {
168
164
  const settings = {
169
165
  general: { language: 'en-US' },
170
- } as UserSettings;
166
+ } as UserSettingsItem;
171
167
  await serverDB.insert(users).values({ id: userId });
172
168
  await serverDB.insert(userSettings).values({ ...settings, keyVaults: '', id: userId });
173
169
 
174
170
  const newSettings = {
175
171
  general: { fontSize: 16, language: 'zh-CN', themeMode: 'dark' },
176
- } as UserSettings;
172
+ } as UserSettingsItem;
177
173
  await userModel.updateSetting(newSettings);
178
174
 
179
175
  const updatedSettings = await serverDB.query.userSettings.findFirst({
@@ -229,14 +225,18 @@ describe('UserModel', () => {
229
225
  keyVaults: encryptedKeyVaults,
230
226
  });
231
227
 
232
- const result = await UserModel.getUserApiKeys(serverDB, userId);
228
+ const result = await UserModel.getUserApiKeys(
229
+ serverDB,
230
+ userId,
231
+ KeyVaultsGateKeeper.getUserKeyVaults,
232
+ );
233
233
  expect(result).toEqual(keyVaults);
234
234
  });
235
235
 
236
236
  it('should throw error when user not found', async () => {
237
- await expect(UserModel.getUserApiKeys(serverDB, 'non-existent-id')).rejects.toThrow(
238
- 'user not found',
239
- );
237
+ await expect(
238
+ UserModel.getUserApiKeys(serverDB, 'non-existent-id', KeyVaultsGateKeeper.getUserKeyVaults),
239
+ ).rejects.toThrow('user not found');
240
240
  });
241
241
 
242
242
  it('should handle decrypt failure and return empty object', async () => {
@@ -249,7 +249,11 @@ describe('UserModel', () => {
249
249
  keyVaults: invalidEncryptedData,
250
250
  });
251
251
 
252
- const result = await UserModel.getUserApiKeys(serverDB, userId);
252
+ const result = await UserModel.getUserApiKeys(
253
+ serverDB,
254
+ userId,
255
+ KeyVaultsGateKeeper.getUserKeyVaults,
256
+ );
253
257
  expect(result).toEqual({});
254
258
  });
255
259
  });
@@ -301,7 +301,9 @@ export class SessionModel {
301
301
  try {
302
302
  // @ts-expect-error
303
303
  return results.map((item) => item.agentsToSessions[0].session);
304
- } catch {}
304
+ } catch (e) {
305
+ console.error('findSessionsByKeywords error:', e);
306
+ }
305
307
  return [];
306
308
  };
307
309
  }