@lobehub/chat 1.119.2 → 1.120.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 (74) hide show
  1. package/.vscode/settings.json +2 -3
  2. package/CHANGELOG.md +58 -0
  3. package/changelog/v1.json +21 -0
  4. package/locales/ar/models.json +24 -3
  5. package/locales/bg-BG/models.json +24 -3
  6. package/locales/de-DE/models.json +24 -3
  7. package/locales/en-US/models.json +24 -3
  8. package/locales/es-ES/models.json +24 -3
  9. package/locales/fa-IR/models.json +24 -3
  10. package/locales/fr-FR/models.json +24 -3
  11. package/locales/it-IT/models.json +24 -3
  12. package/locales/ja-JP/models.json +24 -3
  13. package/locales/ko-KR/models.json +24 -3
  14. package/locales/nl-NL/models.json +24 -3
  15. package/locales/pl-PL/models.json +24 -3
  16. package/locales/pt-BR/models.json +24 -3
  17. package/locales/ru-RU/models.json +24 -3
  18. package/locales/tr-TR/models.json +24 -3
  19. package/locales/vi-VN/models.json +24 -3
  20. package/locales/zh-CN/models.json +24 -3
  21. package/locales/zh-TW/models.json +24 -3
  22. package/package.json +2 -5
  23. package/packages/database/src/models/__tests__/generationBatch.test.ts +47 -1
  24. package/packages/database/src/models/generationBatch.ts +8 -1
  25. package/packages/model-bank/src/aiModels/aihubmix.ts +1 -1
  26. package/packages/model-bank/src/aiModels/google.ts +4 -4
  27. package/packages/model-bank/src/aiModels/openrouter.ts +2 -2
  28. package/packages/model-bank/src/aiModels/qwen.ts +3 -1
  29. package/packages/model-bank/src/aiModels/siliconcloud.ts +6 -0
  30. package/packages/model-bank/src/aiModels/vertexai.ts +2 -2
  31. package/packages/model-runtime/src/google/createImage.ts +52 -24
  32. package/packages/model-runtime/src/qwen/index.ts +1 -1
  33. package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
  34. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +2 -16
  35. package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +1 -3
  36. package/src/app/[variants]/(main)/chat/@session/_layout/Mobile/SessionHeader.tsx +1 -3
  37. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
  38. package/src/config/featureFlags/schema.test.ts +1 -2
  39. package/src/config/featureFlags/schema.ts +0 -6
  40. package/src/config/featureFlags/utils/parser.test.ts +7 -7
  41. package/src/database/_deprecated/core/index.ts +0 -1
  42. package/src/database/_deprecated/core/model.ts +4 -38
  43. package/src/database/_deprecated/models/message.ts +1 -1
  44. package/src/layout/GlobalProvider/StoreInitialization.tsx +0 -3
  45. package/src/store/serverConfig/selectors.test.ts +0 -1
  46. package/src/store/user/initialState.ts +1 -4
  47. package/src/store/user/selectors.ts +0 -1
  48. package/src/store/user/store.ts +1 -4
  49. package/docs/self-hosting/advanced/webrtc.mdx +0 -86
  50. package/docs/self-hosting/advanced/webrtc.zh-CN.mdx +0 -80
  51. package/src/app/[variants]/(main)/settings/sync/features/Alert.tsx +0 -53
  52. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/Card.tsx +0 -42
  53. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/DeviceName.tsx +0 -62
  54. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/SystemIcon.tsx +0 -31
  55. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/index.tsx +0 -103
  56. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/ChannelNameInput.tsx +0 -45
  57. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.css +0 -238
  58. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.tsx +0 -79
  59. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/generateRandomRoomName.ts +0 -4
  60. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/index.tsx +0 -103
  61. package/src/app/[variants]/(main)/settings/sync/index.tsx +0 -17
  62. package/src/app/[variants]/(main)/settings/sync/page.tsx +0 -29
  63. package/src/database/_deprecated/core/sync.ts +0 -321
  64. package/src/features/SyncStatusInspector/DisableSync.tsx +0 -79
  65. package/src/features/SyncStatusInspector/EnableSync.tsx +0 -132
  66. package/src/features/SyncStatusInspector/EnableTag.tsx +0 -66
  67. package/src/features/SyncStatusInspector/index.tsx +0 -27
  68. package/src/hooks/useSyncData.ts +0 -50
  69. package/src/services/__tests__/sync.test.ts +0 -56
  70. package/src/services/sync.ts +0 -19
  71. package/src/store/user/slices/sync/action.test.ts +0 -164
  72. package/src/store/user/slices/sync/action.ts +0 -101
  73. package/src/store/user/slices/sync/initialState.ts +0 -13
  74. package/src/store/user/slices/sync/selectors.ts +0 -20
@@ -1,56 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
-
3
- import { dataSync } from '@/database/_deprecated/core';
4
- import { StartDataSyncParams } from '@/types/sync';
5
-
6
- import { syncService } from '../sync';
7
-
8
- vi.mock('@/database/_deprecated/core', () => ({
9
- dataSync: {
10
- startDataSync: vi.fn(),
11
- disconnect: vi.fn(),
12
- },
13
- }));
14
-
15
- describe('SyncService', () => {
16
- afterEach(() => {
17
- vi.resetAllMocks();
18
- });
19
-
20
- describe('enabledSync', () => {
21
- it('should return false when running on server side', async () => {
22
- const params = { user: { id: '123' }, authToken: 'abc' } as unknown as StartDataSyncParams;
23
-
24
- const origin = global.window;
25
-
26
- // @ts-ignore
27
- global.window = undefined;
28
-
29
- const result = await syncService.enabledSync(params);
30
-
31
- expect(result).toBe(false);
32
- expect(dataSync.startDataSync).not.toHaveBeenCalled();
33
-
34
- // reset
35
- global.window = origin;
36
- });
37
-
38
- it('should start data sync and return true when running on client side', async () => {
39
- const params = { user: { id: '123' }, authToken: 'abc' } as unknown as StartDataSyncParams;
40
-
41
- const result = await syncService.enabledSync(params);
42
-
43
- expect(result).toBe(true);
44
- expect(dataSync.startDataSync).toHaveBeenCalledWith(params);
45
- });
46
- });
47
-
48
- describe('disableSync', () => {
49
- it('should disconnect data sync and return false', async () => {
50
- const result = await syncService.disableSync();
51
-
52
- expect(result).toBe(false);
53
- expect(dataSync.disconnect).toHaveBeenCalled();
54
- });
55
- });
56
- });
@@ -1,19 +0,0 @@
1
- import { dataSync } from '@/database/_deprecated/core';
2
- import { StartDataSyncParams } from '@/types/sync';
3
-
4
- class SyncService {
5
- enabledSync = async (params: StartDataSyncParams) => {
6
- if (typeof window === 'undefined') return false;
7
-
8
- await dataSync.startDataSync(params);
9
- return true;
10
- };
11
-
12
- disableSync = async () => {
13
- await dataSync.disconnect();
14
-
15
- return false;
16
- };
17
- }
18
-
19
- export const syncService = new SyncService();
@@ -1,164 +0,0 @@
1
- import { act, renderHook, waitFor } from '@testing-library/react';
2
- import { afterEach, describe, expect, it, vi } from 'vitest';
3
- import { withSWR } from '~test-utils';
4
-
5
- import { syncService } from '@/services/sync';
6
- import { useUserStore } from '@/store/user';
7
- import { userProfileSelectors } from '@/store/user/selectors';
8
- import { syncSettingsSelectors } from '@/store/user/selectors';
9
-
10
- vi.mock('zustand/traditional');
11
-
12
- vi.mock('swr', async (importOriginal) => {
13
- const modules = await importOriginal();
14
- return {
15
- ...(modules as any),
16
- mutate: vi.fn(),
17
- };
18
- });
19
-
20
- afterEach(() => {
21
- vi.restoreAllMocks();
22
- });
23
-
24
- describe('createSyncSlice', () => {
25
- describe('refreshConnection', () => {
26
- it('should not call triggerEnableSync when userId is empty', async () => {
27
- const { result } = renderHook(() => useUserStore());
28
- const onEvent = vi.fn();
29
-
30
- vi.spyOn(userProfileSelectors, 'userId').mockReturnValueOnce(undefined as any);
31
- const triggerEnableSyncSpy = vi.spyOn(result.current, 'triggerEnableSync');
32
-
33
- await act(async () => {
34
- await result.current.refreshConnection(onEvent);
35
- });
36
-
37
- expect(triggerEnableSyncSpy).not.toHaveBeenCalled();
38
- });
39
-
40
- it('should call triggerEnableSync when userId exists', async () => {
41
- const { result } = renderHook(() => useUserStore());
42
- const onEvent = vi.fn();
43
- const userId = 'user-id';
44
-
45
- vi.spyOn(userProfileSelectors, 'userId').mockReturnValueOnce(userId);
46
- const triggerEnableSyncSpy = vi.spyOn(result.current, 'triggerEnableSync');
47
-
48
- await act(async () => {
49
- await result.current.refreshConnection(onEvent);
50
- });
51
-
52
- expect(triggerEnableSyncSpy).toHaveBeenCalledWith(userId, onEvent);
53
- });
54
- });
55
-
56
- describe('triggerEnableSync', () => {
57
- it('should return false when sync.channelName is empty', async () => {
58
- const { result } = renderHook(() => useUserStore());
59
- const userId = 'user-id';
60
- const onEvent = vi.fn();
61
-
62
- vi.spyOn(syncSettingsSelectors, 'webrtcConfig').mockReturnValueOnce({
63
- channelName: '',
64
- enabled: true,
65
- });
66
-
67
- const data = await act(async () => {
68
- return result.current.triggerEnableSync(userId, onEvent);
69
- });
70
-
71
- expect(data).toBe(false);
72
- });
73
-
74
- it('should call globalService.enabledSync when sync.channelName exists', async () => {
75
- const userId = 'user-id';
76
- const onEvent = vi.fn();
77
- const channelName = 'channel-name';
78
- const channelPassword = 'channel-password';
79
- const deviceName = 'device-name';
80
- const signaling = 'signaling';
81
-
82
- vi.spyOn(syncSettingsSelectors, 'webrtcConfig').mockReturnValueOnce({
83
- channelName,
84
- channelPassword,
85
- signaling,
86
- enabled: true,
87
- });
88
- vi.spyOn(syncSettingsSelectors, 'deviceName').mockReturnValueOnce(deviceName);
89
- const enabledSyncSpy = vi.spyOn(syncService, 'enabledSync').mockResolvedValueOnce(true);
90
- const { result } = renderHook(() => useUserStore());
91
-
92
- const data = await act(async () => {
93
- return result.current.triggerEnableSync(userId, onEvent);
94
- });
95
-
96
- expect(enabledSyncSpy).toHaveBeenCalledWith({
97
- channel: { name: channelName, password: channelPassword },
98
- onAwarenessChange: expect.any(Function),
99
- onSyncEvent: onEvent,
100
- onSyncStatusChange: expect.any(Function),
101
- signaling,
102
- user: expect.objectContaining({ id: userId, name: deviceName }),
103
- });
104
- expect(data).toBe(true);
105
- });
106
- });
107
-
108
- describe('useEnabledSync', () => {
109
- it('should return false when userId is empty', async () => {
110
- const { result } = renderHook(
111
- () =>
112
- useUserStore().useEnabledSync(true, {
113
- userEnableSync: true,
114
- userId: undefined,
115
- onEvent: vi.fn(),
116
- }),
117
- {
118
- wrapper: withSWR,
119
- },
120
- );
121
-
122
- await waitFor(() => expect(result.current.data).toBe(false));
123
- });
124
-
125
- it('should call syncService.disableSync when userEnableSync is false', async () => {
126
- const disableSyncSpy = vi.spyOn(syncService, 'disableSync').mockResolvedValueOnce(false);
127
-
128
- const { result } = renderHook(
129
- () =>
130
- useUserStore().useEnabledSync(true, {
131
- userEnableSync: false,
132
- userId: 'user-id',
133
- onEvent: vi.fn(),
134
- }),
135
-
136
- { wrapper: withSWR },
137
- );
138
-
139
- await waitFor(() => expect(result.current.data).toBeUndefined());
140
- expect(disableSyncSpy).toHaveBeenCalled();
141
- });
142
-
143
- it('should call triggerEnableSync when userEnableSync and userId exist', async () => {
144
- const userId = 'user-id';
145
- const onEvent = vi.fn();
146
- const triggerEnableSyncSpy = vi.fn().mockResolvedValueOnce(true);
147
-
148
- const { result } = renderHook(() => useUserStore());
149
-
150
- // replace triggerEnableSync as a mock
151
- result.current.triggerEnableSync = triggerEnableSyncSpy;
152
-
153
- const { result: swrResult } = renderHook(
154
- () => result.current.useEnabledSync(true, { userEnableSync: true, userId, onEvent }),
155
- {
156
- wrapper: withSWR,
157
- },
158
- );
159
-
160
- await waitFor(() => expect(swrResult.current.data).toBe(true));
161
- expect(triggerEnableSyncSpy).toHaveBeenCalledWith(userId, onEvent);
162
- });
163
- });
164
- });
@@ -1,101 +0,0 @@
1
- import useSWR, { SWRResponse } from 'swr';
2
- import type { StateCreator } from 'zustand/vanilla';
3
-
4
- import type { UserStore } from '@/store/user';
5
- import { OnSyncEvent, PeerSyncStatus } from '@/types/sync';
6
- import { browserInfo } from '@/utils/platform';
7
- import { setNamespace } from '@/utils/storeDebug';
8
-
9
- import { userProfileSelectors } from '../auth/selectors';
10
- import { syncSettingsSelectors } from './selectors';
11
-
12
- const n = setNamespace('sync');
13
-
14
- /**
15
- * 设置操作
16
- */
17
- export interface SyncAction {
18
- refreshConnection: (onEvent: OnSyncEvent) => Promise<void>;
19
- triggerEnableSync: (userId: string, onEvent: OnSyncEvent) => Promise<boolean>;
20
- useEnabledSync: (
21
- systemEnable: boolean | undefined,
22
- params: {
23
- onEvent: OnSyncEvent;
24
- userEnableSync: boolean;
25
- userId: string | undefined;
26
- },
27
- ) => SWRResponse;
28
- }
29
-
30
- export const createSyncSlice: StateCreator<
31
- UserStore,
32
- [['zustand/devtools', never]],
33
- [],
34
- SyncAction
35
- > = (set, get) => ({
36
- refreshConnection: async (onEvent) => {
37
- const userId = userProfileSelectors.userId(get());
38
-
39
- if (!userId) return;
40
-
41
- await get().triggerEnableSync(userId, onEvent);
42
- },
43
-
44
- triggerEnableSync: async (userId: string, onEvent: OnSyncEvent) => {
45
- // double-check the sync ability
46
- // if there is no channelName, don't start sync
47
- const sync = syncSettingsSelectors.webrtcConfig(get());
48
- if (!sync.channelName || !sync.signaling) return false;
49
-
50
- const name = syncSettingsSelectors.deviceName(get());
51
-
52
- const defaultUserName = `My ${browserInfo.browser} (${browserInfo.os})`;
53
-
54
- set({ syncStatus: PeerSyncStatus.Connecting });
55
- const { syncService } = await import('@/services/sync');
56
-
57
- return syncService.enabledSync({
58
- channel: {
59
- name: sync.channelName,
60
- password: sync.channelPassword,
61
- },
62
- onAwarenessChange(state) {
63
- set({ syncAwareness: state });
64
- },
65
- onSyncEvent: onEvent,
66
- onSyncStatusChange: (status) => {
67
- set({ syncStatus: status });
68
- },
69
- signaling: sync.signaling,
70
- user: {
71
- id: userId,
72
- // if user don't set the name, use default name
73
- name: name || defaultUserName,
74
- ...browserInfo,
75
- },
76
- });
77
- },
78
-
79
- useEnabledSync: (systemEnable, { userEnableSync, userId, onEvent }) =>
80
- useSWR<boolean>(
81
- systemEnable ? ['enableSync', userEnableSync, userId] : null,
82
- async () => {
83
- // if user don't enable sync or no userId ,don't start sync
84
- if (!userId) return false;
85
-
86
- // if user don't enable sync, stop sync
87
- if (!userEnableSync) {
88
- const { syncService } = await import('@/services/sync');
89
- return syncService.disableSync();
90
- }
91
-
92
- return get().triggerEnableSync(userId, onEvent);
93
- },
94
- {
95
- onSuccess: (syncEnabled) => {
96
- set({ syncEnabled }, false, n('useEnabledSync'));
97
- },
98
- revalidateOnFocus: false,
99
- },
100
- ),
101
- });
@@ -1,13 +0,0 @@
1
- import { PeerSyncStatus, SyncAwarenessState } from '@/types/sync';
2
-
3
- export interface UserSyncState {
4
- syncAwareness: SyncAwarenessState[];
5
- syncEnabled: boolean;
6
- syncStatus: PeerSyncStatus;
7
- }
8
-
9
- export const initialSyncState: UserSyncState = {
10
- syncAwareness: [],
11
- syncEnabled: false,
12
- syncStatus: PeerSyncStatus.Disabled,
13
- };
@@ -1,20 +0,0 @@
1
- import { DEFAULT_SYNC_CONFIG } from '@/const/settings/sync';
2
- import { UserSyncSettings } from '@/types/user/settings';
3
-
4
- import type { UserStore } from '../../store';
5
- import { currentSettings } from '../settings/selectors/settings';
6
-
7
- const syncConfig = (s: UserStore): UserSyncSettings =>
8
- currentSettings(s).sync || DEFAULT_SYNC_CONFIG;
9
-
10
- const webrtcConfig = (s: UserStore) => syncConfig(s).webrtc;
11
- const webrtcChannelName = (s: UserStore) => webrtcConfig(s).channelName;
12
- const enableWebRTC = (s: UserStore) => webrtcConfig(s).enabled;
13
- const deviceName = (s: UserStore) => syncConfig(s).deviceName;
14
-
15
- export const syncSettingsSelectors = {
16
- deviceName,
17
- enableWebRTC,
18
- webrtcChannelName,
19
- webrtcConfig,
20
- };