@lobehub/lobehub 2.0.0-next.294 → 2.0.0-next.295

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 (170) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/apps/desktop/src/main/__mocks__/node-mac-permissions.ts +0 -1
  3. package/apps/desktop/src/main/__mocks__/setup.ts +0 -1
  4. package/apps/desktop/src/main/controllers/__tests__/SystemCtr.test.ts +1 -4
  5. package/apps/desktop/tsconfig.json +4 -10
  6. package/changelog/v1.json +9 -0
  7. package/e2e/scripts/setup.ts +45 -32
  8. package/package.json +1 -1
  9. package/packages/database/src/models/__tests__/knowledgeBase.test.ts +1 -1
  10. package/packages/database/src/repositories/knowledge/index.ts +1 -4
  11. package/packages/types/src/discover/assistants.ts +2 -2
  12. package/scripts/migrate-spa-navigation.ts +129 -0
  13. package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-topics/route.ts +112 -109
  14. package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-user-topics/route.ts +125 -113
  15. package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-users/route.ts +74 -65
  16. package/src/app/[variants]/(auth)/auth-error/page.tsx +1 -1
  17. package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +1 -1
  18. package/src/app/[variants]/(auth)/next-auth/error/AuthErrorPage.tsx +1 -1
  19. package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +1 -1
  20. package/src/app/[variants]/(auth)/oauth/callback/error/page.tsx +1 -1
  21. package/src/app/[variants]/(auth)/oauth/callback/success/page.tsx +1 -1
  22. package/src/app/[variants]/(auth)/oauth/consent/[uid]/page.tsx +1 -1
  23. package/src/app/[variants]/(auth)/reset-password/layout.tsx +1 -1
  24. package/src/app/[variants]/(auth)/reset-password/page.tsx +2 -2
  25. package/src/app/[variants]/(auth)/signin/layout.tsx +1 -1
  26. package/src/app/[variants]/(auth)/signin/useSignIn.ts +1 -1
  27. package/src/app/[variants]/(auth)/signup/[[...signup]]/BetterAuthSignUpForm.tsx +2 -2
  28. package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -1
  29. package/src/app/[variants]/(auth)/signup/[[...signup]]/useSignUp.tsx +1 -1
  30. package/src/app/[variants]/(auth)/verify-email/layout.tsx +1 -1
  31. package/src/app/[variants]/(auth)/verify-email/page.tsx +2 -2
  32. package/src/app/[variants]/(main)/_layout/index.tsx +1 -1
  33. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/CronTopicGroup.tsx +1 -1
  34. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/AddTopicButon.tsx +1 -1
  35. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/Nav.tsx +1 -1
  36. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/AllTopicsDrawer/index.tsx +1 -1
  37. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/hooks/useThreadNavigation.ts +1 -1
  38. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/hooks/useTopicNavigation.ts +1 -1
  39. package/src/app/[variants]/(main)/agent/features/TelemetryNotification.tsx +2 -3
  40. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Nav.tsx +9 -9
  41. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -3
  42. package/src/app/[variants]/(main)/community/(detail)/features/MakedownRender.tsx +1 -2
  43. package/src/app/[variants]/(main)/community/(detail)/features/ShareButton.tsx +2 -3
  44. package/src/app/[variants]/(main)/community/(detail)/features/Toc/Heading.tsx +2 -3
  45. package/src/app/[variants]/(main)/community/(detail)/mcp/features/Details/Versions/index.tsx +2 -2
  46. package/src/app/[variants]/(main)/community/(detail)/model/features/Details/Nav.tsx +12 -11
  47. package/src/app/[variants]/(main)/community/(detail)/model/features/Details/Parameter/ParameterItem.tsx +2 -3
  48. package/src/app/[variants]/(main)/community/(detail)/provider/features/Details/Nav.tsx +11 -10
  49. package/src/app/[variants]/(main)/community/(detail)/provider/features/Header.tsx +10 -9
  50. package/src/app/[variants]/(main)/community/(list)/(home)/index.tsx +1 -1
  51. package/src/app/[variants]/(main)/community/(list)/assistant/features/Category/useCategory.tsx +1 -1
  52. package/src/app/[variants]/(main)/community/(list)/features/SortButton/index.tsx +2 -3
  53. package/src/app/[variants]/(main)/community/_layout/Sidebar/Header/Nav.tsx +1 -1
  54. package/src/app/[variants]/(main)/community/features/CreateButton/Inner.tsx +1 -1
  55. package/src/app/[variants]/(main)/community/features/CreateButton/index.tsx +1 -1
  56. package/src/app/[variants]/(main)/community/features/Search.tsx +1 -2
  57. package/src/app/[variants]/(main)/community/features/Title.tsx +5 -5
  58. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/Nav.tsx +1 -1
  59. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/AllTopicsDrawer/index.tsx +1 -1
  60. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/hooks/useThreadNavigation.ts +1 -1
  61. package/src/app/[variants]/(main)/group/features/Conversation/Header/ShareButton/index.tsx +1 -1
  62. package/src/app/[variants]/(main)/group/features/TelemetryNotification.tsx +2 -3
  63. package/src/app/[variants]/(main)/home/_layout/Body/Agent/AllAgentsDrawer/index.tsx +1 -1
  64. package/src/app/[variants]/(main)/hooks/useActiveTabKey.ts +6 -11
  65. package/src/app/[variants]/(main)/image/NotSupportClient.tsx +4 -3
  66. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ImageUpload.tsx +1 -1
  67. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/ImageManageModal.tsx +1 -1
  68. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/index.tsx +1 -1
  69. package/src/app/[variants]/(main)/memory/(home)/features/RoleTagCloud/index.tsx +1 -1
  70. package/src/app/[variants]/(main)/memory/_layout/Sidebar/Header/Nav.tsx +1 -1
  71. package/src/app/[variants]/(main)/memory/features/SourceLink.tsx +1 -1
  72. package/src/app/[variants]/(main)/page/_layout/Body/AllPagesDrawer/index.tsx +1 -1
  73. package/src/app/[variants]/(main)/settings/about/features/ItemCard.tsx +2 -3
  74. package/src/app/[variants]/(main)/settings/about/features/ItemLink.tsx +2 -3
  75. package/src/app/[variants]/(main)/settings/about/features/Version.tsx +6 -7
  76. package/src/app/[variants]/(main)/settings/features/SettingsContent.tsx +1 -1
  77. package/src/app/[variants]/(main)/settings/features/UpgradeAlert.tsx +4 -4
  78. package/src/app/[variants]/(main)/settings/provider/(list)/Footer.tsx +2 -2
  79. package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +1 -1
  80. package/src/app/[variants]/(main)/settings/provider/detail/ollama/CheckError.tsx +1 -1
  81. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +12 -6
  82. package/src/app/[variants]/(main)/settings/security/index.tsx +1 -1
  83. package/src/app/[variants]/(main)/settings/stats/features/overview/ShareButton/ShareModal.tsx +1 -1
  84. package/src/app/[variants]/(main)/settings/stats/features/rankings/AssistantsRank.tsx +1 -1
  85. package/src/app/[variants]/(main)/settings/stats/features/rankings/TopicsRank.tsx +1 -1
  86. package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -1
  87. package/src/app/[variants]/(mobile)/chat/settings/features/AgentInfoDescription/index.tsx +1 -1
  88. package/src/app/[variants]/(mobile)/chat/settings/features/SettingButton.tsx +1 -1
  89. package/src/app/[variants]/(mobile)/router/index.tsx +1 -1
  90. package/src/app/[variants]/page.tsx +1 -1
  91. package/src/app/[variants]/router/index.tsx +1 -1
  92. package/src/components/404/index.tsx +4 -4
  93. package/src/components/Analytics/index.tsx +1 -1
  94. package/src/components/BrandWatermark/index.tsx +4 -4
  95. package/src/components/Branding/ProductLogo/Custom.tsx +1 -1
  96. package/src/components/Error/index.tsx +3 -4
  97. package/src/components/GoBack/index.tsx +2 -2
  98. package/src/components/LabsModal/LabCard.tsx +1 -1
  99. package/src/components/Link.tsx +25 -5
  100. package/src/components/OllamaSetupGuide/index.tsx +5 -4
  101. package/src/components/WebFavicon/index.tsx +1 -1
  102. package/src/components/client/ClientResponsiveContent/index.tsx +1 -1
  103. package/src/components/client/ClientResponsiveLayout.tsx +1 -1
  104. package/src/components/mdx/Image.tsx +1 -1
  105. package/src/components/mdx/Link.tsx +26 -9
  106. package/src/features/AlertBanner/CloudBanner.tsx +2 -3
  107. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +8 -7
  108. package/src/features/ChatInput/ActionBar/Params/Controls.tsx +1 -3
  109. package/src/features/ChatInput/ActionBar/Token/index.tsx +1 -1
  110. package/src/features/ChatInput/Mobile/index.tsx +1 -1
  111. package/src/features/Conversation/ChatItem/components/MessageContent/index.tsx +1 -1
  112. package/src/features/Conversation/Error/OllamaBizError/index.tsx +1 -1
  113. package/src/features/Conversation/Error/OllamaSetupGuide/Desktop.tsx +1 -2
  114. package/src/features/Conversation/Error/index.tsx +1 -1
  115. package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/Settings.tsx +1 -1
  116. package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +1 -1
  117. package/src/features/Conversation/Messages/AssistantGroup/index.tsx +1 -1
  118. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +1 -1
  119. package/src/features/Conversation/Messages/components/SearchGrounding.tsx +1 -1
  120. package/src/features/DataImporter/Error.tsx +3 -3
  121. package/src/features/DevPanel/CacheViewer/cacheProvider.tsx +2 -1
  122. package/src/features/DevPanel/MetadataViewer/Og.tsx +1 -1
  123. package/src/features/DevPanel/features/FloatPanel.tsx +1 -1
  124. package/src/features/DevPanel/features/Table/TooltipContent.tsx +3 -4
  125. package/src/features/DevPanel/index.tsx +1 -1
  126. package/src/features/EditorCanvas/InlineToolbar.tsx +1 -6
  127. package/src/features/FileViewer/NotSupport/index.tsx +2 -3
  128. package/src/features/Follow/index.tsx +8 -9
  129. package/src/features/LibraryModal/AddFilesToKnowledgeBase/SelectForm.tsx +2 -2
  130. package/src/features/MCP/Scores.tsx +1 -1
  131. package/src/features/MCPPluginDetail/Nav.tsx +8 -8
  132. package/src/features/MCPPluginDetail/Overview/TagList.tsx +1 -1
  133. package/src/features/MobileTabBar/index.tsx +2 -1
  134. package/src/features/OllamaSetupGuide/Desktop.tsx +1 -2
  135. package/src/features/PWAInstall/Install.tsx +1 -1
  136. package/src/features/PWAInstall/index.tsx +1 -1
  137. package/src/features/PluginStore/McpList/index.tsx +1 -1
  138. package/src/features/PluginStore/PluginList/Detail/Header.tsx +6 -6
  139. package/src/features/PluginsUI/Render/DefaultType/index.tsx +1 -1
  140. package/src/features/Portal/Artifacts/Body/Renderer/index.tsx +1 -1
  141. package/src/features/ResourceManager/components/ChunkDrawer/index.tsx +1 -1
  142. package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +26 -26
  143. package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +147 -149
  144. package/src/features/ResourceManager/index.tsx +1 -1
  145. package/src/features/Setting/Footer.tsx +4 -5
  146. package/src/features/User/UserPanel/PanelContent.tsx +1 -1
  147. package/src/hooks/useActiveTabKey.ts +6 -3
  148. package/src/hooks/useIsSingleMode.test.ts +10 -24
  149. package/src/hooks/useIsSingleMode.ts +4 -2
  150. package/src/hooks/useIsSubSlug.ts +2 -1
  151. package/src/hooks/useQuery.ts +5 -5
  152. package/src/layout/GlobalProvider/AppTheme.tsx +2 -2
  153. package/src/layout/GlobalProvider/StyleRegistry.tsx +1 -1
  154. package/src/layout/GlobalProvider/useUserStateRedirect.ts +13 -25
  155. package/src/libs/next/Image.tsx +13 -0
  156. package/src/libs/next/Link.tsx +13 -0
  157. package/src/libs/next/dynamic.tsx +13 -0
  158. package/src/libs/next/index.ts +22 -0
  159. package/src/libs/next/navigation.ts +22 -0
  160. package/src/libs/router/Link.tsx +30 -0
  161. package/src/libs/router/index.ts +18 -0
  162. package/src/libs/router/navigation.ts +72 -0
  163. package/src/server/modules/AgentRuntime/AgentStateManager.ts +5 -1
  164. package/src/store/chat/slices/portal/selectors.test.ts +5 -15
  165. package/src/store/page/index.ts +1 -1
  166. package/src/store/page/slices/crud/index.ts +1 -1
  167. package/src/app/[variants]/(main)/hooks/usePathname.ts +0 -10
  168. package/src/app/[variants]/(main)/hooks/useQuery.ts +0 -12
  169. package/src/app/[variants]/(main)/hooks/useRouter.ts +0 -22
  170. package/src/app/[variants]/(main)/hooks/useSearchParams.ts +0 -11
@@ -1,7 +1,8 @@
1
+ import { Client } from '@upstash/qstash';
1
2
  import { serve } from '@upstash/workflow/nextjs';
2
3
  import { chunk } from 'es-toolkit/compat';
3
- import { Client } from '@upstash/qstash'
4
4
 
5
+ import { parseMemoryExtractionConfig } from '@/server/globalConfig/parseMemoryExtractionConfig';
5
6
  import {
6
7
  MemoryExtractionExecutor,
7
8
  type MemoryExtractionPayloadInput,
@@ -9,82 +10,90 @@ import {
9
10
  buildWorkflowPayloadInput,
10
11
  normalizeMemoryExtractionPayload,
11
12
  } from '@/server/services/memory/userMemory/extract';
12
- import { parseMemoryExtractionConfig } from '@/server/globalConfig/parseMemoryExtractionConfig';
13
13
 
14
14
  const USER_PAGE_SIZE = 50;
15
15
  const USER_BATCH_SIZE = 10;
16
16
 
17
17
  const { upstashWorkflowExtraHeaders } = parseMemoryExtractionConfig();
18
18
 
19
- export const { POST } = serve<MemoryExtractionPayloadInput>(async (context) => {
20
- const params = normalizeMemoryExtractionPayload(context.requestPayload || {});
21
- if (params.sources.length === 0) {
22
- return { message: 'No sources provided, skip memory extraction.' };
23
- }
19
+ export const { POST } = serve<MemoryExtractionPayloadInput>(
20
+ async (context) => {
21
+ const params = normalizeMemoryExtractionPayload(context.requestPayload || {});
22
+ if (params.sources.length === 0) {
23
+ return { message: 'No sources provided, skip memory extraction.' };
24
+ }
24
25
 
25
- const executor = await MemoryExtractionExecutor.create();
26
+ const executor = await MemoryExtractionExecutor.create();
26
27
 
27
- // NOTICE: Upstash Workflow only supports serializable data into plain JSON,
28
- // this causes the Date object to be converted into string when passed as parameter from
29
- // context to child workflow. So we need to convert it back to Date object here.
30
- const userCursor = params.userCursor
31
- ? { createdAt: new Date(params.userCursor.createdAt), id: params.userCursor.id }
32
- : undefined;
28
+ // NOTICE: Upstash Workflow only supports serializable data into plain JSON,
29
+ // this causes the Date object to be converted into string when passed as parameter from
30
+ // context to child workflow. So we need to convert it back to Date object here.
31
+ const userCursor = params.userCursor
32
+ ? { createdAt: new Date(params.userCursor.createdAt), id: params.userCursor.id }
33
+ : undefined;
33
34
 
34
- const userBatch = await context.run('memory:user-memory:extract:get-users', () =>
35
- params.userIds.length > 0
36
- ? { ids: params.userIds }
37
- : executor.getUsers(USER_PAGE_SIZE, userCursor),
38
- );
35
+ const userBatch = await context.run('memory:user-memory:extract:get-users', () =>
36
+ params.userIds.length > 0
37
+ ? { ids: params.userIds }
38
+ : executor.getUsers(USER_PAGE_SIZE, userCursor),
39
+ );
39
40
 
40
- const ids = userBatch.ids;
41
- if (ids.length === 0) {
42
- return { message: 'No users to process for memory extraction.' };
43
- }
41
+ const ids = userBatch.ids;
42
+ if (ids.length === 0) {
43
+ return { message: 'No users to process for memory extraction.' };
44
+ }
44
45
 
45
- const cursor = 'cursor' in userBatch ? userBatch.cursor : undefined;
46
+ const cursor = 'cursor' in userBatch ? userBatch.cursor : undefined;
46
47
 
47
- const batches = chunk(ids, USER_BATCH_SIZE);
48
- await Promise.all(
49
- batches.map((userIds) =>
50
- context.run(`memory:user-memory:extract:users:process-topic-batches`, () =>
51
- MemoryExtractionWorkflowService.triggerProcessUserTopics({
52
- ...buildWorkflowPayloadInput(params),
53
- topicCursor: undefined,
54
- userId: userIds[0],
55
- userIds,
56
- }, { extraHeaders: upstashWorkflowExtraHeaders},),
48
+ const batches = chunk(ids, USER_BATCH_SIZE);
49
+ await Promise.all(
50
+ batches.map((userIds) =>
51
+ context.run(`memory:user-memory:extract:users:process-topic-batches`, () =>
52
+ MemoryExtractionWorkflowService.triggerProcessUserTopics(
53
+ {
54
+ ...buildWorkflowPayloadInput(params),
55
+ topicCursor: undefined,
56
+ userId: userIds[0],
57
+ userIds,
58
+ },
59
+ { extraHeaders: upstashWorkflowExtraHeaders },
60
+ ),
61
+ ),
57
62
  ),
58
- ),
59
- );
60
-
61
- if (params.userIds.length === 0 && cursor) {
62
- await context.run('memory:user-memory:extract:users:schedule-next-user-batch', () =>
63
- MemoryExtractionWorkflowService.triggerProcessUsers({
64
- ...buildWorkflowPayloadInput({
65
- ...params,
66
- userCursor: { createdAt: cursor.createdAt.toISOString(), id: cursor.id },
67
- }),
68
- }, { extraHeaders: upstashWorkflowExtraHeaders }),
69
63
  );
70
- }
71
64
 
72
- return {
73
- batches: batches.length,
74
- nextCursor: cursor ? cursor.id : null,
75
- processedUsers: ids.length,
76
- };
77
- }, {
78
- // NOTICE(@nekomeowww): Here as scenarios like Vercel Deployment Protection,
79
- // intermediate context.run(...) won't offer customizable headers like context.trigger(...) / client.trigger(...)
80
- // for passing additional headers, we have to provide a custom QStash client with the required headers here.
81
- //
82
- // Refer to the doc for more details:
83
- // https://upstash.com/docs/workflow/troubleshooting/vercel#step-2-pass-header-when-triggering
84
- qstashClient: new Client({
85
- headers: {
86
- ...upstashWorkflowExtraHeaders,
87
- },
88
- token: process.env.QSTASH_TOKEN!
89
- })
90
- });
65
+ if (params.userIds.length === 0 && cursor) {
66
+ await context.run('memory:user-memory:extract:users:schedule-next-user-batch', () =>
67
+ MemoryExtractionWorkflowService.triggerProcessUsers(
68
+ {
69
+ ...buildWorkflowPayloadInput({
70
+ ...params,
71
+ userCursor: { createdAt: cursor.createdAt.toISOString(), id: cursor.id },
72
+ }),
73
+ },
74
+ { extraHeaders: upstashWorkflowExtraHeaders },
75
+ ),
76
+ );
77
+ }
78
+
79
+ return {
80
+ batches: batches.length,
81
+ nextCursor: cursor ? cursor.id : null,
82
+ processedUsers: ids.length,
83
+ };
84
+ },
85
+ {
86
+ // NOTICE(@nekomeowww): Here as scenarios like Vercel Deployment Protection,
87
+ // intermediate context.run(...) won't offer customizable headers like context.trigger(...) / client.trigger(...)
88
+ // for passing additional headers, we have to provide a custom QStash client with the required headers here.
89
+ //
90
+ // Refer to the doc for more details:
91
+ // https://upstash.com/docs/workflow/troubleshooting/vercel#step-2-pass-header-when-triggering
92
+ qstashClient: new Client({
93
+ headers: {
94
+ ...upstashWorkflowExtraHeaders,
95
+ },
96
+ token: process.env.QSTASH_TOKEN!,
97
+ }),
98
+ },
99
+ );
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { SiDiscord } from '@icons-pack/react-simple-icons';
4
4
  import { Alert, Button, Flexbox, Icon } from '@lobehub/ui';
5
- import Link from 'next/link';
5
+ import Link from '@/libs/next/Link';
6
6
  import { parseAsString, useQueryState } from 'nuqs';
7
7
  import { memo } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
@@ -1,6 +1,6 @@
1
1
  import { SignIn } from '@clerk/nextjs';
2
2
  import { BRANDING_NAME } from '@lobechat/business-const';
3
- import { notFound } from 'next/navigation';
3
+ import { notFound } from '@/libs/next/navigation';
4
4
 
5
5
  import { enableClerk } from '@/envs/auth';
6
6
  import { metadataModule } from '@/server/metadata';
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { signIn } from 'next-auth/react';
4
- import { useSearchParams } from 'next/navigation';
4
+ import { useSearchParams } from '@/libs/next/navigation';
5
5
  import { memo } from 'react';
6
6
 
7
7
  import ErrorCapture from '@/components/Error';
@@ -8,7 +8,7 @@ import { Col, Flex, Row } from 'antd';
8
8
  import { createStaticStyles } from 'antd-style';
9
9
  import { AuthError } from 'next-auth';
10
10
  import { signIn } from 'next-auth/react';
11
- import { useRouter, useSearchParams } from 'next/navigation';
11
+ import { useRouter, useSearchParams } from '@/libs/next/navigation';
12
12
  import { memo, useState } from 'react';
13
13
  import { useTranslation } from 'react-i18next';
14
14
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Button, Flexbox, FluentEmoji, Highlighter, Text } from '@lobehub/ui';
4
4
  import { Result } from 'antd';
5
- import Link from 'next/link';
5
+ import Link from '@/libs/next/Link';
6
6
  import { parseAsString, useQueryState } from 'nuqs';
7
7
  import React, { memo } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { FluentEmoji, Text } from '@lobehub/ui';
4
4
  import { Result } from 'antd';
5
- import { useSearchParams } from 'next/navigation';
5
+ import { useSearchParams } from '@/libs/next/navigation';
6
6
  import React, { memo, useEffect, useState } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
8
8
 
@@ -1,4 +1,4 @@
1
- import { notFound } from 'next/navigation';
1
+ import { notFound } from '@/libs/next/navigation';
2
2
 
3
3
  import { authEnv } from '@/envs/auth';
4
4
  import { defaultClients } from '@/libs/oidc-provider/config';
@@ -1,4 +1,4 @@
1
- import { notFound } from 'next/navigation';
1
+ import { notFound } from '@/libs/next/navigation';
2
2
  import { type PropsWithChildren } from 'react';
3
3
 
4
4
  import { enableBetterAuth } from '@/envs/auth';
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { Button } from '@lobehub/ui';
4
4
  import { ChevronLeftIcon } from 'lucide-react';
5
- import Link from 'next/link';
6
- import { useRouter, useSearchParams } from 'next/navigation';
5
+ import Link from '@/libs/next/Link';
6
+ import { useRouter, useSearchParams } from '@/libs/next/navigation';
7
7
  import { useTranslation } from 'react-i18next';
8
8
 
9
9
  import AuthCard from '../../../../features/AuthCard';
@@ -1,4 +1,4 @@
1
- import { notFound } from 'next/navigation';
1
+ import { notFound } from '@/libs/next/navigation';
2
2
  import { type PropsWithChildren } from 'react';
3
3
 
4
4
  import { enableBetterAuth } from '@/envs/auth';
@@ -1,6 +1,6 @@
1
1
  import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
2
2
  import { Form } from 'antd';
3
- import { useRouter, useSearchParams } from 'next/navigation';
3
+ import { useRouter, useSearchParams } from '@/libs/next/navigation';
4
4
  import { useEffect, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
@@ -3,8 +3,8 @@
3
3
  import { Button, Icon, Text } from '@lobehub/ui';
4
4
  import { Form, Input } from 'antd';
5
5
  import { Lock, Mail } from 'lucide-react';
6
- import Link from 'next/link';
7
- import { useSearchParams } from 'next/navigation';
6
+ import Link from '@/libs/next/Link';
7
+ import { useSearchParams } from '@/libs/next/navigation';
8
8
  import { useEffect } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
10
10
 
@@ -1,5 +1,5 @@
1
1
  import { SignUp } from '@clerk/nextjs';
2
- import { notFound } from 'next/navigation';
2
+ import { notFound } from '@/libs/next/navigation';
3
3
 
4
4
  import { enableBetterAuth, enableClerk } from '@/envs/auth';
5
5
  import { metadataModule } from '@/server/metadata';
@@ -1,6 +1,6 @@
1
1
  import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
2
2
  import { form } from 'motion/react-m';
3
- import { useRouter, useSearchParams } from 'next/navigation';
3
+ import { useRouter, useSearchParams } from '@/libs/next/navigation';
4
4
  import { useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
@@ -1,4 +1,4 @@
1
- import { notFound } from 'next/navigation';
1
+ import { notFound } from '@/libs/next/navigation';
2
2
  import { type PropsWithChildren } from 'react';
3
3
 
4
4
  import { enableBetterAuth } from '@/envs/auth';
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { Button } from '@lobehub/ui';
4
4
  import { ChevronLeftIcon } from 'lucide-react';
5
- import Link from 'next/link';
6
- import { useSearchParams } from 'next/navigation';
5
+ import Link from '@/libs/next/Link';
6
+ import { useSearchParams } from '@/libs/next/navigation';
7
7
  import { useTranslation } from 'react-i18next';
8
8
 
9
9
  import AuthCard from '../../../../features/AuthCard';
@@ -3,7 +3,6 @@
3
3
  import { TITLE_BAR_HEIGHT } from '@lobechat/desktop-bridge';
4
4
  import { Flexbox } from '@lobehub/ui';
5
5
  import { cx } from 'antd-style';
6
- import dynamic from 'next/dynamic';
7
6
  import { type FC, Suspense, lazy } from 'react';
8
7
  import { HotkeysProvider } from 'react-hotkeys-hook';
9
8
  import { Outlet } from 'react-router-dom';
@@ -20,6 +19,7 @@ import { useFeedbackModal } from '@/hooks/useFeedbackModal';
20
19
  import { usePlatform } from '@/hooks/usePlatform';
21
20
  import { MarketAuthProvider } from '@/layout/AuthProvider/MarketAuth';
22
21
  import CmdkLazy from '@/layout/GlobalProvider/CmdkLazy';
22
+ import dynamic from '@/libs/next/dynamic';
23
23
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
24
24
  import { HotkeyScopeEnum } from '@/types/hotkey';
25
25
 
@@ -6,8 +6,8 @@ import { memo, useCallback } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { useParams } from 'react-router-dom';
8
8
 
9
- import { useRouter } from '@/app/[variants]/(main)/hooks/useRouter';
10
9
  import type { AgentCronJob } from '@/database/schemas/agentCronJob';
10
+ import { useRouter } from '@/libs/router/navigation';
11
11
 
12
12
  import Actions from './Actions';
13
13
  import CronTopicItem from './CronTopicItem';
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { ActionIcon } from '@lobehub/ui';
4
4
  import { MessageSquarePlusIcon } from 'lucide-react';
5
- import { usePathname } from 'next/navigation';
6
5
  import { memo } from 'react';
7
6
  import { useTranslation } from 'react-i18next';
8
7
  import { useParams } from 'react-router-dom';
@@ -10,6 +9,7 @@ import urlJoin from 'url-join';
10
9
 
11
10
  import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
12
11
  import { useQueryRoute } from '@/hooks/useQueryRoute';
12
+ import { usePathname } from '@/libs/router/navigation';
13
13
  import { useActionSWR } from '@/libs/swr';
14
14
  import { useChatStore } from '@/store/chat';
15
15
  import { useUserStore } from '@/store/user';
@@ -3,7 +3,6 @@
3
3
  import { Flexbox } from '@lobehub/ui';
4
4
  import { BotPromptIcon } from '@lobehub/ui/icons';
5
5
  import { MessageSquarePlusIcon, SearchIcon } from 'lucide-react';
6
- import { usePathname } from 'next/navigation';
7
6
  import { memo } from 'react';
8
7
  import { useTranslation } from 'react-i18next';
9
8
  import { useParams } from 'react-router-dom';
@@ -11,6 +10,7 @@ import urlJoin from 'url-join';
11
10
 
12
11
  import NavItem from '@/features/NavPanel/components/NavItem';
13
12
  import { useQueryRoute } from '@/hooks/useQueryRoute';
13
+ import { usePathname } from '@/libs/router/navigation';
14
14
  import { useActionSWR } from '@/libs/swr';
15
15
  import { useAgentStore } from '@/store/agent';
16
16
  import { builtinAgentSelectors } from '@/store/agent/selectors';
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
 
3
3
  import { Flexbox, SearchBar } from '@lobehub/ui';
4
- import dynamic from 'next/dynamic';
5
4
  import { memo, useState } from 'react';
6
5
  import { useTranslation } from 'react-i18next';
7
6
 
8
7
  import SideBarDrawer from '@/features/NavPanel/SideBarDrawer';
9
8
  import SkeletonList from '@/features/NavPanel/components/SkeletonList';
9
+ import dynamic from '@/libs/next/dynamic';
10
10
 
11
11
  const Content = dynamic(() => import('./Content'), {
12
12
  loading: () => (
@@ -1,9 +1,9 @@
1
- import { usePathname } from 'next/navigation';
2
1
  import { useCallback } from 'react';
3
2
  import { useParams } from 'react-router-dom';
4
3
  import urlJoin from 'url-join';
5
4
 
6
5
  import { useQueryRoute } from '@/hooks/useQueryRoute';
6
+ import { usePathname } from '@/libs/router/navigation';
7
7
  import { useChatStore } from '@/store/chat';
8
8
  import { useGlobalStore } from '@/store/global';
9
9
 
@@ -1,8 +1,8 @@
1
- import { usePathname } from 'next/navigation';
2
1
  import { useCallback } from 'react';
3
2
  import urlJoin from 'url-join';
4
3
 
5
4
  import { useQueryRoute } from '@/hooks/useQueryRoute';
5
+ import { usePathname } from '@/libs/router/navigation';
6
6
  import { useChatStore } from '@/store/chat';
7
7
  import { useGlobalStore } from '@/store/global';
8
8
 
@@ -4,7 +4,6 @@ import { BRANDING_NAME } from '@lobechat/business-const';
4
4
  import { Avatar, Button, Flexbox, Icon } from '@lobehub/ui';
5
5
  import { createStaticStyles, cssVar } from 'antd-style';
6
6
  import { LucideArrowUpRightFromSquare, TelescopeIcon } from 'lucide-react';
7
- import Link from 'next/link';
8
7
  import { memo } from 'react';
9
8
  import { useTranslation } from 'react-i18next';
10
9
 
@@ -56,10 +55,10 @@ const TelemetryNotification = memo<{ mobile?: boolean }>(({ mobile }) => {
56
55
  <div className={styles.desc}>
57
56
  {t('telemetry.desc', { appName: BRANDING_NAME })}
58
57
  <span>
59
- <Link href={PRIVACY_URL} target={'_blank'}>
58
+ <a href={PRIVACY_URL} rel="noreferrer" target="_blank">
60
59
  {t('telemetry.learnMore')}
61
60
  <Icon icon={LucideArrowUpRightFromSquare} style={{ marginInlineStart: 4 }} />
62
- </Link>
61
+ </a>
63
62
  </span>
64
63
  </div>
65
64
  </Flexbox>
@@ -4,7 +4,6 @@ import { SOCIAL_URL } from '@lobechat/business-const';
4
4
  import { Flexbox, Icon, Tabs, Tag } from '@lobehub/ui';
5
5
  import { createStaticStyles } from 'antd-style';
6
6
  import { BookOpenIcon, HistoryIcon, LayersIcon, ListIcon, SquareUserIcon } from 'lucide-react';
7
- import Link from 'next/link';
8
7
  import { memo } from 'react';
9
8
  import { useTranslation } from 'react-i18next';
10
9
  import urlJoin from 'url-join';
@@ -104,21 +103,22 @@ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = AssistantNavKey.
104
103
  <Flexbox align={'center'} className={styles.nav} horizontal justify={'space-between'}>
105
104
  {nav}
106
105
  <Flexbox gap={12} horizontal>
107
- <Link className={styles.link} href={SOCIAL_URL.discord} target={'_blank'}>
106
+ <a className={styles.link} href={SOCIAL_URL.discord} rel="noreferrer" target="_blank">
108
107
  {t('mcp.details.nav.needHelp')}
109
- </Link>
108
+ </a>
110
109
  {identifier && marketplaceLink && (
111
- <Link className={styles.link} href={marketplaceLink} target={'_blank'}>
110
+ <a className={styles.link} href={marketplaceLink} rel="noreferrer" target="_blank">
112
111
  {t('mcp.details.nav.viewSourceCode')}
113
- </Link>
112
+ </a>
114
113
  )}
115
- <Link
114
+ <a
116
115
  className={styles.link}
117
- href={'https://github.com/lobehub/lobe-chat-agents/issues/new/choose'}
118
- target={'_blank'}
116
+ href="https://github.com/lobehub/lobe-chat-agents/issues/new/choose"
117
+ rel="noreferrer"
118
+ target="_blank"
119
119
  >
120
120
  {t('mcp.details.nav.reportIssue')}
121
- </Link>
121
+ </a>
122
122
  </Flexbox>
123
123
  </Flexbox>
124
124
  );
@@ -5,9 +5,8 @@ import qs from 'query-string';
5
5
  import { memo, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
- import Link from '@/app/[variants]/(main)/components/Link';
9
- import { usePathname } from '@/app/[variants]/(main)/hooks/usePathname';
10
- import { useQuery } from '@/app/[variants]/(main)/hooks/useQuery';
8
+ import Link from '@/libs/router/Link';
9
+ import { usePathname , useQuery } from '@/libs/router/navigation';
11
10
  import InlineTable from '@/components/InlineTable';
12
11
  import PublishedTime from '@/components/PublishedTime';
13
12
  import { type AssistantMarketSource, AssistantNavKey } from '@/types/discover';
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { Center, Empty, Markdown } from '@lobehub/ui';
4
4
  import { FileText } from 'lucide-react';
5
- import Link from 'next/link';
6
5
  import { type ReactNode, memo } from 'react';
7
6
  import { useTranslation } from 'react-i18next';
8
7
 
@@ -28,7 +27,7 @@ const MarkdownRender = memo<{ children?: string }>(({ children }) => {
28
27
  components={{
29
28
  a: ({ href, ...rest }: { children?: ReactNode; href?: string }) => {
30
29
  if (href && href.startsWith('http'))
31
- return <Link {...rest} href={href} target={'_blank'} />;
30
+ return <a {...rest} href={href} rel="noreferrer" target="_blank" />;
32
31
  return rest?.children;
33
32
  },
34
33
  h1: H1,
@@ -15,7 +15,6 @@ import {
15
15
  import { createStaticStyles, cssVar } from 'antd-style';
16
16
  import { startCase } from 'es-toolkit/compat';
17
17
  import { LinkIcon, Share2Icon } from 'lucide-react';
18
- import Link from 'next/link';
19
18
  import { type ReactNode, memo, useState } from 'react';
20
19
  import { useTranslation } from 'react-i18next';
21
20
 
@@ -121,14 +120,14 @@ const ShareButton = memo<ShareButtonProps>(({ meta, ...rest }) => {
121
120
  {[x, reddit, telegram, whatsapp, mastodon, weibo].map(
122
121
  (item) =>
123
122
  item.icon && (
124
- <Link href={item.link} key={item.title} target={'_blank'}>
123
+ <a href={item.link} key={item.title} rel="noreferrer" target="_blank">
125
124
  <ActionIcon
126
125
  className={styles.icon}
127
126
  icon={item.icon}
128
127
  size={{ blockSize: 36, borderRadius: 18, size: 16 }}
129
128
  title={item.title}
130
129
  />
131
- </Link>
130
+ </a>
132
131
  ),
133
132
  )}
134
133
  </Flexbox>
@@ -4,7 +4,6 @@ import { Icon } from '@lobehub/ui';
4
4
  import { createStaticStyles, cssVar, cx } from 'antd-style';
5
5
  import { kebabCase } from 'es-toolkit/compat';
6
6
  import { Heading2, Heading3, Heading4, Heading5 } from 'lucide-react';
7
- import Link from 'next/link';
8
7
  import {
9
8
  Children,
10
9
  type ComponentProps,
@@ -92,14 +91,14 @@ const createHeading = (Tag: `h${1 | 2 | 3 | 4 | 5 | 6}`) => {
92
91
  id={id}
93
92
  >
94
93
  {children}
95
- <Link
94
+ <a
96
95
  aria-label="Permalink for this section"
97
96
  className={styles.anchor}
98
97
  href={`#${id}`}
99
98
  style={{ scrollMarginTop: 96 }}
100
99
  >
101
100
  <Icon icon={HeadingIcon[Tag]} />
102
- </Link>
101
+ </a>
103
102
  </Tag>
104
103
  );
105
104
  };
@@ -5,8 +5,8 @@ import qs from 'query-string';
5
5
  import { memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
- import Link from '@/app/[variants]/(main)/components/Link';
9
- import { usePathname } from '@/app/[variants]/(main)/hooks/usePathname';
8
+ import Link from '@/libs/router/Link';
9
+ import { usePathname } from '@/libs/router/navigation';
10
10
  import InlineTable from '@/components/InlineTable';
11
11
 
12
12
  import PublishedTime from '../../../../../../../../../components/PublishedTime';
@@ -4,7 +4,6 @@ import { SOCIAL_URL } from '@lobechat/business-const';
4
4
  import { Flexbox, Icon, Tabs } from '@lobehub/ui';
5
5
  import { createStaticStyles } from 'antd-style';
6
6
  import { BookOpenIcon, ListIcon, Settings2Icon } from 'lucide-react';
7
- import Link from 'next/link';
8
7
  import { memo } from 'react';
9
8
  import { useTranslation } from 'react-i18next';
10
9
 
@@ -65,23 +64,25 @@ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ModelNavKey.Over
65
64
  <Flexbox align={'center'} className={styles.nav} horizontal justify={'space-between'}>
66
65
  {nav}
67
66
  <Flexbox gap={12} horizontal>
68
- <Link className={styles.link} href={SOCIAL_URL.discord} target={'_blank'}>
67
+ <a className={styles.link} href={SOCIAL_URL.discord} rel="noreferrer" target="_blank">
69
68
  {t('mcp.details.nav.needHelp')}
70
- </Link>
71
- <Link
69
+ </a>
70
+ <a
72
71
  className={styles.link}
73
- href={'https://github.com/lobehub/lobe-chat/tree/main/src/config/aiModels'}
74
- target={'_blank'}
72
+ href="https://github.com/lobehub/lobe-chat/tree/main/src/config/aiModels"
73
+ rel="noreferrer"
74
+ target="_blank"
75
75
  >
76
76
  {t('mcp.details.nav.viewSourceCode')}
77
- </Link>
78
- <Link
77
+ </a>
78
+ <a
79
79
  className={styles.link}
80
- href={'https://github.com/lobehub/lobe-chat/issues/new/choose'}
81
- target={'_blank'}
80
+ href="https://github.com/lobehub/lobe-chat/issues/new/choose"
81
+ rel="noreferrer"
82
+ target="_blank"
82
83
  >
83
84
  {t('mcp.details.nav.reportIssue')}
84
- </Link>
85
+ </a>
85
86
  </Flexbox>
86
87
  </Flexbox>
87
88
  );