@lobehub/chat 1.51.16 → 1.52.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.
- package/.env.example +1 -0
- package/CHANGELOG.md +50 -0
- package/Dockerfile.database +2 -1
- package/changelog/v1.json +18 -0
- package/next.config.ts +1 -0
- package/package.json +1 -1
- package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +3 -2
- package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +6 -6
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/UserBanner.tsx +3 -6
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/useCategory.tsx +2 -2
- package/src/app/[variants]/(main)/(mobile)/me/(home)/page.tsx +0 -2
- package/src/app/[variants]/(main)/(mobile)/me/profile/features/Category.tsx +2 -2
- package/src/app/[variants]/(main)/(mobile)/me/profile/page.tsx +0 -2
- package/src/app/[variants]/(main)/(mobile)/me/settings/page.tsx +0 -2
- package/src/app/[variants]/(main)/discover/search/page.tsx +0 -2
- package/src/app/[variants]/(main)/layout.tsx +0 -2
- package/src/app/[variants]/(main)/profile/(home)/Client.tsx +2 -2
- package/src/app/[variants]/(main)/profile/hooks/useCategory.tsx +2 -4
- package/src/app/[variants]/(main)/settings/_layout/Mobile/Header.tsx +1 -3
- package/src/app/[variants]/(main)/settings/layout.ts +0 -2
- package/src/app/[variants]/page.tsx +0 -1
- package/src/config/auth.ts +1 -2
- package/src/const/auth.ts +1 -2
- package/src/features/User/UserPanel/PanelContent.tsx +3 -7
- package/src/features/User/UserPanel/useMenu.tsx +2 -2
- package/src/features/User/__tests__/PanelContent.test.tsx +6 -7
- package/src/features/User/__tests__/useMenu.test.tsx +1 -1
- package/src/layout/GlobalProvider/StoreInitialization.tsx +5 -2
- package/src/layout/GlobalProvider/index.tsx +2 -2
- package/src/middleware.ts +7 -10
- package/src/server/routers/edge/config/index.test.ts +7 -7
- package/src/server/routers/edge/config/index.ts +7 -2
- package/src/services/__tests__/global.test.ts +6 -3
- package/src/services/chat.ts +2 -1
- package/src/services/global.ts +2 -2
- package/src/store/serverConfig/action.ts +36 -0
- package/src/store/serverConfig/index.ts +0 -1
- package/src/store/serverConfig/store.test.ts +1 -1
- package/src/store/serverConfig/store.ts +16 -9
- package/src/store/user/slices/auth/action.test.ts +4 -2
- package/src/store/user/slices/auth/action.ts +2 -4
- package/src/store/user/slices/auth/initialState.ts +0 -1
- package/src/store/user/slices/auth/selectors.ts +5 -7
- package/src/store/user/slices/common/action.ts +0 -1
- package/src/types/serverConfig.ts +6 -0
- package/src/libs/agent-runtime/togetherai/__snapshots__/index.test.ts.snap +0 -2190
@@ -1,7 +1,7 @@
|
|
1
1
|
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
|
2
2
|
|
3
3
|
import { edgeClient } from '@/libs/trpc/client';
|
4
|
-
import {
|
4
|
+
import { GlobalRuntimeConfig } from '@/types/serverConfig';
|
5
5
|
|
6
6
|
import { globalService } from '../global';
|
7
7
|
|
@@ -77,14 +77,17 @@ describe('GlobalService', () => {
|
|
77
77
|
describe('ServerConfig', () => {
|
78
78
|
it('should return the serverConfig when fetch is successful', async () => {
|
79
79
|
// Arrange
|
80
|
-
const mockConfig = {
|
80
|
+
const mockConfig = {
|
81
|
+
serverConfig: { enabledOAuthSSO: true },
|
82
|
+
serverFeatureFlags: {},
|
83
|
+
} as GlobalRuntimeConfig;
|
81
84
|
vi.spyOn(edgeClient.config.getGlobalConfig, 'query').mockResolvedValue(mockConfig);
|
82
85
|
|
83
86
|
// Act
|
84
87
|
const config = await globalService.getGlobalConfig();
|
85
88
|
|
86
89
|
// Assert
|
87
|
-
expect(config).toEqual(
|
90
|
+
expect(config).toEqual(mockConfig);
|
88
91
|
});
|
89
92
|
|
90
93
|
it('should return the defaultAgentConfig when fetch is successful', async () => {
|
package/src/services/chat.ts
CHANGED
@@ -3,6 +3,7 @@ import { produce } from 'immer';
|
|
3
3
|
import { merge } from 'lodash-es';
|
4
4
|
|
5
5
|
import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
|
6
|
+
import { enableAuth } from '@/const/auth';
|
6
7
|
import { INBOX_GUIDE_SYSTEMROLE } from '@/const/guide';
|
7
8
|
import { INBOX_SESSION_ID } from '@/const/session';
|
8
9
|
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
@@ -515,7 +516,7 @@ class ChatService {
|
|
515
516
|
* if enable login and not signed in, return unauthorized error
|
516
517
|
*/
|
517
518
|
const userStore = useUserStore.getState();
|
518
|
-
if (
|
519
|
+
if (enableAuth && !userStore.isSignedIn) {
|
519
520
|
throw AgentRuntimeError.createError(ChatErrorType.InvalidAccessCode);
|
520
521
|
}
|
521
522
|
|
package/src/services/global.ts
CHANGED
@@ -2,7 +2,7 @@ import { DeepPartial } from 'utility-types';
|
|
2
2
|
|
3
3
|
import { edgeClient } from '@/libs/trpc/client';
|
4
4
|
import { LobeAgentConfig } from '@/types/agent';
|
5
|
-
import {
|
5
|
+
import { GlobalRuntimeConfig } from '@/types/serverConfig';
|
6
6
|
|
7
7
|
const VERSION_URL = 'https://registry.npmmirror.com/@lobehub/chat/latest';
|
8
8
|
|
@@ -17,7 +17,7 @@ class GlobalService {
|
|
17
17
|
return data['version'];
|
18
18
|
};
|
19
19
|
|
20
|
-
getGlobalConfig = async (): Promise<
|
20
|
+
getGlobalConfig = async (): Promise<GlobalRuntimeConfig> => {
|
21
21
|
return edgeClient.config.getGlobalConfig.query();
|
22
22
|
};
|
23
23
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { SWRResponse } from 'swr';
|
2
|
+
import { StateCreator } from 'zustand/vanilla';
|
3
|
+
|
4
|
+
import { useOnlyFetchOnceSWR } from '@/libs/swr';
|
5
|
+
import { globalService } from '@/services/global';
|
6
|
+
import { GlobalRuntimeConfig } from '@/types/serverConfig';
|
7
|
+
|
8
|
+
import type { ServerConfigStore } from './store';
|
9
|
+
|
10
|
+
const FETCH_SERVER_CONFIG_KEY = 'FETCH_SERVER_CONFIG';
|
11
|
+
export interface ServerConfigAction {
|
12
|
+
useInitServerConfig: () => SWRResponse<GlobalRuntimeConfig>;
|
13
|
+
}
|
14
|
+
|
15
|
+
export const createServerConfigSlice: StateCreator<
|
16
|
+
ServerConfigStore,
|
17
|
+
[['zustand/devtools', never]],
|
18
|
+
[],
|
19
|
+
ServerConfigAction
|
20
|
+
> = (set) => ({
|
21
|
+
useInitServerConfig: () => {
|
22
|
+
return useOnlyFetchOnceSWR<GlobalRuntimeConfig>(
|
23
|
+
FETCH_SERVER_CONFIG_KEY,
|
24
|
+
() => globalService.getGlobalConfig(),
|
25
|
+
{
|
26
|
+
onSuccess: (data) => {
|
27
|
+
set(
|
28
|
+
{ featureFlags: data.serverFeatureFlags, serverConfig: data.serverConfig },
|
29
|
+
false,
|
30
|
+
'initServerConfig',
|
31
|
+
);
|
32
|
+
},
|
33
|
+
},
|
34
|
+
);
|
35
|
+
},
|
36
|
+
});
|
@@ -21,7 +21,7 @@ describe('createServerConfigStore', () => {
|
|
21
21
|
it('should initialize store with default state', () => {
|
22
22
|
const store = createServerConfigStore();
|
23
23
|
|
24
|
-
expect(store.getState()).
|
24
|
+
expect(store.getState()).toMatchObject({
|
25
25
|
featureFlags: DEFAULT_FEATURE_FLAGS,
|
26
26
|
serverConfig: { telemetry: {}, aiProvider: {} },
|
27
27
|
});
|
@@ -10,26 +10,33 @@ import { GlobalServerConfig } from '@/types/serverConfig';
|
|
10
10
|
import { merge } from '@/utils/merge';
|
11
11
|
import { StoreApiWithSelector } from '@/utils/zustand';
|
12
12
|
|
13
|
-
|
13
|
+
import { ServerConfigAction, createServerConfigSlice } from './action';
|
14
|
+
|
15
|
+
interface ServerConfigState {
|
16
|
+
featureFlags: IFeatureFlags;
|
17
|
+
isMobile?: boolean;
|
18
|
+
serverConfig: GlobalServerConfig;
|
19
|
+
}
|
20
|
+
|
21
|
+
const initialState: ServerConfigState = {
|
14
22
|
featureFlags: DEFAULT_FEATURE_FLAGS,
|
15
23
|
serverConfig: { aiProvider: {}, telemetry: {} },
|
16
24
|
};
|
17
25
|
|
18
26
|
// =============== 聚合 createStoreFn ============ //
|
19
27
|
|
20
|
-
export interface ServerConfigStore {
|
21
|
-
featureFlags: IFeatureFlags;
|
22
|
-
isMobile?: boolean;
|
23
|
-
serverConfig: GlobalServerConfig;
|
24
|
-
}
|
28
|
+
export interface ServerConfigStore extends ServerConfigState, ServerConfigAction {}
|
25
29
|
|
26
30
|
type CreateStore = (
|
27
31
|
initState: Partial<ServerConfigStore>,
|
28
32
|
) => StateCreator<ServerConfigStore, [['zustand/devtools', never]]>;
|
29
33
|
|
30
|
-
const createStore: CreateStore =
|
31
|
-
|
32
|
-
|
34
|
+
const createStore: CreateStore =
|
35
|
+
(runtimeState) =>
|
36
|
+
(...params) => ({
|
37
|
+
...merge(initialState, runtimeState),
|
38
|
+
...createServerConfigSlice(...params),
|
39
|
+
});
|
33
40
|
|
34
41
|
// =============== 实装 useStore ============ //
|
35
42
|
|
@@ -89,7 +89,7 @@ describe('createAuthSlice', () => {
|
|
89
89
|
});
|
90
90
|
|
91
91
|
it('should call next-auth signOut when NextAuth is enabled', async () => {
|
92
|
-
|
92
|
+
enableNextAuth = true;
|
93
93
|
|
94
94
|
const { result } = renderHook(() => useUserStore());
|
95
95
|
|
@@ -100,6 +100,7 @@ describe('createAuthSlice', () => {
|
|
100
100
|
const { signOut } = await import('next-auth/react');
|
101
101
|
|
102
102
|
expect(signOut).toHaveBeenCalled();
|
103
|
+
enableNextAuth = false;
|
103
104
|
});
|
104
105
|
|
105
106
|
it('should not call next-auth signOut when NextAuth is disabled', async () => {
|
@@ -143,7 +144,7 @@ describe('createAuthSlice', () => {
|
|
143
144
|
});
|
144
145
|
|
145
146
|
it('should call next-auth signIn when NextAuth is enabled', async () => {
|
146
|
-
|
147
|
+
enableNextAuth = true;
|
147
148
|
|
148
149
|
const { result } = renderHook(() => useUserStore());
|
149
150
|
|
@@ -154,6 +155,7 @@ describe('createAuthSlice', () => {
|
|
154
155
|
const { signIn } = await import('next-auth/react');
|
155
156
|
|
156
157
|
expect(signIn).toHaveBeenCalled();
|
158
|
+
enableNextAuth = false;
|
157
159
|
});
|
158
160
|
it('should not call next-auth signIn when NextAuth is disabled', async () => {
|
159
161
|
const { result } = renderHook(() => useUserStore());
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
2
2
|
|
3
|
-
import { enableClerk } from '@/const/auth';
|
3
|
+
import { enableAuth, enableClerk, enableNextAuth } from '@/const/auth';
|
4
4
|
|
5
5
|
import { UserStore } from '../../store';
|
6
6
|
|
@@ -23,7 +23,7 @@ export const createAuthSlice: StateCreator<
|
|
23
23
|
UserAuthAction
|
24
24
|
> = (set, get) => ({
|
25
25
|
enableAuth: () => {
|
26
|
-
return
|
26
|
+
return enableAuth;
|
27
27
|
},
|
28
28
|
logout: async () => {
|
29
29
|
if (enableClerk) {
|
@@ -32,7 +32,6 @@ export const createAuthSlice: StateCreator<
|
|
32
32
|
return;
|
33
33
|
}
|
34
34
|
|
35
|
-
const enableNextAuth = get().enabledNextAuth;
|
36
35
|
if (enableNextAuth) {
|
37
36
|
const { signOut } = await import('next-auth/react');
|
38
37
|
signOut();
|
@@ -50,7 +49,6 @@ export const createAuthSlice: StateCreator<
|
|
50
49
|
return;
|
51
50
|
}
|
52
51
|
|
53
|
-
const enableNextAuth = get().enabledNextAuth;
|
54
52
|
if (enableNextAuth) {
|
55
53
|
const { signIn } = await import('next-auth/react');
|
56
54
|
// Check if only one provider is available
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { t } from 'i18next';
|
2
2
|
|
3
|
-
import { enableClerk } from '@/const/auth';
|
3
|
+
import { enableAuth, enableClerk, enableNextAuth } from '@/const/auth';
|
4
4
|
import { BRANDING_NAME } from '@/const/branding';
|
5
5
|
import { UserStore } from '@/store/user';
|
6
6
|
import { LobeUser } from '@/types/user';
|
@@ -8,7 +8,7 @@ import { LobeUser } from '@/types/user';
|
|
8
8
|
const DEFAULT_USERNAME = BRANDING_NAME;
|
9
9
|
|
10
10
|
const nickName = (s: UserStore) => {
|
11
|
-
if (!
|
11
|
+
if (!enableAuth) return t('userPanel.defaultNickname', { ns: 'common' });
|
12
12
|
|
13
13
|
if (s.isSignedIn) return s.user?.fullName || s.user?.username;
|
14
14
|
|
@@ -16,7 +16,7 @@ const nickName = (s: UserStore) => {
|
|
16
16
|
};
|
17
17
|
|
18
18
|
const username = (s: UserStore) => {
|
19
|
-
if (!
|
19
|
+
if (!enableAuth) return DEFAULT_USERNAME;
|
20
20
|
|
21
21
|
if (s.isSignedIn) return s.user?.username;
|
22
22
|
|
@@ -36,17 +36,15 @@ export const userProfileSelectors = {
|
|
36
36
|
*/
|
37
37
|
const isLogin = (s: UserStore) => {
|
38
38
|
// 如果没有开启鉴权,说明不需要登录,默认是登录态
|
39
|
-
if (!
|
39
|
+
if (!enableAuth) return true;
|
40
40
|
|
41
41
|
return s.isSignedIn;
|
42
42
|
};
|
43
43
|
|
44
44
|
export const authSelectors = {
|
45
|
-
enabledAuth: (s: UserStore): boolean => s.enableAuth(),
|
46
|
-
enabledNextAuth: (s: UserStore): boolean => !!s.enabledNextAuth,
|
47
45
|
isLoaded: (s: UserStore) => s.isLoaded,
|
48
46
|
isLogin,
|
49
47
|
isLoginWithAuth: (s: UserStore) => s.isSignedIn,
|
50
48
|
isLoginWithClerk: (s: UserStore): boolean => (s.isSignedIn && enableClerk) || false,
|
51
|
-
isLoginWithNextAuth: (s: UserStore): boolean => (s.isSignedIn && !!
|
49
|
+
isLoginWithNextAuth: (s: UserStore): boolean => (s.isSignedIn && !!enableNextAuth) || false,
|
52
50
|
};
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { DeepPartial } from 'utility-types';
|
2
2
|
|
3
|
+
import { IFeatureFlags } from '@/config/featureFlags';
|
3
4
|
import { ChatModelCard } from '@/types/llm';
|
4
5
|
import {
|
5
6
|
GlobalLLMProviderKey,
|
@@ -38,3 +39,8 @@ export interface GlobalServerConfig {
|
|
38
39
|
langfuse?: boolean;
|
39
40
|
};
|
40
41
|
}
|
42
|
+
|
43
|
+
export interface GlobalRuntimeConfig {
|
44
|
+
serverConfig: GlobalServerConfig;
|
45
|
+
serverFeatureFlags: IFeatureFlags;
|
46
|
+
}
|