@lobehub/chat 0.120.2 → 0.120.4

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 (109) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +47 -22
  3. package/README.zh-CN.md +53 -26
  4. package/docs/Deployment/Upstream-Sync.md +8 -2
  5. package/docs/Deployment/Upstream-Sync.zh-CN.md +9 -3
  6. package/docs/Development/Add-New-Locale.md +9 -1
  7. package/docs/Development/Add-New-Locale.zh-CN.md +9 -1
  8. package/docs/Development/Contributing-Guidelines.md +83 -0
  9. package/docs/Development/Contributing-Guidelines.zh-CN.md +13 -0
  10. package/docs/Development/Internationalization-Implementation.md +125 -0
  11. package/docs/Development/Internationalization-Implementation.zh-CN.md +9 -1
  12. package/docs/Development/State-Management/State-Management-Intro.md +224 -0
  13. package/docs/Development/State-Management/{index.zh-CN.md → State-Management-Intro.zh-CN.md} +25 -28
  14. package/docs/Home.md +9 -6
  15. package/docs/_Sidebar.md +10 -7
  16. package/locales/ar/common.json +1 -0
  17. package/locales/ar/setting.json +1 -3
  18. package/locales/de-DE/common.json +1 -0
  19. package/locales/de-DE/setting.json +1 -3
  20. package/locales/en-US/common.json +1 -0
  21. package/locales/en-US/setting.json +1 -3
  22. package/locales/es-ES/common.json +1 -0
  23. package/locales/es-ES/setting.json +1 -3
  24. package/locales/fr-FR/common.json +1 -0
  25. package/locales/fr-FR/setting.json +1 -3
  26. package/locales/it-IT/common.json +1 -0
  27. package/locales/it-IT/setting.json +1 -3
  28. package/locales/ja-JP/common.json +1 -0
  29. package/locales/ja-JP/setting.json +1 -3
  30. package/locales/ko-KR/common.json +1 -0
  31. package/locales/ko-KR/setting.json +1 -3
  32. package/locales/nl-NL/common.json +1 -0
  33. package/locales/nl-NL/setting.json +1 -3
  34. package/locales/pl-PL/common.json +1 -0
  35. package/locales/pl-PL/setting.json +1 -3
  36. package/locales/pt-BR/common.json +1 -0
  37. package/locales/pt-BR/setting.json +1 -3
  38. package/locales/ru-RU/common.json +1 -0
  39. package/locales/ru-RU/setting.json +1 -3
  40. package/locales/tr-TR/common.json +1 -0
  41. package/locales/tr-TR/setting.json +1 -3
  42. package/locales/vi-VN/common.json +1 -0
  43. package/locales/vi-VN/setting.json +1 -3
  44. package/locales/zh-CN/common.json +1 -0
  45. package/locales/zh-CN/setting.json +1 -3
  46. package/locales/zh-TW/common.json +1 -0
  47. package/locales/zh-TW/setting.json +1 -3
  48. package/next.config.mjs +2 -2
  49. package/package.json +8 -7
  50. package/scripts/docsWorkflow/const.ts +1 -1
  51. package/scripts/docsWorkflow/index.ts +9 -3
  52. package/scripts/readmeWorkflow/syncAgentIndex.ts +2 -2
  53. package/scripts/readmeWorkflow/syncPluginIndex.ts +2 -2
  54. package/src/app/chat/(desktop)/features/ChatHeader.tsx +6 -6
  55. package/src/app/chat/{features → (desktop)/features/SideBar}/SystemRole/index.tsx +8 -5
  56. package/src/app/chat/(desktop)/features/{SideBar.tsx → SideBar/index.tsx} +2 -3
  57. package/src/app/chat/(mobile)/index.tsx +17 -4
  58. package/src/app/chat/(mobile)/mobile/page.tsx +30 -2
  59. package/src/app/chat/components/SessionHydration/index.tsx +44 -0
  60. package/src/app/chat/features/SessionListContent/DefaultMode.tsx +6 -1
  61. package/src/app/chat/features/SessionListContent/List/Item/Actions.tsx +0 -2
  62. package/src/app/chat/features/SessionListContent/List/index.tsx +7 -3
  63. package/src/app/chat/features/TopicListContent/Header.tsx +1 -1
  64. package/src/app/chat/page.tsx +7 -3
  65. package/src/app/home/Redirect.tsx +2 -2
  66. package/src/app/metadata.ts +6 -0
  67. package/src/app/settings/common/Common.tsx +5 -6
  68. package/src/app/welcome/features/Banner/index.tsx +6 -7
  69. package/src/components/StoreHydration/ChatHydration/index.tsx +33 -0
  70. package/src/config/server.ts +4 -0
  71. package/src/const/locale.ts +2 -2
  72. package/src/const/url.ts +1 -1
  73. package/src/database/models/__tests__/message.test.ts +3 -2
  74. package/src/database/models/message.ts +13 -9
  75. package/src/database/schemas/message.ts +1 -1
  76. package/src/features/ChatInput/ActionBar/Clear.tsx +0 -2
  77. package/src/features/ChatInput/useChatInput.ts +2 -6
  78. package/src/features/Conversation/hooks/useInitConversation.ts +0 -2
  79. package/src/features/Conversation/index.tsx +7 -2
  80. package/src/features/PluginDetailModal/index.tsx +0 -2
  81. package/src/features/PluginDevModal/index.tsx +0 -1
  82. package/src/features/SideBar/TopActions.tsx +5 -5
  83. package/src/layout/GlobalLayout/Locale.tsx +37 -10
  84. package/src/layout/GlobalLayout/StoreHydration.tsx +12 -11
  85. package/src/layout/GlobalLayout/index.tsx +1 -1
  86. package/src/locales/default/setting.ts +0 -2
  87. package/src/locales/resources.ts +9 -7
  88. package/src/store/chat/slices/message/action.ts +1 -1
  89. package/src/store/chat/store.ts +2 -34
  90. package/src/store/global/slices/common/action.ts +6 -0
  91. package/src/store/global/slices/common/initialState.ts +5 -0
  92. package/src/store/session/index.ts +0 -1
  93. package/src/store/session/initialState.ts +6 -2
  94. package/src/store/session/slices/agent/selectors.ts +3 -1
  95. package/src/store/session/slices/session/action.ts +13 -17
  96. package/src/store/session/slices/session/selectors/list.ts +7 -0
  97. package/src/store/session/store.ts +5 -46
  98. package/src/app/chat/(mobile)/layout.mobile.tsx +0 -17
  99. package/src/app/chat/(mobile)/mobile/index.tsx +0 -30
  100. package/src/app/chat/(mobile)/mobile/layout.mobile.tsx +0 -11
  101. package/src/store/session/hooks/index.ts +0 -4
  102. package/src/store/session/hooks/useEffectAfterHydrated.ts +0 -27
  103. package/src/store/session/hooks/useOnFinishHydrationSession.ts +0 -19
  104. package/src/store/session/hooks/useSessionChatInit.ts +0 -12
  105. package/src/store/session/hooks/useSessionHydrated.ts +0 -13
  106. /package/docs/Development/{index.md → Intro.md} +0 -0
  107. /package/docs/Development/{index.zh-CN.md → Intro.zh-CN.md} +0 -0
  108. /package/src/app/chat/{features → (desktop)/features/SideBar}/SystemRole/style.ts +0 -0
  109. /package/src/app/chat/{features → components}/SidebarHeader/index.tsx +0 -0
@@ -168,7 +168,7 @@ export const chatMessage: StateCreator<
168
168
  // if message is empty and no files, then stop
169
169
  if (!message && (!fileIdList || fileIdList?.length === 0)) return;
170
170
 
171
- let newMessage: CreateMessageParams = {
171
+ const newMessage: CreateMessageParams = {
172
172
  content: message,
173
173
  // if message has attached with files, then add files to message and the agent
174
174
  files: fileIdList,
@@ -1,12 +1,9 @@
1
- import { PersistOptions, devtools, persist } from 'zustand/middleware';
1
+ import { devtools, subscribeWithSelector } from 'zustand/middleware';
2
2
  import { shallow } from 'zustand/shallow';
3
3
  import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
6
- import { createHyperStorage } from '@/store/middleware/createHyperStorage';
7
6
  import { isDev } from '@/utils/env';
8
- import { isInStandaloneMode } from '@/utils/matchMedia';
9
- import { isMobileScreen } from '@/utils/screen';
10
7
 
11
8
  import { ChatStoreState, initialState } from './initialState';
12
9
  import { ChatEnhanceAction, chatEnhance } from './slices/enchance/action';
@@ -36,42 +33,13 @@ const createStore: StateCreator<ChatStore, [['zustand/devtools', never]]> = (...
36
33
  ...chatPlugin(...params),
37
34
  });
38
35
 
39
- const persistOptions: PersistOptions<ChatStore> = {
40
- name: 'LobeChat_Chat',
41
-
42
- // 手动控制 Hydration ,避免 ssr 报错
43
- skipHydration: true,
44
-
45
- storage: createHyperStorage(() => {
46
- const isMobileAndPWA = isMobileScreen() && isInStandaloneMode();
47
- const selectors = [{ activeTopicId: 'topic' }];
48
-
49
- if (isMobileAndPWA)
50
- return {
51
- localStorage: {
52
- selectors,
53
- },
54
- };
55
-
56
- return {
57
- localStorage: false,
58
- url: {
59
- mode: 'hash',
60
- selectors,
61
- },
62
- };
63
- }),
64
- version: 0,
65
- };
66
-
67
36
  // =============== 实装 useStore ============ //
68
37
 
69
38
  export const useChatStore = createWithEqualityFn<ChatStore>()(
70
- persist(
39
+ subscribeWithSelector(
71
40
  devtools(createStore, {
72
41
  name: 'LobeChat_Chat' + (isDev ? '_DEV' : ''),
73
42
  }),
74
- persistOptions,
75
43
  ),
76
44
  shallow,
77
45
  );
@@ -3,6 +3,8 @@ import { gt } from 'semver';
3
3
  import useSWR, { SWRResponse } from 'swr';
4
4
  import type { StateCreator } from 'zustand/vanilla';
5
5
 
6
+ import { INBOX_SESSION_ID } from '@/const/session';
7
+ import { SESSION_CHAT_URL } from '@/const/url';
6
8
  import { CURRENT_VERSION } from '@/const/version';
7
9
  import { globalService } from '@/services/global';
8
10
  import type { GlobalStore } from '@/store/global';
@@ -18,6 +20,7 @@ const n = setNamespace('settings');
18
20
  * 设置操作
19
21
  */
20
22
  export interface CommonAction {
23
+ switchBackToChat: (sessionId?: string) => void;
21
24
  /**
22
25
  * 切换侧边栏选项
23
26
  * @param key - 选中的侧边栏选项
@@ -38,6 +41,9 @@ export const createCommonSlice: StateCreator<
38
41
  [],
39
42
  CommonAction
40
43
  > = (set, get) => ({
44
+ switchBackToChat: (sessionId) => {
45
+ get().router?.push(SESSION_CHAT_URL(sessionId || INBOX_SESSION_ID, get().isMobile));
46
+ },
41
47
  switchSideBar: (key) => {
42
48
  set({ sidebarKey: key }, false, n('switchSideBar', key));
43
49
  },
@@ -1,3 +1,5 @@
1
+ import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
2
+
1
3
  export enum SidebarTabKey {
2
4
  Chat = 'chat',
3
5
  Market = 'market',
@@ -33,17 +35,20 @@ export interface GlobalPreference {
33
35
 
34
36
  export interface GlobalCommonState {
35
37
  hasNewVersion?: boolean;
38
+ isMobile?: boolean;
36
39
  latestVersion?: string;
37
40
  /**
38
41
  * 用户偏好的 UI 状态
39
42
  * @localStorage
40
43
  */
41
44
  preference: GlobalPreference;
45
+ router?: AppRouterInstance;
42
46
  settingsTab: SettingsTabs;
43
47
  sidebarKey: SidebarTabKey;
44
48
  }
45
49
 
46
50
  export const initialCommonState: GlobalCommonState = {
51
+ isMobile: false,
47
52
  preference: {
48
53
  guide: {},
49
54
  inputHeight: 200,
@@ -1,3 +1,2 @@
1
- export * from './hooks';
2
1
  export type { SessionStore } from './store';
3
2
  export { useSessionStore } from './store';
@@ -10,9 +10,13 @@ export interface SessionState {
10
10
  * @description 当前正在编辑或查看的会话
11
11
  */
12
12
  activeId: string;
13
- fetchSessionsLoading: boolean;
14
13
  isMobile?: boolean;
15
14
  isSearching: boolean;
15
+ isSessionsFirstFetchFinished: boolean;
16
+ /**
17
+ * 后续看看是否可以将 router 部分的逻辑移出去
18
+ * @deprecated
19
+ */
16
20
  router?: AppRouterInstance;
17
21
  searchKeywords: string;
18
22
  searchSessions: LobeAgentSession[];
@@ -21,9 +25,9 @@ export interface SessionState {
21
25
 
22
26
  export const initialState: SessionStoreState = {
23
27
  activeId: 'inbox',
24
- fetchSessionsLoading: true,
25
28
  isMobile: false,
26
29
  isSearching: false,
30
+ isSessionsFirstFetchFinished: false,
27
31
  searchKeywords: '',
28
32
  searchSessions: [],
29
33
  sessions: [],
@@ -78,7 +78,9 @@ const currentAgentMeta = (s: SessionStore): MetaData => {
78
78
  const defaultMeta = {
79
79
  avatar: isInbox ? DEFAULT_INBOX_AVATAR : DEFAULT_AVATAR,
80
80
  backgroundColor: DEFAULT_BACKGROUND_COLOR,
81
- description: isInbox ? t('inbox.desc') : currentAgentSystemRole(s) || t('noDescription'),
81
+ description: isInbox
82
+ ? t('inbox.desc', { ns: 'chat' })
83
+ : currentAgentSystemRole(s) || t('noDescription'),
82
84
  title: isInbox ? t('inbox.title', { ns: 'chat' }) : t('defaultSession'),
83
85
  };
84
86
 
@@ -46,10 +46,6 @@ export interface SessionAction {
46
46
  duplicateSession: (id: string) => Promise<void>;
47
47
  /**
48
48
  * Pins or unpins a session.
49
- *
50
- * @param {string} id - The ID of the session to pin or unpin.
51
- * @param {boolean} [pinned] - Optional. If set to true, it pins the session. If set to false or omitted, it unpins the session.
52
- * @returns {Promise<void>} A promise that resolves when the session is successfully pinned or unpinned.
53
49
  */
54
50
  pinSession: (id: string, pinned?: boolean) => Promise<void>;
55
51
  /**
@@ -61,7 +57,6 @@ export interface SessionAction {
61
57
  * @param id - sessionId
62
58
  */
63
59
  removeSession: (id: string) => void;
64
- switchBackToChat: () => void;
65
60
  /**
66
61
  * switch session url
67
62
  */
@@ -80,7 +75,9 @@ export const createSessionSlice: StateCreator<
80
75
  SessionAction
81
76
  > = (set, get) => ({
82
77
  activeSession: (sessionId) => {
83
- set({ activeId: sessionId }, false, n('activeSession'));
78
+ if (get().activeId === sessionId) return;
79
+
80
+ set({ activeId: sessionId }, false, n(`activeSession/${sessionId}`));
84
81
  },
85
82
 
86
83
  clearSessions: async () => {
@@ -147,30 +144,29 @@ export const createSessionSlice: StateCreator<
147
144
  get().switchSession();
148
145
  }
149
146
  },
150
-
151
- switchBackToChat: () => {
152
- const { activeId, router } = get();
153
-
154
- const id = activeId || INBOX_SESSION_ID;
155
-
156
- get().activeSession(id);
157
-
158
- router?.push(SESSION_CHAT_URL(id, get().isMobile));
159
- },
160
147
  switchSession: (sessionId = INBOX_SESSION_ID) => {
161
148
  const { isMobile, router } = get();
162
149
 
163
150
  get().activeSession(sessionId);
164
151
 
152
+ // TODO: 后续可以把 router 移除
165
153
  router?.push(SESSION_CHAT_URL(sessionId, isMobile));
166
154
  },
167
155
 
168
156
  useFetchSessions: () =>
169
157
  useSWR<LobeSessions>(FETCH_SESSIONS_KEY, sessionService.getSessions, {
170
158
  onSuccess: (data) => {
159
+ // 由于 https://github.com/lobehub/lobe-chat/pull/541 的关系
160
+ // 只有触发了 refreshSessions 才会更新 sessions,进而触发页面 rerender
161
+ // 因此这里不能补充判断,否则会导致页面不更新
162
+ // TODO:后续的根本解法应该是解除 inbox 和 session 的数据耦合
163
+ // 避免互相依赖的情况出现
164
+
165
+ // if (get().isSessionsFirstFetchFinished && isEqual(get().sessions, data)) return;
166
+
171
167
  set(
172
168
  {
173
- fetchSessionsLoading: false,
169
+ isSessionsFirstFetchFinished: true,
174
170
  sessions: data,
175
171
  },
176
172
  false,
@@ -49,6 +49,11 @@ const hasCustomAgents = (s: SessionStore) => defaultSessions(s).length > 0;
49
49
 
50
50
  const isInboxSession = (s: SessionStore) => s.activeId === INBOX_SESSION_ID;
51
51
 
52
+ const isSessionListInit = (s: SessionStore) => s.isSessionsFirstFetchFinished;
53
+
54
+ // use to judge whether a session is fully activated
55
+ const isSomeSessionActive = (s: SessionStore) => !!s.activeId && isSessionListInit(s);
56
+
52
57
  export const sessionSelectors = {
53
58
  currentSession,
54
59
  currentSessionSafe,
@@ -57,6 +62,8 @@ export const sessionSelectors = {
57
62
  hasCustomAgents,
58
63
  hasPinnedSessionList,
59
64
  isInboxSession,
65
+ isSessionListInit,
66
+ isSomeSessionActive,
60
67
  pinnedSessionList,
61
68
  searchSessions,
62
69
  unpinnedSessionList,
@@ -1,13 +1,10 @@
1
- import { PersistOptions, devtools, persist, subscribeWithSelector } from 'zustand/middleware';
1
+ import { devtools, subscribeWithSelector } from 'zustand/middleware';
2
2
  import { shallow } from 'zustand/shallow';
3
3
  import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
6
6
  import { isDev } from '@/utils/env';
7
- import { isInStandaloneMode } from '@/utils/matchMedia';
8
- import { isMobileScreen } from '@/utils/screen';
9
7
 
10
- import { createHyperStorage } from '../middleware/createHyperStorage';
11
8
  import { SessionStoreState, initialState } from './initialState';
12
9
  import { AgentAction, createAgentSlice } from './slices/agent/action';
13
10
  import { SessionAction, createSessionSlice } from './slices/session/action';
@@ -21,51 +18,13 @@ const createStore: StateCreator<SessionStore, [['zustand/devtools', never]]> = (
21
18
  ...createSessionSlice(...parameters),
22
19
  });
23
20
 
24
- // =============== persist 本地缓存中间件配置 ============ //
25
-
26
- const persistOptions: PersistOptions<SessionStore> = {
27
- name: 'LOBE_CHAT',
28
-
29
- // 手动控制 Hydration ,避免 ssr 报错
30
- skipHydration: true,
31
-
32
- storage: createHyperStorage(() => {
33
- const isMobileAndPWA = isMobileScreen() && isInStandaloneMode();
34
-
35
- const selectors = [
36
- // map state key to storage key
37
- { activeId: 'session' },
38
- ];
39
-
40
- if (isMobileAndPWA)
41
- return {
42
- localStorage: {
43
- selectors,
44
- },
45
- };
46
-
47
- return {
48
- localStorage: false,
49
- url: {
50
- mode: 'hash',
51
- selectors,
52
- },
53
- };
54
- }),
55
-
56
- version: 2,
57
- };
58
-
59
21
  // =============== 实装 useStore ============ //
60
22
 
61
23
  export const useSessionStore = createWithEqualityFn<SessionStore>()(
62
- persist(
63
- subscribeWithSelector(
64
- devtools(createStore, {
65
- name: 'LobeChat_Session' + (isDev ? '_DEV' : ''),
66
- }),
67
- ),
68
- persistOptions,
24
+ subscribeWithSelector(
25
+ devtools(createStore, {
26
+ name: 'LobeChat_Session' + (isDev ? '_DEV' : ''),
27
+ }),
69
28
  ),
70
29
  shallow,
71
30
  );
@@ -1,17 +0,0 @@
1
- 'use client';
2
-
3
- import { PropsWithChildren, memo } from 'react';
4
-
5
- import SessionHeader from '@/app/chat/(mobile)/features/SessionHeader';
6
- import AppLayoutMobile from '@/layout/AppLayout.mobile';
7
- import { useSwitchSideBarOnInit } from '@/store/global';
8
- import { SidebarTabKey } from '@/store/global/initialState';
9
-
10
- export default memo(({ children }: PropsWithChildren) => {
11
- useSwitchSideBarOnInit(SidebarTabKey.Chat);
12
- return (
13
- <AppLayoutMobile navBar={<SessionHeader />} showTabBar>
14
- {children}
15
- </AppLayoutMobile>
16
- );
17
- });
@@ -1,30 +0,0 @@
1
- 'use client';
2
-
3
- import dynamic from 'next/dynamic';
4
- import { memo } from 'react';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import Conversation from '@/features/Conversation';
8
- import { useSessionStore } from '@/store/session';
9
-
10
- import ChatInput from '../features/ChatInput';
11
- import Layout from './layout.mobile';
12
-
13
- const TopicList = dynamic(() => import('../features/TopicList'));
14
-
15
- const Chat = memo(() => {
16
- // due to mobile side don't have sessionList, so we need to fetch sessions here
17
- // refs: https://github.com/lobehub/lobe-chat/pull/541
18
- const useFetchSessions = useSessionStore((s) => s.useFetchSessions);
19
- useFetchSessions();
20
-
21
- return (
22
- <Layout>
23
- <Flexbox height={'calc(100% - 44px)'} horizontal>
24
- <Conversation chatInput={<ChatInput />} mobile />
25
- <TopicList />
26
- </Flexbox>
27
- </Layout>
28
- );
29
- });
30
- export default Chat;
@@ -1,11 +0,0 @@
1
- 'use client';
2
-
3
- import { PropsWithChildren } from 'react';
4
-
5
- import AppLayoutMobile from '@/layout/AppLayout.mobile';
6
-
7
- import ChatHeader from '../features/ChatHeader';
8
-
9
- export default ({ children }: PropsWithChildren) => (
10
- <AppLayoutMobile navBar={<ChatHeader />}>{children}</AppLayoutMobile>
11
- );
@@ -1,4 +0,0 @@
1
- export * from './useEffectAfterHydrated';
2
- export * from './useOnFinishHydrationSession';
3
- export * from './useSessionChatInit';
4
- export * from './useSessionHydrated';
@@ -1,27 +0,0 @@
1
- import { useEffect } from 'react';
2
-
3
- import { SessionStore, useSessionStore } from '../store';
4
-
5
- export const useEffectAfterSessionHydrated = (
6
- fn: (session: typeof useSessionStore, store: SessionStore) => void,
7
- deps: any[] = [],
8
- ) => {
9
- // const hasTrigger = useRef(false);
10
- useEffect(() => {
11
- const hasRehydrated = useSessionStore.persist.hasHydrated();
12
-
13
- if (hasRehydrated) {
14
- // equal useEffect triggered multi-time
15
- fn(useSessionStore, useSessionStore.getState());
16
- } else {
17
- // keep onFinishHydration just are triggered only once
18
- // if (hasTrigger.current) return;
19
- //
20
- // hasTrigger.current = true;
21
- // equal useEffect first trigger
22
- useSessionStore.persist.onFinishHydration(() => {
23
- fn(useSessionStore, useSessionStore.getState());
24
- });
25
- }
26
- }, deps);
27
- };
@@ -1,19 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { StoreApi, UseBoundStore } from 'zustand';
3
-
4
- import { SessionStore, useSessionStore } from '../store';
5
-
6
- /**
7
- * 当 Session 水合完毕后才会执行的 useEffect
8
- * @param fn
9
- */
10
- export const useOnFinishHydrationSession = (
11
- fn: (state: SessionStore, store: UseBoundStore<StoreApi<SessionStore>>) => void,
12
- ) => {
13
- useEffect(() => {
14
- // 只有当水合完毕后再开始做操作
15
- useSessionStore.persist.onFinishHydration(() => {
16
- fn(useSessionStore.getState(), useSessionStore);
17
- });
18
- }, []);
19
- };
@@ -1,12 +0,0 @@
1
- import { useSessionStore } from '../store';
2
- import { useSessionHydrated } from './useSessionHydrated';
3
-
4
- /**
5
- * 用于判断某个会话是否完全被激活
6
- */
7
- export const useSessionChatInit = () => {
8
- const sessionHydrated = useSessionHydrated();
9
- const [hasActive] = useSessionStore((s) => [!!s.activeId]);
10
-
11
- return sessionHydrated && hasActive;
12
- };
@@ -1,13 +0,0 @@
1
- import { useSessionStore } from '../store';
2
-
3
- export const useSessionHydrated = () => {
4
- const [fetchSessionsLoading, useFetchSessions] = useSessionStore((s) => [
5
- s.fetchSessionsLoading,
6
-
7
- s.useFetchSessions,
8
- ]);
9
-
10
- const { isLoading } = useFetchSessions();
11
-
12
- return !(isLoading || fetchSessionsLoading);
13
- };
File without changes