@lobehub/chat 0.160.5 → 0.160.6

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 (57) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/locales/ar/error.json +2 -0
  3. package/locales/bg-BG/error.json +2 -0
  4. package/locales/de-DE/error.json +2 -0
  5. package/locales/en-US/error.json +2 -0
  6. package/locales/es-ES/error.json +2 -0
  7. package/locales/fr-FR/error.json +2 -0
  8. package/locales/it-IT/error.json +2 -0
  9. package/locales/ja-JP/error.json +2 -0
  10. package/locales/ko-KR/error.json +2 -0
  11. package/locales/nl-NL/error.json +2 -0
  12. package/locales/pl-PL/error.json +2 -0
  13. package/locales/pt-BR/error.json +2 -0
  14. package/locales/ru-RU/error.json +2 -0
  15. package/locales/tr-TR/error.json +2 -0
  16. package/locales/vi-VN/error.json +2 -0
  17. package/locales/zh-CN/error.json +2 -0
  18. package/locales/zh-TW/error.json +2 -0
  19. package/package.json +2 -2
  20. package/src/app/(loading)/Redirect.tsx +8 -0
  21. package/src/app/(main)/chat/(workspace)/features/TelemetryNotification.tsx +42 -75
  22. package/src/app/(main)/market/_layout/Desktop/index.tsx +24 -20
  23. package/src/app/(main)/settings/llm/Azure/index.tsx +1 -0
  24. package/src/app/(main)/settings/llm/OpenAI/index.tsx +0 -1
  25. package/src/app/trpc/edge/[trpc]/route.ts +1 -1
  26. package/src/components/FetchErrorNotification/Description.tsx +48 -0
  27. package/src/components/FetchErrorNotification/index.tsx +15 -0
  28. package/src/components/ModelProviderIcon/index.tsx +6 -1
  29. package/src/components/Notification/index.tsx +95 -0
  30. package/src/config/server/provider.ts +1 -0
  31. package/src/database/client/models/__tests__/message.test.ts +2 -2
  32. package/src/database/client/models/message.ts +2 -2
  33. package/src/features/User/UserAvatar.tsx +4 -3
  34. package/src/locales/default/error.ts +3 -1
  35. package/src/middleware.ts +10 -1
  36. package/src/server/globalConfig/index.ts +2 -0
  37. package/src/server/routers/edge/config/__snapshots__/index.test.ts.snap +1 -0
  38. package/src/services/file/type.ts +2 -3
  39. package/src/services/message/client.test.ts +151 -23
  40. package/src/services/message/client.ts +9 -5
  41. package/src/services/message/type.ts +10 -3
  42. package/src/services/upload.ts +4 -4
  43. package/src/services/user/client.ts +17 -1
  44. package/src/services/user/type.ts +14 -0
  45. package/src/store/chat/slices/enchance/action.test.ts +4 -3
  46. package/src/store/chat/slices/enchance/action.ts +3 -2
  47. package/src/store/chat/slices/plugin/action.test.ts +3 -5
  48. package/src/store/chat/slices/plugin/action.ts +1 -1
  49. package/src/store/market/action.ts +7 -0
  50. package/src/store/user/slices/auth/selectors.ts +1 -1
  51. package/src/store/user/slices/preference/action.test.ts +4 -9
  52. package/src/store/user/slices/preference/action.ts +17 -20
  53. package/src/store/user/slices/settings/selectors/modelConfig.test.ts +29 -1
  54. package/src/store/user/slices/settings/selectors/modelConfig.ts +1 -1
  55. package/src/tools/dalle/Render/Item/Error.tsx +1 -1
  56. package/src/types/files.ts +33 -0
  57. /package/src/types/{user.ts → user/index.ts} +0 -0
@@ -43,5 +43,5 @@ const isLogin = (s: UserStore) => {
43
43
  export const authSelectors = {
44
44
  isLogin,
45
45
  isLoginWithAuth: (s: UserStore) => s.isSignedIn,
46
- isLoginWithClerk: (s: UserStore) => s.isSignedIn && enableClerk,
46
+ isLoginWithClerk: (s: UserStore): boolean => (s.isSignedIn && enableClerk) || false,
47
47
  };
@@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
  import { withSWR } from '~test-utils';
4
4
 
5
5
  import { DEFAULT_PREFERENCE } from '@/const/user';
6
+ import { userService } from '@/services/user';
6
7
  import { useUserStore } from '@/store/user';
7
8
  import { UserGuide, UserPreference } from '@/types/user';
8
9
 
@@ -44,9 +45,7 @@ describe('createPreferenceSlice', () => {
44
45
  it('should return false when userId is empty', async () => {
45
46
  const { result } = renderHook(() => useUserStore());
46
47
 
47
- vi.spyOn(result.current.preferenceStorage, 'getFromLocalStorage').mockResolvedValueOnce(
48
- {} as any,
49
- );
48
+ vi.spyOn(userService, 'getPreference').mockResolvedValueOnce({} as any);
50
49
 
51
50
  const { result: prefernce } = renderHook(() => result.current.useInitPreference(), {
52
51
  wrapper: withSWR,
@@ -60,9 +59,7 @@ describe('createPreferenceSlice', () => {
60
59
  it('should return default preference when local storage is empty', async () => {
61
60
  const { result } = renderHook(() => useUserStore());
62
61
 
63
- vi.spyOn(result.current.preferenceStorage, 'getFromLocalStorage').mockResolvedValueOnce(
64
- {} as any,
65
- );
62
+ vi.spyOn(userService, 'getPreference').mockResolvedValueOnce({} as any);
66
63
 
67
64
  renderHook(() => result.current.useInitPreference(), {
68
65
  wrapper: withSWR,
@@ -82,9 +79,7 @@ describe('createPreferenceSlice', () => {
82
79
  guide: { topic: false, moveSettingsToAvatar: true },
83
80
  };
84
81
 
85
- vi.spyOn(result.current.preferenceStorage, 'getFromLocalStorage').mockResolvedValueOnce(
86
- savedPreference,
87
- );
82
+ vi.spyOn(userService, 'getPreference').mockResolvedValueOnce(savedPreference);
88
83
 
89
84
  const { result: prefernce } = renderHook(() => result.current.useInitPreference(), {
90
85
  wrapper: withSWR,
@@ -3,6 +3,7 @@ import type { StateCreator } from 'zustand/vanilla';
3
3
 
4
4
  import { DEFAULT_PREFERENCE } from '@/const/user';
5
5
  import { useClientDataSWR } from '@/libs/swr';
6
+ import { userService } from '@/services/user';
6
7
  import type { UserStore } from '@/store/user';
7
8
  import { UserGuide, UserPreference } from '@/types/user';
8
9
  import { merge } from '@/utils/merge';
@@ -11,8 +12,8 @@ import { setNamespace } from '@/utils/storeDebug';
11
12
  const n = setNamespace('preference');
12
13
 
13
14
  export interface PreferenceAction {
14
- updateGuideState: (guide: Partial<UserGuide>) => void;
15
- updatePreference: (preference: Partial<UserPreference>, action?: any) => void;
15
+ updateGuideState: (guide: Partial<UserGuide>) => Promise<void>;
16
+ updatePreference: (preference: Partial<UserPreference>, action?: any) => Promise<void>;
16
17
  useInitPreference: () => SWRResponse;
17
18
  }
18
19
 
@@ -22,33 +23,29 @@ export const createPreferenceSlice: StateCreator<
22
23
  [],
23
24
  PreferenceAction
24
25
  > = (set, get) => ({
25
- updateGuideState: (guide) => {
26
+ updateGuideState: async (guide) => {
26
27
  const { updatePreference } = get();
27
28
  const nextGuide = merge(get().preference.guide, guide);
28
- updatePreference({ guide: nextGuide });
29
+ await updatePreference({ guide: nextGuide });
29
30
  },
30
- updatePreference: (preference, action) => {
31
+ updatePreference: async (preference, action) => {
31
32
  const nextPreference = merge(get().preference, preference);
32
33
 
33
34
  set({ preference: nextPreference }, false, action || n('updatePreference'));
34
35
 
35
- get().preferenceStorage.saveToLocalStorage(nextPreference);
36
+ await userService.updatePreference(nextPreference);
36
37
  },
37
38
 
38
39
  useInitPreference: () =>
39
- useClientDataSWR<UserPreference>(
40
- 'initUserPreference',
41
- () => get().preferenceStorage.getFromLocalStorage(),
42
- {
43
- onSuccess: (preference) => {
44
- const isEmpty = Object.keys(preference).length === 0;
45
-
46
- set(
47
- { isPreferenceInit: true, preference: isEmpty ? DEFAULT_PREFERENCE : preference },
48
- false,
49
- n('initPreference'),
50
- );
51
- },
40
+ useClientDataSWR<UserPreference>('initUserPreference', userService.getPreference, {
41
+ onSuccess: (preference) => {
42
+ const isEmpty = Object.keys(preference).length === 0;
43
+
44
+ set(
45
+ { isPreferenceInit: true, preference: isEmpty ? DEFAULT_PREFERENCE : preference },
46
+ false,
47
+ n('initPreference'),
48
+ );
52
49
  },
53
- ),
50
+ }),
54
51
  });
@@ -1,8 +1,8 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
+ import { UserStore } from '@/store/user';
3
4
  import { merge } from '@/utils/merge';
4
5
 
5
- import { UserStore, useUserStore } from '../../../store';
6
6
  import { UserSettingsState, initialSettingsState } from '../initialState';
7
7
  import { modelConfigSelectors } from './modelConfig';
8
8
 
@@ -33,6 +33,34 @@ describe('modelConfigSelectors', () => {
33
33
  });
34
34
  });
35
35
 
36
+ describe('isProviderFetchOnClient', () => {
37
+ it('client fetch should disabled on default', () => {
38
+ const s = merge(initialSettingsState, {
39
+ settings: {
40
+ languageModel: {
41
+ azure: {
42
+ endpoint: 'endpoint',
43
+ apiKey: 'apikey',
44
+ },
45
+ },
46
+ },
47
+ } as UserSettingsState) as unknown as UserStore;
48
+
49
+ expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(false);
50
+ });
51
+
52
+ it('client fetch should enabled if user set it enabled', () => {
53
+ const s = merge(initialSettingsState, {
54
+ settings: {
55
+ languageModel: {
56
+ azure: { fetchOnClient: true },
57
+ },
58
+ },
59
+ } as UserSettingsState) as unknown as UserStore;
60
+ expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(true);
61
+ });
62
+ });
63
+
36
64
  describe('getCustomModelCardById', () => {
37
65
  it('should return the custom model card with the given id and provider', () => {
38
66
  const s = merge(initialSettingsState, {
@@ -13,7 +13,7 @@ const isProviderFetchOnClient = (provider: GlobalLLMProviderKey | string) => (s:
13
13
  const config = getProviderConfigById(provider)(s);
14
14
  if (typeof config?.fetchOnClient !== 'undefined') return config?.fetchOnClient;
15
15
 
16
- return isProviderEndpointNotEmpty(provider)(s);
16
+ return false;
17
17
  };
18
18
 
19
19
  const getCustomModelCard =
@@ -28,7 +28,7 @@ const Error = memo<ErrorProps>(({ messageId, index }) => {
28
28
  <Alert
29
29
  extra={
30
30
  <Highlighter copyButtonSize={'small'} language={'json'}>
31
- {JSON.stringify(error.body, null, 2)}
31
+ {JSON.stringify(error?.body || error, null, 2)}
32
32
  </Highlighter>
33
33
  }
34
34
  extraDefaultExpand
@@ -1,3 +1,5 @@
1
+ import { z } from 'zod';
2
+
1
3
  export interface FilePreview {
2
4
  base64Url?: string;
3
5
  data?: ArrayBuffer;
@@ -6,3 +8,34 @@ export interface FilePreview {
6
8
  saveMode: 'local' | 'url';
7
9
  url: string;
8
10
  }
11
+
12
+ export const UploadFileSchema = z.object({
13
+ data: z.instanceof(ArrayBuffer).optional(),
14
+ /**
15
+ * file type
16
+ * @example 'image/png'
17
+ */
18
+ fileType: z.string(),
19
+ metadata: z.any().optional(),
20
+ /**
21
+ * file name
22
+ * @example 'test.png'
23
+ */
24
+ name: z.string(),
25
+ /**
26
+ * the mode database save the file
27
+ * local mean save the raw file into data
28
+ * url mean upload the file to a cdn and then save the url
29
+ */
30
+ saveMode: z.enum(['local', 'url']),
31
+ /**
32
+ * file size
33
+ */
34
+ size: z.number(),
35
+ /**
36
+ * file url if saveMode is url
37
+ */
38
+ url: z.string().optional(),
39
+ });
40
+
41
+ export type UploadFileParams = z.infer<typeof UploadFileSchema>;
File without changes