@lobehub/chat 0.158.2 → 0.159.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 (91) hide show
  1. package/.env.example +4 -0
  2. package/CHANGELOG.md +58 -0
  3. package/Dockerfile +3 -0
  4. package/README.md +1 -0
  5. package/README.zh-CN.md +1 -0
  6. package/docs/self-hosting/advanced/authentication.mdx +9 -0
  7. package/docs/self-hosting/advanced/authentication.zh-CN.mdx +9 -0
  8. package/docs/self-hosting/environment-variables/model-provider.mdx +16 -7
  9. package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +16 -7
  10. package/docs/usage/features/multi-ai-providers.mdx +1 -0
  11. package/docs/usage/features/multi-ai-providers.zh-CN.mdx +1 -0
  12. package/locales/ar/error.json +2 -0
  13. package/locales/ar/modelProvider.json +12 -0
  14. package/locales/bg-BG/error.json +2 -0
  15. package/locales/bg-BG/modelProvider.json +12 -0
  16. package/locales/de-DE/error.json +2 -0
  17. package/locales/de-DE/modelProvider.json +12 -0
  18. package/locales/en-US/error.json +2 -0
  19. package/locales/en-US/modelProvider.json +12 -0
  20. package/locales/es-ES/error.json +2 -0
  21. package/locales/es-ES/modelProvider.json +12 -0
  22. package/locales/fr-FR/error.json +2 -0
  23. package/locales/fr-FR/modelProvider.json +12 -0
  24. package/locales/it-IT/error.json +2 -0
  25. package/locales/it-IT/modelProvider.json +12 -0
  26. package/locales/ja-JP/error.json +2 -0
  27. package/locales/ja-JP/modelProvider.json +12 -0
  28. package/locales/ko-KR/error.json +2 -0
  29. package/locales/ko-KR/modelProvider.json +12 -0
  30. package/locales/nl-NL/error.json +2 -0
  31. package/locales/nl-NL/modelProvider.json +12 -0
  32. package/locales/pl-PL/error.json +2 -0
  33. package/locales/pl-PL/modelProvider.json +12 -0
  34. package/locales/pt-BR/error.json +2 -0
  35. package/locales/pt-BR/modelProvider.json +12 -0
  36. package/locales/ru-RU/error.json +2 -0
  37. package/locales/ru-RU/modelProvider.json +12 -0
  38. package/locales/tr-TR/error.json +2 -0
  39. package/locales/tr-TR/modelProvider.json +12 -0
  40. package/locales/vi-VN/error.json +2 -0
  41. package/locales/vi-VN/modelProvider.json +12 -0
  42. package/locales/zh-CN/error.json +2 -0
  43. package/locales/zh-CN/modelProvider.json +12 -0
  44. package/locales/zh-TW/error.json +2 -0
  45. package/locales/zh-TW/modelProvider.json +12 -0
  46. package/package.json +2 -2
  47. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Main.tsx +13 -15
  48. package/src/app/(main)/settings/common/features/Common.tsx +11 -8
  49. package/src/app/(main)/settings/common/index.tsx +1 -9
  50. package/src/app/(main)/settings/llm/DeepSeek/index.tsx +21 -0
  51. package/src/app/(main)/settings/llm/index.tsx +2 -0
  52. package/src/app/api/chat/agentRuntime.test.ts +17 -0
  53. package/src/app/api/chat/agentRuntime.ts +5 -0
  54. package/src/app/api/errorResponse.test.ts +6 -0
  55. package/src/app/api/errorResponse.ts +3 -0
  56. package/src/components/ModelIcon/index.tsx +2 -0
  57. package/src/components/ModelProviderIcon/index.tsx +5 -0
  58. package/src/components/ModelTag/ModelIcon.tsx +2 -0
  59. package/src/config/modelProviders/deepseek.ts +23 -0
  60. package/src/config/modelProviders/index.ts +4 -0
  61. package/src/config/server/provider.ts +10 -0
  62. package/src/const/settings/index.ts +6 -0
  63. package/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx +5 -0
  64. package/src/features/Conversation/Error/APIKeyForm/index.tsx +4 -0
  65. package/src/features/Conversation/Error/OAuthForm.tsx +6 -4
  66. package/src/features/Conversation/Error/index.tsx +1 -0
  67. package/src/features/User/__tests__/UserAvatar.test.tsx +8 -3
  68. package/src/features/User/__tests__/useMenu.test.tsx +3 -3
  69. package/src/libs/agent-runtime/AgentRuntime.ts +7 -0
  70. package/src/libs/agent-runtime/deepseek/index.test.ts +254 -0
  71. package/src/libs/agent-runtime/deepseek/index.ts +15 -0
  72. package/src/libs/agent-runtime/error.ts +3 -0
  73. package/src/libs/agent-runtime/index.ts +1 -0
  74. package/src/libs/agent-runtime/types/type.ts +1 -0
  75. package/src/libs/next-auth/index.ts +0 -7
  76. package/src/locales/default/error.ts +3 -0
  77. package/src/locales/default/modelProvider.ts +12 -0
  78. package/src/migrations/FromV3ToV4/types/v3.ts +0 -8
  79. package/src/server/globalConfig/index.ts +4 -0
  80. package/src/services/__tests__/chat.test.ts +16 -0
  81. package/src/services/chat.ts +3 -0
  82. package/src/store/serverConfig/selectors.ts +1 -0
  83. package/src/store/user/slices/auth/action.test.ts +61 -0
  84. package/src/store/user/slices/auth/action.ts +17 -15
  85. package/src/store/user/slices/auth/selectors.test.ts +18 -2
  86. package/src/store/user/slices/auth/selectors.ts +4 -4
  87. package/src/store/user/slices/settings/actions/llm.ts +2 -0
  88. package/src/types/next-auth.d.ts +23 -0
  89. package/src/types/serverConfig.ts +1 -0
  90. package/src/types/settings/modelProvider.ts +1 -0
  91. package/src/hooks/useOAuthSession.ts +0 -24
@@ -13,6 +13,7 @@ import { parseAgentConfig } from './parseDefaultAgent';
13
13
 
14
14
  export const getServerGlobalConfig = () => {
15
15
  const {
16
+ ACCESS_CODES,
16
17
  ENABLE_LANGFUSE,
17
18
 
18
19
  DEFAULT_AGENT_CONFIG,
@@ -23,6 +24,7 @@ export const getServerGlobalConfig = () => {
23
24
  ENABLED_AWS_BEDROCK,
24
25
  ENABLED_GOOGLE,
25
26
  ENABLED_GROQ,
27
+ ENABLED_DEEPSEEK,
26
28
  ENABLED_PERPLEXITY,
27
29
  ENABLED_ANTHROPIC,
28
30
  ENABLED_MINIMAX,
@@ -48,6 +50,7 @@ export const getServerGlobalConfig = () => {
48
50
  config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
49
51
  },
50
52
 
53
+ enabledAccessCode: ACCESS_CODES?.length > 0,
51
54
  enabledOAuthSSO: enableNextAuth,
52
55
  languageModel: {
53
56
  anthropic: {
@@ -63,6 +66,7 @@ export const getServerGlobalConfig = () => {
63
66
  }),
64
67
  },
65
68
  bedrock: { enabled: ENABLED_AWS_BEDROCK },
69
+ deepseek: { enabled: ENABLED_DEEPSEEK },
66
70
  google: { enabled: ENABLED_GOOGLE },
67
71
  groq: { enabled: ENABLED_GROQ },
68
72
  minimax: { enabled: ENABLED_MINIMAX },
@@ -10,6 +10,7 @@ import {
10
10
  LobeBedrockAI,
11
11
  LobeGoogleAI,
12
12
  LobeGroq,
13
+ LobeDeepSeekAI,
13
14
  LobeMistralAI,
14
15
  LobeMoonshotAI,
15
16
  LobeOllamaAI,
@@ -873,6 +874,21 @@ describe('AgentRuntimeOnClient', () => {
873
874
  expect(runtime['_runtime']).toBeInstanceOf(LobeGroq);
874
875
  });
875
876
 
877
+ it('DeepSeek provider: with apiKey', async () => {
878
+ merge(initialSettingsState, {
879
+ settings: {
880
+ languageModel: {
881
+ deepseek: {
882
+ apiKey: 'user-deepseek-key',
883
+ },
884
+ },
885
+ },
886
+ } as UserSettingsState) as unknown as UserStore;
887
+ const runtime = await initializeWithClientStore(ModelProvider.DeepSeek, {});
888
+ expect(runtime).toBeInstanceOf(AgentRuntime);
889
+ expect(runtime['_runtime']).toBeInstanceOf(LobeDeepSeekAI);
890
+ });
891
+
876
892
  /**
877
893
  * Should not have a unknown provider in client, but has
878
894
  * similar cases in server side
@@ -139,6 +139,9 @@ export function initializeWithClientStore(provider: string, payload: any) {
139
139
  case ModelProvider.Groq: {
140
140
  break;
141
141
  }
142
+ case ModelProvider.DeepSeek: {
143
+ break;
144
+ }
142
145
  case ModelProvider.OpenRouter: {
143
146
  break;
144
147
  }
@@ -6,6 +6,7 @@ export const featureFlagsSelectors = (s: ServerConfigStore) =>
6
6
  mapFeatureFlagsEnvToState(s.featureFlags);
7
7
 
8
8
  export const serverConfigSelectors = {
9
+ enabledAccessCode: (s: ServerConfigStore) => !!s.serverConfig?.enabledAccessCode,
9
10
  enabledOAuthSSO: (s: ServerConfigStore) => s.serverConfig.enabledOAuthSSO,
10
11
  enabledTelemetryChat: (s: ServerConfigStore) => s.serverConfig.telemetry.langfuse || false,
11
12
  isMobile: (s: ServerConfigStore) => s.isMobile || false,
@@ -43,6 +43,16 @@ afterEach(() => {
43
43
  enableClerk = false;
44
44
  });
45
45
 
46
+ /**
47
+ * Mock nextauth 库相关方法
48
+ */
49
+ vi.mock('next-auth/react', async () => {
50
+ return {
51
+ signIn: vi.fn(),
52
+ signOut: vi.fn(),
53
+ };
54
+ });
55
+
46
56
  describe('createAuthSlice', () => {
47
57
  describe('refreshUserConfig', () => {
48
58
  it('should refresh user config', async () => {
@@ -162,6 +172,32 @@ describe('createAuthSlice', () => {
162
172
 
163
173
  expect(clerkSignOutMock).not.toHaveBeenCalled();
164
174
  });
175
+
176
+ it('should call next-auth signOut when NextAuth is enabled', async () => {
177
+ useUserStore.setState({ enabledNextAuth: () => true });
178
+
179
+ const { result } = renderHook(() => useUserStore());
180
+
181
+ await act(async () => {
182
+ await result.current.logout();
183
+ });
184
+
185
+ const { signOut } = await import('next-auth/react');
186
+
187
+ expect(signOut).toHaveBeenCalled();
188
+ });
189
+
190
+ it('should not call next-auth signOut when NextAuth is disabled', async () => {
191
+ const { result } = renderHook(() => useUserStore());
192
+
193
+ await act(async () => {
194
+ await result.current.logout();
195
+ });
196
+
197
+ const { signOut } = await import('next-auth/react');
198
+
199
+ expect(signOut).not.toHaveBeenCalled();
200
+ });
165
201
  });
166
202
 
167
203
  describe('openLogin', () => {
@@ -190,6 +226,31 @@ describe('createAuthSlice', () => {
190
226
 
191
227
  expect(clerkSignInMock).not.toHaveBeenCalled();
192
228
  });
229
+
230
+ it('should call next-auth signIn when NextAuth is enabled', async () => {
231
+ useUserStore.setState({ enabledNextAuth: () => true });
232
+
233
+ const { result } = renderHook(() => useUserStore());
234
+
235
+ await act(async () => {
236
+ await result.current.openLogin();
237
+ });
238
+
239
+ const { signIn } = await import('next-auth/react');
240
+
241
+ expect(signIn).toHaveBeenCalled();
242
+ });
243
+ it('should not call next-auth signIn when NextAuth is disabled', async () => {
244
+ const { result } = renderHook(() => useUserStore());
245
+
246
+ await act(async () => {
247
+ await result.current.openLogin();
248
+ });
249
+
250
+ const { signIn } = await import('next-auth/react');
251
+
252
+ expect(signIn).not.toHaveBeenCalled();
253
+ });
193
254
  });
194
255
 
195
256
  describe('openUserProfile', () => {
@@ -1,7 +1,7 @@
1
1
  import useSWR, { SWRResponse, mutate } from 'swr';
2
2
  import { StateCreator } from 'zustand/vanilla';
3
3
 
4
- import { enableClerk, enableNextAuth } from '@/const/auth';
4
+ import { enableClerk } from '@/const/auth';
5
5
  import { UserConfig, userService } from '@/services/user';
6
6
  import { switchLang } from '@/utils/client/switchLang';
7
7
  import { setNamespace } from '@/utils/storeDebug';
@@ -13,8 +13,9 @@ const n = setNamespace('auth');
13
13
  const USER_CONFIG_FETCH_KEY = 'fetchUserConfig';
14
14
 
15
15
  export interface UserAuthAction {
16
+ enableAuth: () => boolean;
17
+ enabledNextAuth: () => boolean;
16
18
  getUserConfig: () => void;
17
- login: () => Promise<void>;
18
19
  /**
19
20
  * universal logout method
20
21
  */
@@ -24,8 +25,8 @@ export interface UserAuthAction {
24
25
  */
25
26
  openLogin: () => Promise<void>;
26
27
  openUserProfile: () => Promise<void>;
27
- refreshUserConfig: () => Promise<void>;
28
28
 
29
+ refreshUserConfig: () => Promise<void>;
29
30
  useFetchUserConfig: (initServer: boolean) => SWRResponse<UserConfig | undefined>;
30
31
  }
31
32
 
@@ -35,13 +36,15 @@ export const createAuthSlice: StateCreator<
35
36
  [],
36
37
  UserAuthAction
37
38
  > = (set, get) => ({
39
+ enableAuth: () => {
40
+ return enableClerk || get()?.enabledNextAuth();
41
+ },
42
+ enabledNextAuth: () => {
43
+ return !!get()?.serverConfig.enabledOAuthSSO;
44
+ },
38
45
  getUserConfig: () => {
39
46
  console.log(n('userconfig'));
40
47
  },
41
- login: async () => {
42
- // TODO: 针对开启 next-auth 的场景,需要在这里调用登录方法
43
- console.log(n('login'));
44
- },
45
48
  logout: async () => {
46
49
  if (enableClerk) {
47
50
  get().clerkSignOut?.({ redirectUrl: location.toString() });
@@ -49,9 +52,10 @@ export const createAuthSlice: StateCreator<
49
52
  return;
50
53
  }
51
54
 
55
+ const enableNextAuth = get().enabledNextAuth();
52
56
  if (enableNextAuth) {
53
- // TODO: 针对开启 next-auth 的场景,需要在这里调用登录方法
54
- console.log(n('logout'));
57
+ const { signOut } = await import('next-auth/react');
58
+ signOut();
55
59
  }
56
60
  },
57
61
  openLogin: async () => {
@@ -63,20 +67,19 @@ export const createAuthSlice: StateCreator<
63
67
  return;
64
68
  }
65
69
 
70
+ const enableNextAuth = get().enabledNextAuth();
66
71
  if (enableNextAuth) {
67
- // TODO: 针对开启 next-auth 的场景,需要在这里调用登录方法
72
+ const { signIn } = await import('next-auth/react');
73
+ signIn();
68
74
  }
69
75
  },
76
+
70
77
  openUserProfile: async () => {
71
78
  if (enableClerk) {
72
79
  get().clerkOpenUserProfile?.();
73
80
 
74
81
  return;
75
82
  }
76
-
77
- if (enableNextAuth) {
78
- // TODO: 针对开启 next-auth 的场景,需要在这里调用打开 profile 页
79
- }
80
83
  },
81
84
  refreshUserConfig: async () => {
82
85
  await mutate([USER_CONFIG_FETCH_KEY, true]);
@@ -84,7 +87,6 @@ export const createAuthSlice: StateCreator<
84
87
  // when get the user config ,refresh the model provider list to the latest
85
88
  get().refreshModelProviderList();
86
89
  },
87
-
88
90
  useFetchUserConfig: (initServer) =>
89
91
  useSWR<UserConfig | undefined>(
90
92
  [USER_CONFIG_FETCH_KEY, initServer],
@@ -31,6 +31,7 @@ describe('userProfileSelectors', () => {
31
31
  const store: UserStore = {
32
32
  isSignedIn: false,
33
33
  user: null,
34
+ enableAuth: () => false,
34
35
  } as unknown as UserStore;
35
36
 
36
37
  expect(userProfileSelectors.nickName(store)).toBe('userPanel.defaultNickname');
@@ -43,6 +44,7 @@ describe('userProfileSelectors', () => {
43
44
  const store: UserStore = {
44
45
  isSignedIn: true,
45
46
  user: { fullName: 'John Doe' },
47
+ enableAuth: () => true,
46
48
  } as UserStore;
47
49
 
48
50
  expect(userProfileSelectors.nickName(store)).toBe('John Doe');
@@ -52,6 +54,7 @@ describe('userProfileSelectors', () => {
52
54
  const store: UserStore = {
53
55
  isSignedIn: true,
54
56
  user: { username: 'johndoe' },
57
+ enableAuth: () => true,
55
58
  } as UserStore;
56
59
 
57
60
  expect(userProfileSelectors.nickName(store)).toBe('johndoe');
@@ -60,7 +63,11 @@ describe('userProfileSelectors', () => {
60
63
  it('should return anonymous nickname when not signed in', () => {
61
64
  enableAuth = true;
62
65
 
63
- const store: UserStore = { isSignedIn: false, user: null } as unknown as UserStore;
66
+ const store: UserStore = {
67
+ enableAuth: () => true,
68
+ isSignedIn: false,
69
+ user: null,
70
+ } as unknown as UserStore;
64
71
 
65
72
  expect(userProfileSelectors.nickName(store)).toBe('userPanel.anonymousNickName');
66
73
  expect(t).toHaveBeenCalledWith('userPanel.anonymousNickName', { ns: 'common' });
@@ -74,6 +81,7 @@ describe('userProfileSelectors', () => {
74
81
  const store: UserStore = {
75
82
  isSignedIn: false,
76
83
  user: null,
84
+ enableAuth: () => false,
77
85
  } as unknown as UserStore;
78
86
 
79
87
  expect(userProfileSelectors.username(store)).toBe('LobeChat');
@@ -83,13 +91,18 @@ describe('userProfileSelectors', () => {
83
91
  const store: UserStore = {
84
92
  isSignedIn: true,
85
93
  user: { username: 'johndoe' },
94
+ enableAuth: () => true,
86
95
  } as UserStore;
87
96
 
88
97
  expect(userProfileSelectors.username(store)).toBe('johndoe');
89
98
  });
90
99
 
91
100
  it('should return "anonymous" when not signed in', () => {
92
- const store: UserStore = { isSignedIn: false, user: null } as unknown as UserStore;
101
+ const store: UserStore = {
102
+ enableAuth: () => true,
103
+ isSignedIn: false,
104
+ user: null,
105
+ } as unknown as UserStore;
93
106
 
94
107
  expect(userProfileSelectors.username(store)).toBe('anonymous');
95
108
  });
@@ -103,6 +116,7 @@ describe('authSelectors', () => {
103
116
 
104
117
  const store: UserStore = {
105
118
  isSignedIn: false,
119
+ enableAuth: () => false,
106
120
  } as UserStore;
107
121
 
108
122
  expect(authSelectors.isLogin(store)).toBe(true);
@@ -111,6 +125,7 @@ describe('authSelectors', () => {
111
125
  it('should return true when signed in', () => {
112
126
  const store: UserStore = {
113
127
  isSignedIn: true,
128
+ enableAuth: () => true,
114
129
  } as UserStore;
115
130
 
116
131
  expect(authSelectors.isLogin(store)).toBe(true);
@@ -119,6 +134,7 @@ describe('authSelectors', () => {
119
134
  it('should return false when not signed in and auth is enabled', () => {
120
135
  const store: UserStore = {
121
136
  isSignedIn: false,
137
+ enableAuth: () => true,
122
138
  } as UserStore;
123
139
 
124
140
  expect(authSelectors.isLogin(store)).toBe(false);
@@ -1,13 +1,13 @@
1
1
  import { t } from 'i18next';
2
2
 
3
- import { enableAuth, enableClerk } from '@/const/auth';
3
+ import { enableClerk } from '@/const/auth';
4
4
  import { UserStore } from '@/store/user';
5
5
  import { LobeUser } from '@/types/user';
6
6
 
7
7
  const DEFAULT_USERNAME = 'LobeChat';
8
8
 
9
9
  const nickName = (s: UserStore) => {
10
- if (!enableAuth) return t('userPanel.defaultNickname', { ns: 'common' });
10
+ if (!s.enableAuth()) return t('userPanel.defaultNickname', { ns: 'common' });
11
11
 
12
12
  if (s.isSignedIn) return s.user?.fullName || s.user?.username;
13
13
 
@@ -15,7 +15,7 @@ const nickName = (s: UserStore) => {
15
15
  };
16
16
 
17
17
  const username = (s: UserStore) => {
18
- if (!enableAuth) return DEFAULT_USERNAME;
18
+ if (!s.enableAuth()) return DEFAULT_USERNAME;
19
19
 
20
20
  if (s.isSignedIn) return s.user?.username;
21
21
 
@@ -35,7 +35,7 @@ export const userProfileSelectors = {
35
35
  */
36
36
  const isLogin = (s: UserStore) => {
37
37
  // 如果没有开启鉴权,说明不需要登录,默认是登录态
38
- if (!enableAuth) return true;
38
+ if (!s.enableAuth()) return true;
39
39
 
40
40
  return s.isSignedIn;
41
41
  };
@@ -5,6 +5,7 @@ import {
5
5
  AnthropicProviderCard,
6
6
  AzureProviderCard,
7
7
  BedrockProviderCard,
8
+ DeepSeekProviderCard,
8
9
  GoogleProviderCard,
9
10
  GroqProviderCard,
10
11
  MinimaxProviderCard,
@@ -109,6 +110,7 @@ export const llmSettingsSlice: StateCreator<
109
110
  chatModels: mergeModels('togetherai', TogetherAIProviderCard.chatModels),
110
111
  },
111
112
  BedrockProviderCard,
113
+ DeepSeekProviderCard,
112
114
  PerplexityProviderCard,
113
115
  MinimaxProviderCard,
114
116
  MistralProviderCard,
@@ -0,0 +1,23 @@
1
+ import { type DefaultSession } from 'next-auth';
2
+
3
+ declare module 'next-auth' {
4
+ /**
5
+ * Returned by `useSession`, `auth`, contains information about the active session.
6
+ */
7
+ interface Session {
8
+ user: {
9
+ firstName?: string;
10
+ } & DefaultSession['user'];
11
+ }
12
+ /**
13
+ * More types can be extends here
14
+ * ref: https://authjs.dev/getting-started/typescript
15
+ */
16
+ }
17
+
18
+ declare module '@auth/core/jwt' {
19
+ /** Returned by the `jwt` callback and `auth`, when using JWT sessions */
20
+ interface JWT {
21
+ userId: string;
22
+ }
23
+ }
@@ -15,6 +15,7 @@ export interface ServerModelProviderConfig {
15
15
 
16
16
  export interface GlobalServerConfig {
17
17
  defaultAgent?: DeepPartial<GlobalDefaultAgent>;
18
+ enabledAccessCode?: boolean;
18
19
  enabledOAuthSSO?: boolean;
19
20
  languageModel?: Partial<Record<GlobalLLMProviderKey, ServerModelProviderConfig>>;
20
21
  telemetry: {
@@ -44,6 +44,7 @@ export interface GlobalLLMConfig {
44
44
  anthropic: GeneralModelProviderConfig;
45
45
  azure: AzureOpenAIConfig;
46
46
  bedrock: AWSBedrockConfig;
47
+ deepseek: GeneralModelProviderConfig;
47
48
  google: GeneralModelProviderConfig;
48
49
  groq: GeneralModelProviderConfig;
49
50
  minimax: GeneralModelProviderConfig;
@@ -1,24 +0,0 @@
1
- import { User } from '@auth/core/types';
2
- import { SessionContextValue, useSession } from 'next-auth/react';
3
- import { useMemo } from 'react';
4
-
5
- interface OAuthSession {
6
- isOAuthLoggedIn: boolean;
7
- user?: User | null;
8
- }
9
-
10
- export const useOAuthSession = () => {
11
- let authSession: SessionContextValue | null;
12
- try {
13
- // refs: https://github.com/lobehub/lobe-chat/pull/1286
14
- // eslint-disable-next-line react-hooks/rules-of-hooks
15
- authSession = useSession();
16
- } catch {
17
- authSession = null;
18
- }
19
-
20
- const { data: session, status } = authSession || {};
21
- const isOAuthLoggedIn = (status === 'authenticated' && session && !!session.user) || false;
22
-
23
- return useMemo<OAuthSession>(() => ({ isOAuthLoggedIn, user: session?.user }), [session, status]);
24
- };