@lobehub/chat 0.161.11 → 0.161.12
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/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/src/app/(loading)/Redirect.tsx +29 -17
- package/src/layout/AuthProvider/NoAuth/index.tsx +16 -0
- package/src/layout/AuthProvider/index.tsx +2 -1
- package/src/middleware.ts +1 -10
- package/src/services/user/client.test.ts +2 -0
- package/src/services/user/client.ts +4 -0
- package/src/services/user/type.ts +0 -1
- package/src/store/user/slices/auth/selectors.ts +1 -0
- package/src/store/user/slices/common/action.test.ts +2 -1
- package/src/store/user/slices/common/action.ts +8 -1
- package/src/store/user/slices/common/initialState.ts +6 -0
- package/src/types/user/index.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.161.12](https://github.com/lobehub/lobe-chat/compare/v0.161.11...v0.161.12)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-05-23**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Refactor the home redirect implement.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Refactor the home redirect implement, closes [#2626](https://github.com/lobehub/lobe-chat/issues/2626) ([ab4216e](https://github.com/lobehub/lobe-chat/commit/ab4216e))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
### [Version 0.161.11](https://github.com/lobehub/lobe-chat/compare/v0.161.10...v0.161.11)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2024-05-23**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.161.
|
|
3
|
+
"version": "0.161.12",
|
|
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",
|
|
@@ -3,35 +3,47 @@
|
|
|
3
3
|
import { useRouter } from 'next/navigation';
|
|
4
4
|
import { memo, useEffect } from 'react';
|
|
5
5
|
|
|
6
|
-
import { messageService } from '@/services/message';
|
|
7
|
-
import { sessionService } from '@/services/session';
|
|
8
6
|
import { useUserStore } from '@/store/user';
|
|
9
7
|
import { authSelectors } from '@/store/user/selectors';
|
|
10
8
|
|
|
11
|
-
const checkHasConversation = async () => {
|
|
12
|
-
const hasMessages = await messageService.hasMessages();
|
|
13
|
-
const hasAgents = await sessionService.hasSessions();
|
|
14
|
-
return hasMessages || hasAgents;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
9
|
const Redirect = memo(() => {
|
|
18
10
|
const router = useRouter();
|
|
19
|
-
const isLogin = useUserStore(
|
|
11
|
+
const [isLogin, isLoaded, isUserStateInit, isUserHasConversation, isOnboard] = useUserStore(
|
|
12
|
+
(s) => [
|
|
13
|
+
authSelectors.isLogin(s),
|
|
14
|
+
authSelectors.isLoaded(s),
|
|
15
|
+
s.isUserStateInit,
|
|
16
|
+
s.isUserHasConversation,
|
|
17
|
+
s.isOnboard,
|
|
18
|
+
],
|
|
19
|
+
);
|
|
20
20
|
|
|
21
21
|
useEffect(() => {
|
|
22
|
+
// if user auth state is not ready, wait for loading
|
|
23
|
+
if (!isLoaded) return;
|
|
24
|
+
|
|
25
|
+
// this mean user is definitely not login
|
|
22
26
|
if (!isLogin) {
|
|
23
27
|
router.replace('/welcome');
|
|
24
28
|
return;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
// if user state not init, wait for loading
|
|
32
|
+
if (!isUserStateInit) return;
|
|
33
|
+
|
|
34
|
+
// user need to onboard
|
|
35
|
+
if (!isOnboard) {
|
|
36
|
+
router.replace('/onboard');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// finally check the conversation status
|
|
41
|
+
if (isUserHasConversation) {
|
|
42
|
+
router.replace('/chat');
|
|
43
|
+
} else {
|
|
44
|
+
router.replace('/welcome');
|
|
45
|
+
}
|
|
46
|
+
}, [isUserStateInit, isLoaded, isUserHasConversation, isOnboard, isLogin]);
|
|
35
47
|
|
|
36
48
|
return null;
|
|
37
49
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { PropsWithChildren, memo } from 'react';
|
|
4
|
+
import { createStoreUpdater } from 'zustand-utils';
|
|
5
|
+
|
|
6
|
+
import { useUserStore } from '@/store/user';
|
|
7
|
+
|
|
8
|
+
const NoAuthProvider = memo<PropsWithChildren>(({ children }) => {
|
|
9
|
+
const useStoreUpdater = createStoreUpdater(useUserStore);
|
|
10
|
+
|
|
11
|
+
useStoreUpdater('isLoaded', true);
|
|
12
|
+
|
|
13
|
+
return children;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export default NoAuthProvider;
|
|
@@ -4,13 +4,14 @@ import { authEnv } from '@/config/auth';
|
|
|
4
4
|
|
|
5
5
|
import Clerk from './Clerk';
|
|
6
6
|
import NextAuth from './NextAuth';
|
|
7
|
+
import NoAuth from './NoAuth';
|
|
7
8
|
|
|
8
9
|
const AuthProvider = ({ children }: PropsWithChildren) => {
|
|
9
10
|
if (authEnv.NEXT_PUBLIC_ENABLE_CLERK_AUTH) return <Clerk>{children}</Clerk>;
|
|
10
11
|
|
|
11
12
|
if (authEnv.NEXT_PUBLIC_ENABLE_NEXT_AUTH) return <NextAuth>{children}</NextAuth>;
|
|
12
13
|
|
|
13
|
-
return children
|
|
14
|
+
return <NoAuth>{children}</NoAuth>;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
export default AuthProvider;
|
package/src/middleware.ts
CHANGED
|
@@ -41,16 +41,7 @@ const nextAuthMiddleware = auth((req) => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
export default authEnv.NEXT_PUBLIC_ENABLE_CLERK_AUTH
|
|
44
|
-
?
|
|
45
|
-
clerkMiddleware((auth, request) => {
|
|
46
|
-
// if user is logged in and on the home page, redirect to chat
|
|
47
|
-
if (auth().userId && request.nextUrl.pathname === '/') {
|
|
48
|
-
request.nextUrl.pathname = '/chat';
|
|
49
|
-
return NextResponse.redirect(request.nextUrl);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return NextResponse.next();
|
|
53
|
-
})
|
|
44
|
+
? clerkMiddleware()
|
|
54
45
|
: authEnv.NEXT_PUBLIC_ENABLE_NEXT_AUTH
|
|
55
46
|
? nextAuthMiddleware
|
|
56
47
|
: defaultMiddleware;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DeepPartial } from 'utility-types';
|
|
2
2
|
|
|
3
3
|
import { MessageModel } from '@/database/client/models/message';
|
|
4
|
+
import { SessionModel } from '@/database/client/models/session';
|
|
4
5
|
import { UserModel } from '@/database/client/models/user';
|
|
5
6
|
import { GlobalSettings } from '@/types/settings';
|
|
6
7
|
import { UserInitializationState, UserPreference } from '@/types/user';
|
|
@@ -18,10 +19,13 @@ export class ClientService implements IUserService {
|
|
|
18
19
|
async getUserState(): Promise<UserInitializationState> {
|
|
19
20
|
const user = await UserModel.getUser();
|
|
20
21
|
const messageCount = await MessageModel.count();
|
|
22
|
+
const sessionCount = await SessionModel.count();
|
|
21
23
|
|
|
22
24
|
return {
|
|
23
25
|
avatar: user.avatar,
|
|
26
|
+
canEnablePWAGuide: messageCount >= 2,
|
|
24
27
|
canEnableTrace: messageCount >= 4,
|
|
28
|
+
hasConversation: messageCount > 0 || sessionCount > 0,
|
|
25
29
|
isOnboard: true,
|
|
26
30
|
preference: await this.preferenceStorage.getFromLocalStorage(),
|
|
27
31
|
settings: user.settings as GlobalSettings,
|
|
@@ -6,7 +6,6 @@ import { UserInitializationState, UserPreference } from '@/types/user';
|
|
|
6
6
|
export interface IUserService {
|
|
7
7
|
getUserState: () => Promise<UserInitializationState>;
|
|
8
8
|
resetUserSettings: () => Promise<any>;
|
|
9
|
-
updateAvatar: (avatar: string) => Promise<any>;
|
|
10
9
|
updatePreference: (preference: UserPreference) => Promise<any>;
|
|
11
10
|
updateUserSettings: (patch: DeepPartial<GlobalSettings>) => Promise<any>;
|
|
12
11
|
}
|
|
@@ -41,6 +41,7 @@ const isLogin = (s: UserStore) => {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const authSelectors = {
|
|
44
|
+
isLoaded: (s: UserStore) => s.isLoaded,
|
|
44
45
|
isLogin,
|
|
45
46
|
isLoginWithAuth: (s: UserStore) => s.isSignedIn,
|
|
46
47
|
isLoginWithClerk: (s: UserStore): boolean => (s.isSignedIn && enableClerk) || false,
|
|
@@ -5,6 +5,7 @@ import { withSWR } from '~test-utils';
|
|
|
5
5
|
|
|
6
6
|
import { DEFAULT_PREFERENCE } from '@/const/user';
|
|
7
7
|
import { userService } from '@/services/user';
|
|
8
|
+
import { ClientService } from '@/services/user/client';
|
|
8
9
|
import { useUserStore } from '@/store/user';
|
|
9
10
|
import { preferenceSelectors } from '@/store/user/selectors';
|
|
10
11
|
import { GlobalServerConfig } from '@/types/serverConfig';
|
|
@@ -36,7 +37,7 @@ describe('createCommonSlice', () => {
|
|
|
36
37
|
const avatar = 'new-avatar';
|
|
37
38
|
|
|
38
39
|
const spyOn = vi.spyOn(result.current, 'refreshUserState');
|
|
39
|
-
const updateAvatarSpy = vi.spyOn(
|
|
40
|
+
const updateAvatarSpy = vi.spyOn(ClientService.prototype, 'updateAvatar');
|
|
40
41
|
|
|
41
42
|
await act(async () => {
|
|
42
43
|
await result.current.updateAvatar(avatar);
|
|
@@ -4,6 +4,7 @@ import type { StateCreator } from 'zustand/vanilla';
|
|
|
4
4
|
|
|
5
5
|
import { DEFAULT_PREFERENCE } from '@/const/user';
|
|
6
6
|
import { userService } from '@/services/user';
|
|
7
|
+
import { ClientService } from '@/services/user/client';
|
|
7
8
|
import type { UserStore } from '@/store/user';
|
|
8
9
|
import type { GlobalServerConfig } from '@/types/serverConfig';
|
|
9
10
|
import type { GlobalSettings } from '@/types/settings';
|
|
@@ -45,7 +46,9 @@ export const createCommonSlice: StateCreator<
|
|
|
45
46
|
await mutate(GET_USER_STATE_KEY);
|
|
46
47
|
},
|
|
47
48
|
updateAvatar: async (avatar) => {
|
|
48
|
-
|
|
49
|
+
const clientService = new ClientService();
|
|
50
|
+
|
|
51
|
+
await clientService.updateAvatar(avatar);
|
|
49
52
|
await get().refreshUserState();
|
|
50
53
|
},
|
|
51
54
|
|
|
@@ -89,8 +92,12 @@ export const createCommonSlice: StateCreator<
|
|
|
89
92
|
{
|
|
90
93
|
defaultSettings,
|
|
91
94
|
enabledNextAuth: serverConfig.enabledOAuthSSO,
|
|
95
|
+
isOnboard: data.isOnboard,
|
|
96
|
+
isShowPWAGuide: data.canEnablePWAGuide,
|
|
92
97
|
isUserCanEnableTrace: data.canEnableTrace,
|
|
98
|
+
isUserHasConversation: data.hasConversation,
|
|
93
99
|
isUserStateInit: true,
|
|
100
|
+
|
|
94
101
|
preference,
|
|
95
102
|
serverLanguageModel: serverConfig.languageModel,
|
|
96
103
|
settings: data.settings || {},
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
export interface CommonState {
|
|
2
|
+
isOnboard: boolean;
|
|
3
|
+
isShowPWAGuide: boolean;
|
|
2
4
|
isUserCanEnableTrace: boolean;
|
|
5
|
+
isUserHasConversation: boolean;
|
|
3
6
|
isUserStateInit: boolean;
|
|
4
7
|
}
|
|
5
8
|
|
|
6
9
|
export const initialCommonState: CommonState = {
|
|
10
|
+
isOnboard: false,
|
|
11
|
+
isShowPWAGuide: false,
|
|
7
12
|
isUserCanEnableTrace: false,
|
|
13
|
+
isUserHasConversation: false,
|
|
8
14
|
isUserStateInit: false,
|
|
9
15
|
};
|
package/src/types/user/index.ts
CHANGED
|
@@ -34,7 +34,9 @@ export interface UserPreference {
|
|
|
34
34
|
|
|
35
35
|
export interface UserInitializationState {
|
|
36
36
|
avatar?: string;
|
|
37
|
+
canEnablePWAGuide?: boolean;
|
|
37
38
|
canEnableTrace?: boolean;
|
|
39
|
+
hasConversation?: boolean;
|
|
38
40
|
isOnboard?: boolean;
|
|
39
41
|
preference: UserPreference;
|
|
40
42
|
settings: DeepPartial<GlobalSettings>;
|